From b8e0730d0cbd09346af042f70e1f7c02d933d9d3 Mon Sep 17 00:00:00 2001 From: Ryland Herrick Date: Thu, 30 Apr 2020 14:48:37 -0500 Subject: [PATCH 01/10] [SIEM] NP Plugin dependency cleanup (#64842) * Remove static src dependencies from kibana.json We are only importing static code from these plugins, and not consuming their plugin contracts. For this reason, we can safely remove them from kibana.json as that imported code will always be included in our own bundle. * Make usageCollection an optional dependency If it's not enabled, we simply use a noop for our tracker call. * Remove unused plugin contracts These are only needed when we're actually using them in our codebase. For request handler contexts, we only need our kibana.json declaration. * Remove unnecessary try/catch With the addition of the null coalescing, the only chance for an error is in usageCollection. However, if the usageCollection contract changes, we should get a type error long before we see a runtime error. * Improve typings of our Plugin classes * passes missing generic arguments to public plugin interface * passes missing generic arguments to both plugins' CoreSetup types * Don't re-export core types Instead, import them from core as needed. --- x-pack/plugins/siem/kibana.json | 12 ++++++++---- .../plugins/siem/public/lib/telemetry/index.ts | 8 +++----- x-pack/plugins/siem/public/plugin.tsx | 6 +++--- x-pack/plugins/siem/server/lib/compose/kibana.ts | 3 ++- .../lib/framework/kibana_framework_adapter.ts | 3 ++- x-pack/plugins/siem/server/plugin.ts | 16 ++++------------ 6 files changed, 22 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/siem/kibana.json b/x-pack/plugins/siem/kibana.json index e0ff82eb10eb2..39e50838c1c97 100644 --- a/x-pack/plugins/siem/kibana.json +++ b/x-pack/plugins/siem/kibana.json @@ -8,18 +8,22 @@ "alerting", "data", "embeddable", - "esUiShared", "features", "home", "inspector", - "kibanaUtils", "licensing", "maps", "triggers_actions_ui", - "uiActions", + "uiActions" + ], + "optionalPlugins": [ + "encryptedSavedObjects", + "ml", + "newsfeed", + "security", + "spaces", "usageCollection" ], - "optionalPlugins": ["encryptedSavedObjects", "ml", "newsfeed", "security", "spaces"], "server": true, "ui": true } diff --git a/x-pack/plugins/siem/public/lib/telemetry/index.ts b/x-pack/plugins/siem/public/lib/telemetry/index.ts index 856b7783a5367..37d181e9b8ad7 100644 --- a/x-pack/plugins/siem/public/lib/telemetry/index.ts +++ b/x-pack/plugins/siem/public/lib/telemetry/index.ts @@ -13,6 +13,8 @@ export { METRIC_TYPE }; type TrackFn = (type: UiStatsMetricType, event: string | string[], count?: number) => void; +const noop = () => {}; + let _track: TrackFn; export const track: TrackFn = (type, event, count) => { @@ -24,11 +26,7 @@ export const track: TrackFn = (type, event, count) => { }; export const initTelemetry = (usageCollection: SetupPlugins['usageCollection'], appId: string) => { - try { - _track = usageCollection.reportUiStats.bind(null, appId); - } catch (error) { - // ignore failed setup here, as we'll just have an inert tracker - } + _track = usageCollection?.reportUiStats?.bind(null, appId) ?? noop; }; export enum TELEMETRY_EVENT { diff --git a/x-pack/plugins/siem/public/plugin.tsx b/x-pack/plugins/siem/public/plugin.tsx index e54c96364ba6b..f9c44bd341fac 100644 --- a/x-pack/plugins/siem/public/plugin.tsx +++ b/x-pack/plugins/siem/public/plugin.tsx @@ -37,7 +37,7 @@ export interface SetupPlugins { home: HomePublicPluginSetup; security: SecurityPluginSetup; triggers_actions_ui: TriggersActionsSetup; - usageCollection: UsageCollectionSetup; + usageCollection?: UsageCollectionSetup; } export interface StartPlugins { @@ -59,14 +59,14 @@ export interface PluginSetup {} // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface PluginStart {} -export class Plugin implements IPlugin { +export class Plugin implements IPlugin { private kibanaVersion: string; constructor(initializerContext: PluginInitializerContext) { this.kibanaVersion = initializerContext.env.packageInfo.version; } - public setup(core: CoreSetup, plugins: SetupPlugins) { + public setup(core: CoreSetup, plugins: SetupPlugins) { initTelemetry(plugins.usageCollection, APP_ID); plugins.home.featureCatalogue.register({ diff --git a/x-pack/plugins/siem/server/lib/compose/kibana.ts b/x-pack/plugins/siem/server/lib/compose/kibana.ts index 4a595032e43eb..8bc90bed25168 100644 --- a/x-pack/plugins/siem/server/lib/compose/kibana.ts +++ b/x-pack/plugins/siem/server/lib/compose/kibana.ts @@ -4,7 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup, SetupPlugins } from '../../plugin'; +import { CoreSetup } from '../../../../../../src/core/server'; +import { SetupPlugins } from '../../plugin'; import { Authentications } from '../authentications'; import { ElasticsearchAuthenticationAdapter } from '../authentications/elasticsearch_adapter'; diff --git a/x-pack/plugins/siem/server/lib/framework/kibana_framework_adapter.ts b/x-pack/plugins/siem/server/lib/framework/kibana_framework_adapter.ts index 762416149c0fb..1e99c40ef5727 100644 --- a/x-pack/plugins/siem/server/lib/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/siem/server/lib/framework/kibana_framework_adapter.ts @@ -9,6 +9,7 @@ import { GraphQLSchema } from 'graphql'; import { runHttpQuery } from 'apollo-server-core'; import { schema as configSchema } from '@kbn/config-schema'; import { + CoreSetup, IRouter, KibanaResponseFactory, RequestHandlerContext, @@ -16,7 +17,7 @@ import { } from '../../../../../../src/core/server'; import { IndexPatternsFetcher } from '../../../../../../src/plugins/data/server'; import { AuthenticatedUser } from '../../../../security/common/model'; -import { CoreSetup, SetupPlugins } from '../../plugin'; +import { SetupPlugins } from '../../plugin'; import { FrameworkAdapter, diff --git a/x-pack/plugins/siem/server/plugin.ts b/x-pack/plugins/siem/server/plugin.ts index dc484b75ab531..3ef4b39bd0979 100644 --- a/x-pack/plugins/siem/server/plugin.ts +++ b/x-pack/plugins/siem/server/plugin.ts @@ -15,16 +15,12 @@ import { PluginInitializerContext, Logger, } from '../../../../src/core/server'; -import { - PluginStartContract as AlertingStart, - PluginSetupContract as AlertingSetup, -} from '../../alerting/server'; +import { PluginSetupContract as AlertingSetup } from '../../alerting/server'; import { SecurityPluginSetup as SecuritySetup } from '../../security/server'; import { PluginSetupContract as FeaturesSetup } from '../../features/server'; import { MlPluginSetup as MlSetup } from '../../ml/server'; import { EncryptedSavedObjectsPluginSetup as EncryptedSavedObjectsSetup } from '../../encrypted_saved_objects/server'; import { SpacesPluginSetup as SpacesSetup } from '../../spaces/server'; -import { PluginStartContract as ActionsStart } from '../../actions/server'; import { LicensingPluginSetup } from '../../licensing/server'; import { initServer } from './init_server'; import { compose } from './lib/compose/kibana'; @@ -40,8 +36,6 @@ import { createConfig$, ConfigType } from './config'; import { initUiSettings } from './ui_settings'; import { APP_ID, APP_ICON } from '../common/constants'; -export { CoreSetup, CoreStart }; - export interface SetupPlugins { alerting: AlertingSetup; encryptedSavedObjects?: EncryptedSavedObjectsSetup; @@ -52,10 +46,8 @@ export interface SetupPlugins { ml?: MlSetup; } -export interface StartPlugins { - actions: ActionsStart; - alerting: AlertingStart; -} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface StartPlugins {} // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface PluginSetup {} @@ -77,7 +69,7 @@ export class Plugin implements IPlugin, plugins: SetupPlugins) { this.logger.debug('plugin setup'); if (hasListsFeature()) { From 6e3791ea12c4283561e1cdd5284c1589274b2417 Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Thu, 30 Apr 2020 15:52:14 -0400 Subject: [PATCH 02/10] Ingest Node Pipelines UI (#62321) --- .github/CODEOWNERS | 1 + x-pack/.i18nrc.json | 1 + x-pack/plugins/ingest_pipelines/README.md | 24 ++ .../ingest_pipelines/common/constants.ts | 18 + .../ingest_pipelines/common/lib/index.ts | 7 + .../common/lib/pipeline_serialization.test.ts | 68 ++++ .../common/lib/pipeline_serialization.ts | 20 ++ .../plugins/ingest_pipelines/common/types.ts | 28 ++ x-pack/plugins/ingest_pipelines/kibana.json | 17 + .../public/application/app.tsx | 101 ++++++ .../public/application/components/index.ts | 7 + .../components/pipeline_form/index.ts | 7 + .../pipeline_form/pipeline_form.tsx | 166 +++++++++ .../pipeline_form/pipeline_form_error.tsx | 34 ++ .../pipeline_form/pipeline_form_fields.tsx | 223 ++++++++++++ .../pipeline_form/pipeline_form_provider.tsx | 18 + .../pipeline_request_flyout/index.ts | 7 + .../pipeline_request_flyout.tsx | 89 +++++ .../pipeline_request_flyout_provider.tsx | 29 ++ .../pipeline_test_flyout/index.ts | 7 + .../pipeline_test_flyout.tsx | 203 +++++++++++ .../pipeline_test_flyout_provider.tsx | 39 +++ .../pipeline_test_flyout/tabs/index.ts | 11 + .../tabs/pipeline_test_tabs.tsx | 60 ++++ .../pipeline_test_flyout/tabs/schema.tsx | 87 +++++ .../tabs/tab_documents.tsx | 152 ++++++++ .../pipeline_test_flyout/tabs/tab_output.tsx | 106 ++++++ .../components/pipeline_form/schema.tsx | 147 ++++++++ .../pipeline_form/test_config_context.tsx | 57 +++ .../public/application/constants/index.ts | 14 + .../public/application/index.tsx | 55 +++ .../public/application/lib/index.ts | 7 + .../public/application/lib/utils.test.ts | 37 ++ .../public/application/lib/utils.ts | 25 ++ .../application/mount_management_section.ts | 35 ++ .../public/application/sections/index.ts | 13 + .../sections/pipelines_clone/index.ts | 7 + .../pipelines_clone/pipelines_clone.tsx | 59 ++++ .../sections/pipelines_create/index.ts | 7 + .../pipelines_create/pipelines_create.tsx | 109 ++++++ .../sections/pipelines_edit/index.ts | 7 + .../pipelines_edit/pipelines_edit.tsx | 151 ++++++++ .../sections/pipelines_list/delete_modal.tsx | 125 +++++++ .../pipelines_list/details_flyout.tsx | 210 +++++++++++ .../pipelines_list/details_json_block.tsx | 31 ++ .../sections/pipelines_list/empty_list.tsx | 29 ++ .../sections/pipelines_list/index.ts | 7 + .../sections/pipelines_list/main.tsx | 207 +++++++++++ .../pipelines_list/not_found_flyout.tsx | 42 +++ .../sections/pipelines_list/table.tsx | 148 ++++++++ .../public/application/services/api.ts | 125 +++++++ .../application/services/breadcrumbs.ts | 71 ++++ .../application/services/documentation.ts | 39 +++ .../public/application/services/index.ts | 13 + .../public/application/services/ui_metric.ts | 32 ++ .../plugins/ingest_pipelines/public/index.ts | 11 + .../plugins/ingest_pipelines/public/plugin.ts | 39 +++ .../ingest_pipelines/public/shared_imports.ts | 54 +++ .../plugins/ingest_pipelines/public/types.ts | 13 + .../plugins/ingest_pipelines/server/index.ts | 12 + .../ingest_pipelines/server/lib/index.ts | 7 + .../server/lib/is_es_error.ts | 13 + .../plugins/ingest_pipelines/server/plugin.ts | 59 ++++ .../server/routes/api/create.ts | 83 +++++ .../server/routes/api/delete.ts | 49 +++ .../ingest_pipelines/server/routes/api/get.ts | 83 +++++ .../server/routes/api/index.ts | 17 + .../server/routes/api/privileges.ts | 62 ++++ .../server/routes/api/simulate.ts | 61 ++++ .../server/routes/api/update.ts | 67 ++++ .../ingest_pipelines/server/routes/index.ts | 27 ++ .../ingest_pipelines/server/services/index.ts | 7 + .../server/services/license.ts | 82 +++++ .../plugins/ingest_pipelines/server/types.ts | 22 ++ .../api_integration/apis/management/index.js | 1 + .../apis/management/ingest_pipelines/index.ts | 12 + .../ingest_pipelines/ingest_pipelines.ts | 330 ++++++++++++++++++ .../ingest_pipelines/lib/elasticsearch.ts | 39 +++ .../management/ingest_pipelines/lib/index.ts | 7 + .../functional/apps/ingest_pipelines/index.ts | 14 + .../apps/ingest_pipelines/ingest_pipelines.ts | 27 ++ x-pack/test/functional/config.js | 5 + x-pack/test/functional/page_objects/index.ts | 2 + .../page_objects/ingest_pipelines_page.ts | 17 + 84 files changed, 4561 insertions(+) create mode 100644 x-pack/plugins/ingest_pipelines/README.md create mode 100644 x-pack/plugins/ingest_pipelines/common/constants.ts create mode 100644 x-pack/plugins/ingest_pipelines/common/lib/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.test.ts create mode 100644 x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.ts create mode 100644 x-pack/plugins/ingest_pipelines/common/types.ts create mode 100644 x-pack/plugins/ingest_pipelines/kibana.json create mode 100644 x-pack/plugins/ingest_pipelines/public/application/app.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_fields.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_provider.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/pipeline_request_flyout.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/pipeline_request_flyout_provider.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/pipeline_test_flyout.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/pipeline_test_flyout_provider.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/pipeline_test_tabs.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/schema.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/tab_documents.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/tab_output.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/schema.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/test_config_context.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/constants/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/index.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/lib/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/lib/utils.test.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/lib/utils.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/mount_management_section.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/pipelines_clone.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_create/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_create/pipelines_create.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/pipelines_edit.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/delete_modal.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_flyout.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_json_block.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/empty_list.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/not_found_flyout.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/table.tsx create mode 100644 x-pack/plugins/ingest_pipelines/public/application/services/api.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/services/breadcrumbs.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/services/documentation.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/services/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/application/services/ui_metric.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/plugin.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/shared_imports.ts create mode 100644 x-pack/plugins/ingest_pipelines/public/types.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/lib/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/lib/is_es_error.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/plugin.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/routes/api/create.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/routes/api/delete.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/routes/api/get.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/routes/api/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/routes/api/update.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/routes/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/services/index.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/services/license.ts create mode 100644 x-pack/plugins/ingest_pipelines/server/types.ts create mode 100644 x-pack/test/api_integration/apis/management/ingest_pipelines/index.ts create mode 100644 x-pack/test/api_integration/apis/management/ingest_pipelines/ingest_pipelines.ts create mode 100644 x-pack/test/api_integration/apis/management/ingest_pipelines/lib/elasticsearch.ts create mode 100644 x-pack/test/api_integration/apis/management/ingest_pipelines/lib/index.ts create mode 100644 x-pack/test/functional/apps/ingest_pipelines/index.ts create mode 100644 x-pack/test/functional/apps/ingest_pipelines/ingest_pipelines.ts create mode 100644 x-pack/test/functional/page_objects/ingest_pipelines_page.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index a97400ee09c0e..c17538849660e 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -203,6 +203,7 @@ /x-pack/plugins/snapshot_restore/ @elastic/es-ui /x-pack/plugins/upgrade_assistant/ @elastic/es-ui /x-pack/plugins/watcher/ @elastic/es-ui +/x-pack/plugins/ingest_pipelines/ @elastic/es-ui # Endpoint /x-pack/plugins/endpoint/ @elastic/endpoint-app-team @elastic/siem diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 4acb170d12574..9f43bf8da0601 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -21,6 +21,7 @@ "xpack.indexLifecycleMgmt": "plugins/index_lifecycle_management", "xpack.infra": "plugins/infra", "xpack.ingestManager": "plugins/ingest_manager", + "xpack.ingestPipelines": "plugins/ingest_pipelines", "xpack.lens": "plugins/lens", "xpack.licenseMgmt": "plugins/license_management", "xpack.licensing": "plugins/licensing", diff --git a/x-pack/plugins/ingest_pipelines/README.md b/x-pack/plugins/ingest_pipelines/README.md new file mode 100644 index 0000000000000..a469511bdbbd2 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/README.md @@ -0,0 +1,24 @@ +# Ingest Node Pipelines UI + +## Summary +The `ingest_pipelines` plugin provides Kibana support for [Elasticsearch's ingest nodes](https://www.elastic.co/guide/en/elasticsearch/reference/master/ingest.html). Please refer to the Elasticsearch documentation for more details. + +This plugin allows Kibana to create, edit, clone and delete ingest node pipelines. It also provides support to simulate a pipeline. + +It requires a Basic license and the following cluster privileges: `manage_pipeline` and `cluster:monitor/nodes/info`. + +--- + +## Development + +A new app called Ingest Node Pipelines is registered in the Management section and follows a typical CRUD UI pattern. The client-side portion of this app lives in [public/application](public/application) and uses endpoints registered in [server/routes/api](server/routes/api). + +See the [kibana contributing guide](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md) for instructions on setting up your development environment. + +### Test coverage + +The app has the following test coverage: + +- Complete API integration tests +- Smoke-level functional test +- Client-integration tests diff --git a/x-pack/plugins/ingest_pipelines/common/constants.ts b/x-pack/plugins/ingest_pipelines/common/constants.ts new file mode 100644 index 0000000000000..edf681c276a84 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/common/constants.ts @@ -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 { LicenseType } from '../../licensing/common/types'; + +const basicLicense: LicenseType = 'basic'; + +export const PLUGIN_ID = 'ingest_pipelines'; + +export const PLUGIN_MIN_LICENSE_TYPE = basicLicense; + +export const BASE_PATH = '/management/elasticsearch/ingest_pipelines'; + +export const API_BASE_PATH = '/api/ingest_pipelines'; + +export const APP_CLUSTER_REQUIRED_PRIVILEGES = ['manage_pipeline', 'cluster:monitor/nodes/info']; diff --git a/x-pack/plugins/ingest_pipelines/common/lib/index.ts b/x-pack/plugins/ingest_pipelines/common/lib/index.ts new file mode 100644 index 0000000000000..a976f66bc7c40 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/common/lib/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 { deserializePipelines } from './pipeline_serialization'; diff --git a/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.test.ts b/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.test.ts new file mode 100644 index 0000000000000..65d6b6e30497f --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.test.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 { deserializePipelines } from './pipeline_serialization'; + +describe('pipeline_serialization', () => { + describe('deserializePipelines()', () => { + it('should deserialize pipelines', () => { + expect( + deserializePipelines({ + pipeline1: { + description: 'pipeline 1 description', + version: 1, + processors: [ + { + script: { + source: 'ctx._type = null', + }, + }, + ], + on_failure: [ + { + set: { + field: 'error.message', + value: '{{ failure_message }}', + }, + }, + ], + }, + pipeline2: { + description: 'pipeline2 description', + version: 1, + processors: [], + }, + }) + ).toEqual([ + { + name: 'pipeline1', + description: 'pipeline 1 description', + version: 1, + processors: [ + { + script: { + source: 'ctx._type = null', + }, + }, + ], + on_failure: [ + { + set: { + field: 'error.message', + value: '{{ failure_message }}', + }, + }, + ], + }, + { + name: 'pipeline2', + description: 'pipeline2 description', + version: 1, + processors: [], + }, + ]); + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.ts b/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.ts new file mode 100644 index 0000000000000..572f655076015 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/common/lib/pipeline_serialization.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 { PipelinesByName, Pipeline } from '../types'; + +export function deserializePipelines(pipelinesByName: PipelinesByName): Pipeline[] { + const pipelineNames: string[] = Object.keys(pipelinesByName); + + const deserializedPipelines = pipelineNames.map((name: string) => { + return { + ...pipelinesByName[name], + name, + }; + }); + + return deserializedPipelines; +} diff --git a/x-pack/plugins/ingest_pipelines/common/types.ts b/x-pack/plugins/ingest_pipelines/common/types.ts new file mode 100644 index 0000000000000..8d77359a7c3c5 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/common/types.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. + */ + +interface Processor { + [key: string]: { + [key: string]: unknown; + }; +} + +export interface Pipeline { + name: string; + description: string; + version?: number; + processors: Processor[]; + on_failure?: Processor[]; +} + +export interface PipelinesByName { + [key: string]: { + description: string; + version?: number; + processors: Processor[]; + on_failure?: Processor[]; + }; +} diff --git a/x-pack/plugins/ingest_pipelines/kibana.json b/x-pack/plugins/ingest_pipelines/kibana.json new file mode 100644 index 0000000000000..ec02c5f80edf9 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/kibana.json @@ -0,0 +1,17 @@ +{ + "id": "ingestPipelines", + "version": "8.0.0", + "server": true, + "ui": true, + "requiredPlugins": [ + "licensing", + "management" + ], + "optionalPlugins": [ + "usageCollection" + ], + "configPath": [ + "xpack", + "ingest_pipelines" + ] +} diff --git a/x-pack/plugins/ingest_pipelines/public/application/app.tsx b/x-pack/plugins/ingest_pipelines/public/application/app.tsx new file mode 100644 index 0000000000000..ba7675b507596 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/app.tsx @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiPageContent } from '@elastic/eui'; +import React, { FunctionComponent } from 'react'; +import { HashRouter, Switch, Route } from 'react-router-dom'; + +import { BASE_PATH, APP_CLUSTER_REQUIRED_PRIVILEGES } from '../../common/constants'; + +import { + SectionError, + useAuthorizationContext, + WithPrivileges, + SectionLoading, + NotAuthorizedSection, +} from '../shared_imports'; + +import { PipelinesList, PipelinesCreate, PipelinesEdit, PipelinesClone } from './sections'; + +export const AppWithoutRouter = () => ( + + + + + + {/* Catch all */} + + +); + +export const App: FunctionComponent = () => { + const { apiError } = useAuthorizationContext(); + + if (apiError) { + return ( + + } + error={apiError} + /> + ); + } + + return ( + `cluster.${privilege}`)} + > + {({ isLoading, hasPrivileges, privilegesMissing }) => { + if (isLoading) { + return ( + + + + ); + } + + if (!hasPrivileges) { + return ( + + + } + message={ + + } + /> + + ); + } + + return ( + + + + ); + }} + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/index.ts new file mode 100644 index 0000000000000..21a2ee30a84e1 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/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 { PipelineForm } from './pipeline_form'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/index.ts new file mode 100644 index 0000000000000..2b007a25667a1 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/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 { PipelineFormProvider as PipelineForm } from './pipeline_form_provider'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form.tsx new file mode 100644 index 0000000000000..9082196a48b39 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form.tsx @@ -0,0 +1,166 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiButton, EuiButtonEmpty, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; + +import { useForm, Form, FormConfig } from '../../../shared_imports'; +import { Pipeline } from '../../../../common/types'; + +import { PipelineRequestFlyout } from './pipeline_request_flyout'; +import { PipelineTestFlyout } from './pipeline_test_flyout'; +import { PipelineFormFields } from './pipeline_form_fields'; +import { PipelineFormError } from './pipeline_form_error'; +import { pipelineFormSchema } from './schema'; + +export interface PipelineFormProps { + onSave: (pipeline: Pipeline) => void; + onCancel: () => void; + isSaving: boolean; + saveError: any; + defaultValue?: Pipeline; + isEditing?: boolean; +} + +export const PipelineForm: React.FunctionComponent = ({ + defaultValue = { + name: '', + description: '', + processors: '', + on_failure: '', + version: '', + }, + onSave, + isSaving, + saveError, + isEditing, + onCancel, +}) => { + const [isRequestVisible, setIsRequestVisible] = useState(false); + + const [isTestingPipeline, setIsTestingPipeline] = useState(false); + + const handleSave: FormConfig['onSubmit'] = (formData, isValid) => { + if (isValid) { + onSave(formData as Pipeline); + } + }; + + const handleTestPipelineClick = () => { + setIsTestingPipeline(true); + }; + + const { form } = useForm({ + schema: pipelineFormSchema, + defaultValue, + onSubmit: handleSave, + }); + + const saveButtonLabel = isSaving ? ( + + ) : isEditing ? ( + + ) : ( + + ); + + return ( + <> +
+ {/* Request error */} + {saveError && } + + {/* All form fields */} + + + {/* Form submission */} + + + + + + {saveButtonLabel} + + + + + + + + + + + setIsRequestVisible(prevIsRequestVisible => !prevIsRequestVisible)} + > + {isRequestVisible ? ( + + ) : ( + + )} + + + + + {/* ES request flyout */} + {isRequestVisible ? ( + setIsRequestVisible(prevIsRequestVisible => !prevIsRequestVisible)} + /> + ) : null} + + {/* Test pipeline flyout */} + {isTestingPipeline ? ( + { + setIsTestingPipeline(prevIsTestingPipeline => !prevIsTestingPipeline); + }} + /> + ) : null} + + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error.tsx new file mode 100644 index 0000000000000..ef0e2737df24d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_error.tsx @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiSpacer, EuiCallOut } from '@elastic/eui'; + +interface Props { + errorMessage: string; +} + +export const PipelineFormError: React.FunctionComponent = ({ errorMessage }) => { + return ( + <> + + } + color="danger" + iconType="alert" + data-test-subj="savePipelineError" + > +

{errorMessage}

+
+ + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_fields.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_fields.tsx new file mode 100644 index 0000000000000..045afd52204fa --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_fields.tsx @@ -0,0 +1,223 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useState } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { EuiButton, EuiSpacer, EuiSwitch, EuiLink } from '@elastic/eui'; + +import { + getUseField, + getFormRow, + Field, + JsonEditorField, + useKibana, +} from '../../../shared_imports'; + +interface Props { + hasVersion: boolean; + hasOnFailure: boolean; + isTestButtonDisabled: boolean; + onTestPipelineClick: () => void; + isEditing?: boolean; +} + +const UseField = getUseField({ component: Field }); +const FormRow = getFormRow({ titleTag: 'h3' }); + +export const PipelineFormFields: React.FunctionComponent = ({ + isEditing, + hasVersion, + hasOnFailure, + isTestButtonDisabled, + onTestPipelineClick, +}) => { + const { services } = useKibana(); + + const [isVersionVisible, setIsVersionVisible] = useState(hasVersion); + const [isOnFailureEditorVisible, setIsOnFailureEditorVisible] = useState(hasOnFailure); + + return ( + <> + {/* Name field with optional version field */} + } + description={ + <> + + + + } + checked={isVersionVisible} + onChange={e => setIsVersionVisible(e.target.checked)} + data-test-subj="versionToggle" + /> + + } + > + + + {isVersionVisible && ( + + )} + + + {/* Description field */} + + } + description={ + + } + > + + + + {/* Processors field */} + + } + description={ + <> + + {i18n.translate('xpack.ingestPipelines.form.processorsDocumentionLink', { + defaultMessage: 'Learn more.', + })} + + ), + }} + /> + + + + + + + + } + > + + + + {/* On-failure field */} + + } + description={ + <> + + {i18n.translate('xpack.ingestPipelines.form.onFailureDocumentionLink', { + defaultMessage: 'Learn more.', + })} + + ), + }} + /> + + + } + checked={isOnFailureEditorVisible} + onChange={e => setIsOnFailureEditorVisible(e.target.checked)} + data-test-subj="onFailureToggle" + /> + + } + > + {isOnFailureEditorVisible ? ( + + ) : ( + // requires children or a field + // For now, we return an empty
if the editor is not visible +
+ )} + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_provider.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_provider.tsx new file mode 100644 index 0000000000000..57abea2309aa1 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_form_provider.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 React from 'react'; + +import { PipelineForm as PipelineFormUI, PipelineFormProps } from './pipeline_form'; +import { TestConfigContextProvider } from './test_config_context'; + +export const PipelineFormProvider: React.FunctionComponent = passThroughProps => { + return ( + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/index.ts new file mode 100644 index 0000000000000..9476b65557c54 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/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 { PipelineRequestFlyoutProvider as PipelineRequestFlyout } from './pipeline_request_flyout_provider'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/pipeline_request_flyout.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/pipeline_request_flyout.tsx new file mode 100644 index 0000000000000..58e86695808b1 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/pipeline_request_flyout.tsx @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useRef } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { + EuiButtonEmpty, + EuiCodeBlock, + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlyoutHeader, + EuiSpacer, + EuiText, + EuiTitle, +} from '@elastic/eui'; + +import { Pipeline } from '../../../../../common/types'; + +interface Props { + pipeline: Pipeline; + closeFlyout: () => void; +} + +export const PipelineRequestFlyout: React.FunctionComponent = ({ + closeFlyout, + pipeline, +}) => { + const { name, ...pipelineBody } = pipeline; + const endpoint = `PUT _ingest/pipeline/${name || ''}`; + const payload = JSON.stringify(pipelineBody, null, 2); + const request = `${endpoint}\n${payload}`; + // Hack so that copied-to-clipboard value updates as content changes + // Related issue: https://github.com/elastic/eui/issues/3321 + const uuid = useRef(0); + uuid.current++; + + return ( + + + +

+ {name ? ( + + ) : ( + + )} +

+
+
+ + + +

+ +

+
+ + + + {request} + +
+ + + + + + +
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/pipeline_request_flyout_provider.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/pipeline_request_flyout_provider.tsx new file mode 100644 index 0000000000000..6dcedca6085af --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_request_flyout/pipeline_request_flyout_provider.tsx @@ -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 React, { useState, useEffect } from 'react'; + +import { Pipeline } from '../../../../../common/types'; +import { useFormContext } from '../../../../shared_imports'; +import { PipelineRequestFlyout } from './pipeline_request_flyout'; + +export const PipelineRequestFlyoutProvider = ({ closeFlyout }: { closeFlyout: () => void }) => { + const form = useFormContext(); + const [formData, setFormData] = useState({} as Pipeline); + + useEffect(() => { + const subscription = form.subscribe(async ({ isValid, validate, data }) => { + const isFormValid = isValid ?? (await validate()); + if (isFormValid) { + setFormData(data.format() as Pipeline); + } + }); + + return subscription.unsubscribe; + }, [form]); + + return ; +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/index.ts new file mode 100644 index 0000000000000..38bbc43b469a5 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/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 { PipelineTestFlyoutProvider as PipelineTestFlyout } from './pipeline_test_flyout_provider'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/pipeline_test_flyout.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/pipeline_test_flyout.tsx new file mode 100644 index 0000000000000..16f39b2912c1d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/pipeline_test_flyout.tsx @@ -0,0 +1,203 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useState, useEffect, useCallback } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; + +import { + EuiFlyout, + EuiFlyoutBody, + EuiFlyoutHeader, + EuiSpacer, + EuiTitle, + EuiCallOut, +} from '@elastic/eui'; + +import { useKibana } from '../../../../shared_imports'; +import { Pipeline } from '../../../../../common/types'; +import { Tabs, Tab, OutputTab, DocumentsTab } from './tabs'; +import { useTestConfigContext } from '../test_config_context'; + +export interface PipelineTestFlyoutProps { + closeFlyout: () => void; + pipeline: Pipeline; + isPipelineValid: boolean; +} + +export const PipelineTestFlyout: React.FunctionComponent = ({ + closeFlyout, + pipeline, + isPipelineValid, +}) => { + const { services } = useKibana(); + + const { testConfig } = useTestConfigContext(); + const { documents: cachedDocuments, verbose: cachedVerbose } = testConfig; + + const initialSelectedTab = cachedDocuments ? 'output' : 'documents'; + const [selectedTab, setSelectedTab] = useState(initialSelectedTab); + + const [shouldExecuteImmediately, setShouldExecuteImmediately] = useState(false); + const [isExecuting, setIsExecuting] = useState(false); + const [executeError, setExecuteError] = useState(null); + const [executeOutput, setExecuteOutput] = useState(undefined); + + const handleExecute = useCallback( + async (documents: object[], verbose?: boolean) => { + const { name: pipelineName, ...pipelineDefinition } = pipeline; + + setIsExecuting(true); + setExecuteError(null); + + const { error, data: output } = await services.api.simulatePipeline({ + documents, + verbose, + pipeline: pipelineDefinition, + }); + + setIsExecuting(false); + + if (error) { + setExecuteError(error); + return; + } + + setExecuteOutput(output); + + services.notifications.toasts.addSuccess( + i18n.translate('xpack.ingestPipelines.testPipelineFlyout.successNotificationText', { + defaultMessage: 'Pipeline executed', + }), + { + toastLifeTimeMs: 1000, + } + ); + + setSelectedTab('output'); + }, + [pipeline, services.api, services.notifications.toasts] + ); + + useEffect(() => { + if (cachedDocuments) { + setShouldExecuteImmediately(true); + } + // We only want to know on initial mount if there are cached documents + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + useEffect(() => { + // If the user has already tested the pipeline once, + // use the cached test config and automatically execute the pipeline + if (shouldExecuteImmediately && Object.entries(pipeline).length > 0) { + setShouldExecuteImmediately(false); + handleExecute(cachedDocuments!, cachedVerbose); + } + }, [ + pipeline, + handleExecute, + cachedDocuments, + cachedVerbose, + isExecuting, + shouldExecuteImmediately, + ]); + + let tabContent; + + if (selectedTab === 'output') { + tabContent = ( + + ); + } else { + // default to "documents" tab + tabContent = ( + + ); + } + + return ( + + + +

+ {pipeline.name ? ( + + ) : ( + + )} +

+
+
+ + + !executeOutput && tabId === 'output'} + /> + + + + {/* Execute error */} + {executeError ? ( + <> + + } + color="danger" + iconType="alert" + > +

{executeError.message}

+
+ + + ) : null} + + {/* Invalid pipeline error */} + {!isPipelineValid ? ( + <> + + } + color="danger" + iconType="alert" + /> + + + ) : null} + + {/* Documents or output tab content */} + {tabContent} +
+
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/pipeline_test_flyout_provider.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/pipeline_test_flyout_provider.tsx new file mode 100644 index 0000000000000..351478394595a --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/pipeline_test_flyout_provider.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, { useState, useEffect } from 'react'; + +import { Pipeline } from '../../../../../common/types'; +import { useFormContext } from '../../../../shared_imports'; +import { PipelineTestFlyout, PipelineTestFlyoutProps } from './pipeline_test_flyout'; + +type Props = Omit; + +export const PipelineTestFlyoutProvider: React.FunctionComponent = ({ closeFlyout }) => { + const form = useFormContext(); + const [formData, setFormData] = useState({} as Pipeline); + const [isFormDataValid, setIsFormDataValid] = useState(false); + + useEffect(() => { + const subscription = form.subscribe(async ({ isValid, validate, data }) => { + const isFormValid = isValid ?? (await validate()); + if (isFormValid) { + setFormData(data.format() as Pipeline); + } + setIsFormDataValid(isFormValid); + }); + + return subscription.unsubscribe; + }, [form]); + + return ( + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/index.ts b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/index.ts new file mode 100644 index 0000000000000..ea8fe2cd92350 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/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 { Tabs, Tab } from './pipeline_test_tabs'; + +export { DocumentsTab } from './tab_documents'; + +export { OutputTab } from './tab_output'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/pipeline_test_tabs.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/pipeline_test_tabs.tsx new file mode 100644 index 0000000000000..f720b80122702 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/pipeline_test_tabs.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 from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiTab, EuiTabs } from '@elastic/eui'; + +export type Tab = 'documents' | 'output'; + +interface Props { + onTabChange: (tab: Tab) => void; + selectedTab: Tab; + getIsDisabled: (tab: Tab) => boolean; +} + +export const Tabs: React.FunctionComponent = ({ + onTabChange, + selectedTab, + getIsDisabled, +}) => { + const tabs: Array<{ + id: Tab; + name: React.ReactNode; + }> = [ + { + id: 'documents', + name: ( + + ), + }, + { + id: 'output', + name: ( + + ), + }, + ]; + + return ( + + {tabs.map(tab => ( + onTabChange(tab.id)} + isSelected={tab.id === selectedTab} + key={tab.id} + disabled={getIsDisabled(tab.id)} + data-test-subj={tab.id.toLowerCase() + '_tab'} + > + {tab.name} + + ))} + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/schema.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/schema.tsx new file mode 100644 index 0000000000000..de9910344bd4b --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/schema.tsx @@ -0,0 +1,87 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { EuiCode } from '@elastic/eui'; + +import { FormSchema, fieldValidators, ValidationFuncArg } from '../../../../../shared_imports'; +import { parseJson, stringifyJson } from '../../../../lib'; + +const { emptyField, isJsonField } = fieldValidators; + +export const documentsSchema: FormSchema = { + documents: { + label: i18n.translate( + 'xpack.ingestPipelines.testPipelineFlyout.documentsForm.documentsFieldLabel', + { + defaultMessage: 'Documents', + } + ), + helpText: ( + + {JSON.stringify([ + { + _index: 'index', + _id: 'id', + _source: { + foo: 'bar', + }, + }, + ])} + + ), + }} + /> + ), + serializer: parseJson, + deserializer: stringifyJson, + validations: [ + { + validator: emptyField( + i18n.translate( + 'xpack.ingestPipelines.testPipelineFlyout.documentsForm.noDocumentsError', + { + defaultMessage: 'Documents are required.', + } + ) + ), + }, + { + validator: isJsonField( + i18n.translate( + 'xpack.ingestPipelines.testPipelineFlyout.documentsForm.documentsJsonError', + { + defaultMessage: 'The documents JSON is not valid.', + } + ) + ), + }, + { + validator: ({ value }: ValidationFuncArg) => { + const parsedJSON = JSON.parse(value); + + if (!parsedJSON.length) { + return { + message: i18n.translate( + 'xpack.ingestPipelines.testPipelineFlyout.documentsForm.oneDocumentRequiredError', + { + defaultMessage: 'At least one document is required.', + } + ), + }; + } + }, + }, + ], + }, +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/tab_documents.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/tab_documents.tsx new file mode 100644 index 0000000000000..97bf03dbdc068 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/tab_documents.tsx @@ -0,0 +1,152 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; + +import { EuiSpacer, EuiText, EuiButton, EuiHorizontalRule, EuiLink } from '@elastic/eui'; + +import { + getUseField, + Field, + JsonEditorField, + Form, + useForm, + FormConfig, + useKibana, +} from '../../../../../shared_imports'; + +import { documentsSchema } from './schema'; +import { useTestConfigContext, TestConfig } from '../../test_config_context'; + +const UseField = getUseField({ component: Field }); + +interface Props { + handleExecute: (documents: object[], verbose: boolean) => void; + isPipelineValid: boolean; + isExecuting: boolean; +} + +export const DocumentsTab: React.FunctionComponent = ({ + isPipelineValid, + handleExecute, + isExecuting, +}) => { + const { services } = useKibana(); + + const { setCurrentTestConfig, testConfig } = useTestConfigContext(); + const { verbose: cachedVerbose, documents: cachedDocuments } = testConfig; + + const executePipeline: FormConfig['onSubmit'] = (formData, isValid) => { + if (!isValid || !isPipelineValid) { + return; + } + + const { documents } = formData as TestConfig; + + // Update context + setCurrentTestConfig({ + ...testConfig, + documents, + }); + + handleExecute(documents!, cachedVerbose); + }; + + const { form } = useForm({ + schema: documentsSchema, + defaultValue: { + documents: cachedDocuments || '', + verbose: cachedVerbose || false, + }, + onSubmit: executePipeline, + }); + + return ( + <> + +

+ + {i18n.translate( + 'xpack.ingestPipelines.testPipelineFlyout.documentsTab.simulateDocumentionLink', + { + defaultMessage: 'Learn more.', + } + )} + + ), + }} + /> +

+
+ + + +
+ {/* Documents editor */} + + + + + +

+ +

+
+ + + + + {isExecuting ? ( + + ) : ( + + )} + + + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/tab_output.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/tab_output.tsx new file mode 100644 index 0000000000000..aa80f8c86ad8b --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/pipeline_test_flyout/tabs/tab_output.tsx @@ -0,0 +1,106 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiCodeBlock, + EuiSpacer, + EuiText, + EuiSwitch, + EuiLink, + EuiIcon, + EuiLoadingSpinner, + EuiIconTip, +} from '@elastic/eui'; +import { useTestConfigContext } from '../../test_config_context'; + +interface Props { + executeOutput?: { docs: object[] }; + handleExecute: (documents: object[], verbose: boolean) => void; + isExecuting: boolean; +} + +export const OutputTab: React.FunctionComponent = ({ + executeOutput, + handleExecute, + isExecuting, +}) => { + const { setCurrentTestConfig, testConfig } = useTestConfigContext(); + const { verbose: cachedVerbose, documents: cachedDocuments } = testConfig; + + const onEnableVerbose = (isVerboseEnabled: boolean) => { + setCurrentTestConfig({ + ...testConfig, + verbose: isVerboseEnabled, + }); + + handleExecute(cachedDocuments!, isVerboseEnabled); + }; + + let content: React.ReactNode | undefined; + + if (isExecuting) { + content = ; + } else if (executeOutput) { + content = ( + + {JSON.stringify(executeOutput, null, 2)} + + ); + } + + return ( + <> + +

+ handleExecute(cachedDocuments!, cachedVerbose)}> + {' '} + + + ), + }} + /> +

+
+ + + + + {' '} + + } + /> + + } + checked={cachedVerbose} + onChange={e => onEnableVerbose(e.target.checked)} + /> + + + + {content} + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/schema.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/schema.tsx new file mode 100644 index 0000000000000..2e2689f41527a --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/schema.tsx @@ -0,0 +1,147 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCode } from '@elastic/eui'; + +import { FormSchema, FIELD_TYPES, fieldValidators, fieldFormatters } from '../../../shared_imports'; +import { parseJson, stringifyJson } from '../../lib'; + +const { emptyField, isJsonField } = fieldValidators; +const { toInt } = fieldFormatters; + +export const pipelineFormSchema: FormSchema = { + name: { + type: FIELD_TYPES.TEXT, + label: i18n.translate('xpack.ingestPipelines.form.nameFieldLabel', { + defaultMessage: 'Name', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.form.pipelineNameRequiredError', { + defaultMessage: 'A pipeline name is required.', + }) + ), + }, + ], + }, + description: { + type: FIELD_TYPES.TEXTAREA, + label: i18n.translate('xpack.ingestPipelines.form.descriptionFieldLabel', { + defaultMessage: 'Description', + }), + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.form.pipelineDescriptionRequiredError', { + defaultMessage: 'A pipeline description is required.', + }) + ), + }, + ], + }, + processors: { + label: i18n.translate('xpack.ingestPipelines.form.processorsFieldLabel', { + defaultMessage: 'Processors', + }), + helpText: ( + + {JSON.stringify([ + { + set: { + field: 'foo', + value: 'bar', + }, + }, + ])} + + ), + }} + /> + ), + serializer: parseJson, + deserializer: stringifyJson, + validations: [ + { + validator: emptyField( + i18n.translate('xpack.ingestPipelines.form.processorsRequiredError', { + defaultMessage: 'Processors are required.', + }) + ), + }, + { + validator: isJsonField( + i18n.translate('xpack.ingestPipelines.form.processorsJsonError', { + defaultMessage: 'The processors JSON is not valid.', + }) + ), + }, + ], + }, + on_failure: { + label: i18n.translate('xpack.ingestPipelines.form.onFailureFieldLabel', { + defaultMessage: 'On-failure processors (optional)', + }), + helpText: ( + + {JSON.stringify([ + { + set: { + field: '_index', + value: 'failed-{{ _index }}', + }, + }, + ])} + + ), + }} + /> + ), + serializer: value => { + const result = parseJson(value); + // If an empty array was passed, strip out this value entirely. + if (!result.length) { + return undefined; + } + return result; + }, + deserializer: stringifyJson, + validations: [ + { + validator: validationArg => { + if (!validationArg.value) { + return; + } + return isJsonField( + i18n.translate('xpack.ingestPipelines.form.onFailureProcessorsJsonError', { + defaultMessage: 'The on-failure processors JSON is not valid.', + }) + )(validationArg); + }, + }, + ], + }, + version: { + type: FIELD_TYPES.NUMBER, + label: i18n.translate('xpack.ingestPipelines.form.versionFieldLabel', { + defaultMessage: 'Version (optional)', + }), + formatters: [toInt], + }, +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/test_config_context.tsx b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/test_config_context.tsx new file mode 100644 index 0000000000000..6840ebef28796 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/components/pipeline_form/test_config_context.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, { useState, useCallback, useContext } from 'react'; + +export interface TestConfig { + documents?: object[] | undefined; + verbose: boolean; +} + +interface TestConfigContext { + testConfig: TestConfig; + setCurrentTestConfig: (config: TestConfig) => void; +} + +const TEST_CONFIG_DEFAULT_VALUE = { + testConfig: { + verbose: false, + }, + setCurrentTestConfig: () => {}, +}; + +const TestConfigContext = React.createContext(TEST_CONFIG_DEFAULT_VALUE); + +export const useTestConfigContext = () => { + const ctx = useContext(TestConfigContext); + if (!ctx) { + throw new Error( + '"useTestConfigContext" can only be called inside of TestConfigContext.Provider!' + ); + } + return ctx; +}; + +export const TestConfigContextProvider = ({ children }: { children: React.ReactNode }) => { + const [testConfig, setTestConfig] = useState({ + verbose: false, + }); + + const setCurrentTestConfig = useCallback((currentTestConfig: TestConfig): void => { + setTestConfig(currentTestConfig); + }, []); + + return ( + + {children} + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/constants/index.ts b/x-pack/plugins/ingest_pipelines/public/application/constants/index.ts new file mode 100644 index 0000000000000..776d44c825670 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/constants/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. + */ + +// UI metric constants +export const UIM_APP_NAME = 'ingest_pipelines'; +export const UIM_PIPELINES_LIST_LOAD = 'pipelines_list_load'; +export const UIM_PIPELINE_CREATE = 'pipeline_create'; +export const UIM_PIPELINE_UPDATE = 'pipeline_update'; +export const UIM_PIPELINE_DELETE = 'pipeline_delete'; +export const UIM_PIPELINE_DELETE_MANY = 'pipeline_delete_many'; +export const UIM_PIPELINE_SIMULATE = 'pipeline_simulate'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/index.tsx b/x-pack/plugins/ingest_pipelines/public/application/index.tsx new file mode 100644 index 0000000000000..e43dba4689b44 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/index.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. + */ + +import { HttpSetup } from 'kibana/public'; +import React, { ReactNode } from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; +import { NotificationsSetup } from 'kibana/public'; +import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; + +import { API_BASE_PATH } from '../../common/constants'; + +import { AuthorizationProvider } from '../shared_imports'; + +import { App } from './app'; +import { DocumentationService, UiMetricService, ApiService, BreadcrumbService } from './services'; + +export interface AppServices { + breadcrumbs: BreadcrumbService; + metric: UiMetricService; + documentation: DocumentationService; + api: ApiService; + notifications: NotificationsSetup; +} + +export interface CoreServices { + http: HttpSetup; +} + +export const renderApp = ( + element: HTMLElement, + I18nContext: ({ children }: { children: ReactNode }) => JSX.Element, + services: AppServices, + coreServices: CoreServices +) => { + render( + + + + + + + , + element + ); + + return () => { + unmountComponentAtNode(element); + }; +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/lib/index.ts b/x-pack/plugins/ingest_pipelines/public/application/lib/index.ts new file mode 100644 index 0000000000000..1283033267a50 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/lib/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 { stringifyJson, parseJson } from './utils'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/lib/utils.test.ts b/x-pack/plugins/ingest_pipelines/public/application/lib/utils.test.ts new file mode 100644 index 0000000000000..e7eff3bd6ca33 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/lib/utils.test.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 { stringifyJson, parseJson } from './utils'; + +describe('utils', () => { + describe('stringifyJson()', () => { + it('should stringify a valid JSON array', () => { + expect(stringifyJson([1, 2, 3])).toEqual(`[ + 1, + 2, + 3 +]`); + }); + + it('should return a stringified empty array if the value is not a valid JSON array', () => { + expect(stringifyJson({})).toEqual('[\n\n]'); + }); + }); + + describe('parseJson()', () => { + it('should parse a valid JSON string', () => { + expect(parseJson('[1,2,3]')).toEqual([1, 2, 3]); + expect(parseJson('[{"foo": "bar"}]')).toEqual([{ foo: 'bar' }]); + }); + + it('should convert valid JSON that is not an array to an array', () => { + expect(parseJson('{"foo": "bar"}')).toEqual([{ foo: 'bar' }]); + }); + + it('should return an empty array if invalid JSON string', () => { + expect(parseJson('{invalidJsonString}')).toEqual([]); + }); + }); +}); diff --git a/x-pack/plugins/ingest_pipelines/public/application/lib/utils.ts b/x-pack/plugins/ingest_pipelines/public/application/lib/utils.ts new file mode 100644 index 0000000000000..fe4e9e65f4b9a --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/lib/utils.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. + */ + +export const stringifyJson = (json: any): string => + Array.isArray(json) ? JSON.stringify(json, null, 2) : '[\n\n]'; + +export const parseJson = (jsonString: string): object[] => { + let parsedJSON: any; + + try { + parsedJSON = JSON.parse(jsonString); + + if (!Array.isArray(parsedJSON)) { + // Convert object to array + parsedJSON = [parsedJSON]; + } + } catch { + parsedJSON = []; + } + + return parsedJSON; +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/mount_management_section.ts b/x-pack/plugins/ingest_pipelines/public/application/mount_management_section.ts new file mode 100644 index 0000000000000..e36f27cbf5f62 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/mount_management_section.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 { CoreSetup } from 'src/core/public'; +import { ManagementAppMountParams } from 'src/plugins/management/public'; + +import { documentationService, uiMetricService, apiService, breadcrumbService } from './services'; +import { renderApp } from '.'; + +export async function mountManagementSection( + { http, getStartServices, notifications }: CoreSetup, + params: ManagementAppMountParams +) { + const { element, setBreadcrumbs } = params; + const [coreStart] = await getStartServices(); + const { + docLinks, + i18n: { Context: I18nContext }, + } = coreStart; + + documentationService.setup(docLinks); + breadcrumbService.setup(setBreadcrumbs); + + const services = { + breadcrumbs: breadcrumbService, + metric: uiMetricService, + documentation: documentationService, + api: apiService, + notifications, + }; + + return renderApp(element, I18nContext, services, { http }); +} diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/index.ts b/x-pack/plugins/ingest_pipelines/public/application/sections/index.ts new file mode 100644 index 0000000000000..b2925666c5768 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { PipelinesList } from './pipelines_list'; + +export { PipelinesCreate } from './pipelines_create'; + +export { PipelinesEdit } from './pipelines_edit'; + +export { PipelinesClone } from './pipelines_clone'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/index.ts b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/index.ts new file mode 100644 index 0000000000000..614a3598d407d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/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 { PipelinesClone } from './pipelines_clone'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/pipelines_clone.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/pipelines_clone.tsx new file mode 100644 index 0000000000000..b3b1217caf834 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_clone/pipelines_clone.tsx @@ -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 React, { FunctionComponent, useEffect } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { SectionLoading, useKibana } from '../../../shared_imports'; + +import { PipelinesCreate } from '../pipelines_create'; + +export interface ParamProps { + sourceName: string; +} + +/** + * This section is a wrapper around the create section where we receive a pipeline name + * to load and set as the source pipeline for the {@link PipelinesCreate} form. + */ +export const PipelinesClone: FunctionComponent> = props => { + const { sourceName } = props.match.params; + const { services } = useKibana(); + + const { error, data: pipeline, isLoading, isInitialRequest } = services.api.useLoadPipeline( + decodeURIComponent(sourceName) + ); + + useEffect(() => { + if (error && !isLoading) { + services.notifications!.toasts.addError(error, { + title: i18n.translate('xpack.ingestPipelines.clone.loadSourcePipelineErrorTitle', { + defaultMessage: 'Cannot load {name}.', + values: { name: sourceName }, + }), + }); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [error, isLoading]); + + if (isLoading && isInitialRequest) { + return ( + + + + ); + } else { + // We still show the create form even if we were not able to load the + // latest pipeline data. + const sourcePipeline = pipeline ? { ...pipeline, name: `${pipeline.name}-copy` } : undefined; + return ; + } +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_create/index.ts b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_create/index.ts new file mode 100644 index 0000000000000..374defa869916 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_create/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 { PipelinesCreate } from './pipelines_create'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_create/pipelines_create.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_create/pipelines_create.tsx new file mode 100644 index 0000000000000..34a362d596d92 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_create/pipelines_create.tsx @@ -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 React, { useState, useEffect } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiPageBody, + EuiPageContent, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiSpacer, +} from '@elastic/eui'; + +import { BASE_PATH } from '../../../../common/constants'; +import { Pipeline } from '../../../../common/types'; +import { useKibana } from '../../../shared_imports'; +import { PipelineForm } from '../../components'; + +interface Props { + /** + * This value may be passed in to prepopulate the creation form + */ + sourcePipeline?: Pipeline; +} + +export const PipelinesCreate: React.FunctionComponent = ({ + history, + sourcePipeline, +}) => { + const { services } = useKibana(); + + const [isSaving, setIsSaving] = useState(false); + const [saveError, setSaveError] = useState(null); + + const onSave = async (pipeline: Pipeline) => { + setIsSaving(true); + setSaveError(null); + + const { error } = await services.api.createPipeline(pipeline); + + setIsSaving(false); + + if (error) { + setSaveError(error); + return; + } + + history.push(BASE_PATH + `?pipeline=${pipeline.name}`); + }; + + const onCancel = () => { + history.push(BASE_PATH); + }; + + useEffect(() => { + services.breadcrumbs.setBreadcrumbs('create'); + }, [services]); + + return ( + + + + + + +

+ +

+
+
+ + + + + + +
+
+ + + + +
+
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/index.ts b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/index.ts new file mode 100644 index 0000000000000..26458d23fd6d8 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/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 { PipelinesEdit } from './pipelines_edit'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/pipelines_edit.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/pipelines_edit.tsx new file mode 100644 index 0000000000000..99cd8d7eef97b --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_edit/pipelines_edit.tsx @@ -0,0 +1,151 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useState, useEffect } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiPageBody, + EuiPageContent, + EuiSpacer, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, +} from '@elastic/eui'; + +import { EuiCallOut } from '@elastic/eui'; +import { BASE_PATH } from '../../../../common/constants'; +import { Pipeline } from '../../../../common/types'; +import { useKibana, SectionLoading } from '../../../shared_imports'; +import { PipelineForm } from '../../components'; + +interface MatchParams { + name: string; +} + +export const PipelinesEdit: React.FunctionComponent> = ({ + match: { + params: { name }, + }, + history, +}) => { + const { services } = useKibana(); + + const [isSaving, setIsSaving] = useState(false); + const [saveError, setSaveError] = useState(null); + + const decodedPipelineName = decodeURI(decodeURIComponent(name)); + + const { error, data: pipeline, isLoading } = services.api.useLoadPipeline(decodedPipelineName); + + const onSave = async (updatedPipeline: Pipeline) => { + setIsSaving(true); + setSaveError(null); + + const { error: savePipelineError } = await services.api.updatePipeline(updatedPipeline); + + setIsSaving(false); + + if (savePipelineError) { + setSaveError(savePipelineError); + return; + } + + history.push(BASE_PATH + `?pipeline=${updatedPipeline.name}`); + }; + + const onCancel = () => { + history.push(BASE_PATH); + }; + + useEffect(() => { + services.breadcrumbs.setBreadcrumbs('edit'); + }, [services.breadcrumbs]); + + let content: React.ReactNode; + + if (isLoading) { + content = ( + + + + ); + } else if (error) { + content = ( + <> + + } + color="danger" + iconType="alert" + data-test-subj="fetchPipelineError" + > +

{error.message}

+
+ + + ); + } else if (pipeline) { + content = ( + + ); + } + + return ( + + + + + + +

+ +

+
+
+ + + + + + +
+
+ + + + {content} +
+
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/delete_modal.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/delete_modal.tsx new file mode 100644 index 0000000000000..c7736a6c19ba1 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/delete_modal.tsx @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { useKibana } from '../../../shared_imports'; + +export const PipelineDeleteModal = ({ + pipelinesToDelete, + callback, +}: { + pipelinesToDelete: string[]; + callback: (data?: { hasDeletedPipelines: boolean }) => void; +}) => { + const { services } = useKibana(); + + const numPipelinesToDelete = pipelinesToDelete.length; + + const handleDeletePipelines = () => { + services.api + .deletePipelines(pipelinesToDelete) + .then(({ data: { itemsDeleted, errors }, error }) => { + const hasDeletedPipelines = itemsDeleted && itemsDeleted.length; + + if (hasDeletedPipelines) { + const successMessage = + itemsDeleted.length === 1 + ? i18n.translate( + 'xpack.ingestPipelines.deleteModal.successDeleteSingleNotificationMessageText', + { + defaultMessage: "Deleted pipeline '{pipelineName}'", + values: { pipelineName: pipelinesToDelete[0] }, + } + ) + : i18n.translate( + 'xpack.ingestPipelines.deleteModal.successDeleteMultipleNotificationMessageText', + { + defaultMessage: + 'Deleted {numSuccesses, plural, one {# pipeline} other {# pipelines}}', + values: { numSuccesses: itemsDeleted.length }, + } + ); + + callback({ hasDeletedPipelines }); + services.notifications.toasts.addSuccess(successMessage); + } + + if (error || errors?.length) { + const hasMultipleErrors = errors?.length > 1 || (error && pipelinesToDelete.length > 1); + const errorMessage = hasMultipleErrors + ? i18n.translate( + 'xpack.ingestPipelines.deleteModal.multipleErrorsNotificationMessageText', + { + defaultMessage: 'Error deleting {count} pipelines', + values: { + count: errors?.length || pipelinesToDelete.length, + }, + } + ) + : i18n.translate('xpack.ingestPipelines.deleteModal.errorNotificationMessageText', { + defaultMessage: "Error deleting pipeline '{name}'", + values: { name: (errors && errors[0].name) || pipelinesToDelete[0] }, + }); + services.notifications.toasts.addDanger(errorMessage); + } + }); + }; + + const handleOnCancel = () => { + callback(); + }; + + return ( + + + } + onCancel={handleOnCancel} + onConfirm={handleDeletePipelines} + cancelButtonText={ + + } + confirmButtonText={ + + } + > + <> +

+ +

+ +
    + {pipelinesToDelete.map(name => ( +
  • {name}
  • + ))} +
+ +
+
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_flyout.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_flyout.tsx new file mode 100644 index 0000000000000..98243a5149c0d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_flyout.tsx @@ -0,0 +1,210 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { FunctionComponent, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { + EuiFlyout, + EuiFlyoutHeader, + EuiFlyoutBody, + EuiTitle, + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, + EuiFlyoutFooter, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiIcon, + EuiPopover, + EuiContextMenu, + EuiButton, +} from '@elastic/eui'; + +import { Pipeline } from '../../../../common/types'; + +import { PipelineDetailsJsonBlock } from './details_json_block'; + +export interface Props { + pipeline: Pipeline; + onEditClick: (pipelineName: string) => void; + onCloneClick: (pipelineName: string) => void; + onDeleteClick: (pipelineName: string[]) => void; + onClose: () => void; +} + +export const PipelineDetailsFlyout: FunctionComponent = ({ + pipeline, + onClose, + onEditClick, + onCloneClick, + onDeleteClick, +}) => { + const [showPopover, setShowPopover] = useState(false); + const actionMenuItems = [ + /** + * Edit pipeline + */ + { + name: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.editActionLabel', { + defaultMessage: 'Edit', + }), + icon: , + onClick: () => onEditClick(pipeline.name), + }, + /** + * Clone pipeline + */ + { + name: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.cloneActionLabel', { + defaultMessage: 'Clone', + }), + icon: , + onClick: () => onCloneClick(pipeline.name), + }, + /** + * Delete pipeline + */ + { + name: i18n.translate('xpack.ingestPipelines.list.pipelineDetails.deleteActionLabel', { + defaultMessage: 'Delete', + }), + icon: , + onClick: () => onDeleteClick([pipeline.name]), + }, + ]; + + const managePipelineButton = ( + setShowPopover(previousBool => !previousBool)} + iconType="arrowUp" + iconSide="right" + fill + > + {i18n.translate('xpack.ingestPipelines.list.pipelineDetails.managePipelineButtonLabel', { + defaultMessage: 'Manage', + })} + + ); + + return ( + + + +

{pipeline.name}

+
+
+ + + + {/* Pipeline description */} + + {i18n.translate('xpack.ingestPipelines.list.pipelineDetails.descriptionTitle', { + defaultMessage: 'Description', + })} + + + {pipeline.description ?? ''} + + + {/* Pipeline version */} + {pipeline.version && ( + <> + + {i18n.translate('xpack.ingestPipelines.list.pipelineDetails.versionTitle', { + defaultMessage: 'Version', + })} + + + {String(pipeline.version)} + + + )} + + {/* Processors JSON */} + + {i18n.translate('xpack.ingestPipelines.list.pipelineDetails.processorsTitle', { + defaultMessage: 'Processors JSON', + })} + + + + + + {/* On Failure Processor JSON */} + {pipeline.on_failure?.length && ( + <> + + {i18n.translate( + 'xpack.ingestPipelines.list.pipelineDetails.failureProcessorsTitle', + { + defaultMessage: 'On failure processors JSON', + } + )} + + + + + + )} + + + + + + + + {i18n.translate('xpack.ingestPipelines.list.pipelineDetails.closeButtonLabel', { + defaultMessage: 'Close', + })} + + + + + setShowPopover(false)} + button={managePipelineButton} + panelPaddingSize="none" + withTitle + repositionOnScroll + > + + + + + + +
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_json_block.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_json_block.tsx new file mode 100644 index 0000000000000..6c44336c7547d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/details_json_block.tsx @@ -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 React, { FunctionComponent, useRef } from 'react'; +import { EuiCodeBlock } from '@elastic/eui'; + +export interface Props { + json: Record; +} + +export const PipelineDetailsJsonBlock: FunctionComponent = ({ json }) => { + // Hack so copied-to-clipboard value updates as content changes + // Related issue: https://github.com/elastic/eui/issues/3321 + const uuid = useRef(0); + uuid.current++; + + return ( + 0 ? 300 : undefined} + isCopyable + key={uuid.current} + > + {JSON.stringify(json, null, 2)} + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/empty_list.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/empty_list.tsx new file mode 100644 index 0000000000000..ef64fb33a6a55 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/empty_list.tsx @@ -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 React, { FunctionComponent } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiButton, EuiEmptyPrompt } from '@elastic/eui'; +import { BASE_PATH } from '../../../../common/constants'; + +export const EmptyList: FunctionComponent = () => ( + + {i18n.translate('xpack.ingestPipelines.list.table.emptyPromptTitle', { + defaultMessage: 'Start by creating a pipeline', + })} + + } + actions={ + + {i18n.translate('xpack.ingestPipelines.list.table.emptyPrompt.createButtonLabel', { + defaultMessage: 'Create a pipeline', + })} + + } + /> +); diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/index.ts b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/index.ts new file mode 100644 index 0000000000000..a541e3bb85fd0 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/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 { PipelinesList } from './main'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx new file mode 100644 index 0000000000000..c90ac2714a95a --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/main.tsx @@ -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 React, { useEffect, useState } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { Location } from 'history'; +import { parse } from 'query-string'; + +import { + EuiPageBody, + EuiPageContent, + EuiTitle, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiCallOut, +} from '@elastic/eui'; + +import { EuiSpacer, EuiText } from '@elastic/eui'; + +import { Pipeline } from '../../../../common/types'; +import { BASE_PATH } from '../../../../common/constants'; +import { useKibana, SectionLoading } from '../../../shared_imports'; +import { UIM_PIPELINES_LIST_LOAD } from '../../constants'; + +import { EmptyList } from './empty_list'; +import { PipelineTable } from './table'; +import { PipelineDetailsFlyout } from './details_flyout'; +import { PipelineNotFoundFlyout } from './not_found_flyout'; +import { PipelineDeleteModal } from './delete_modal'; + +const getPipelineNameFromLocation = (location: Location) => { + const { pipeline } = parse(location.search.substring(1)); + return pipeline; +}; + +export const PipelinesList: React.FunctionComponent = ({ + history, + location, +}) => { + const { services } = useKibana(); + const pipelineNameFromLocation = getPipelineNameFromLocation(location); + + const [selectedPipeline, setSelectedPipeline] = useState(undefined); + const [showFlyout, setShowFlyout] = useState(false); + + const [pipelinesToDelete, setPipelinesToDelete] = useState([]); + + const { data, isLoading, error, sendRequest } = services.api.useLoadPipelines(); + + // Track component loaded + useEffect(() => { + services.metric.trackUiMetric(UIM_PIPELINES_LIST_LOAD); + services.breadcrumbs.setBreadcrumbs('home'); + }, [services.metric, services.breadcrumbs]); + + useEffect(() => { + if (pipelineNameFromLocation && data?.length) { + const pipeline = data.find(p => p.name === pipelineNameFromLocation); + setSelectedPipeline(pipeline); + setShowFlyout(true); + } + }, [pipelineNameFromLocation, data]); + + const goToEditPipeline = (name: string) => { + history.push(`${BASE_PATH}/edit/${encodeURIComponent(name)}`); + }; + + const goToClonePipeline = (name: string) => { + history.push(`${BASE_PATH}/create/${encodeURIComponent(name)}`); + }; + + const goHome = () => { + setShowFlyout(false); + history.push(BASE_PATH); + }; + + let content: React.ReactNode; + + if (isLoading) { + content = ( + + + + ); + } else if (data?.length) { + content = ( + + ); + } else { + content = ; + } + + const renderFlyout = (): React.ReactNode => { + if (!showFlyout) { + return; + } + if (selectedPipeline) { + return ( + { + setSelectedPipeline(undefined); + goHome(); + }} + onEditClick={goToEditPipeline} + onCloneClick={goToClonePipeline} + onDeleteClick={setPipelinesToDelete} + /> + ); + } else { + // Somehow we triggered show pipeline details, but do not have a pipeline. + // We assume not found. + return ( + { + goHome(); + }} + pipelineName={pipelineNameFromLocation} + /> + ); + } + }; + + return ( + <> + + + + + +

+ +

+
+ + + + + +
+
+ + + + + + + + {/* Error call out for pipeline table */} + {error ? ( + + ) : ( + content + )} +
+
+ {renderFlyout()} + {pipelinesToDelete?.length > 0 ? ( + { + if (deleteResponse?.hasDeletedPipelines) { + // reload pipelines list + sendRequest(); + } + setPipelinesToDelete([]); + setSelectedPipeline(undefined); + }} + pipelinesToDelete={pipelinesToDelete} + /> + ) : null} + + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/not_found_flyout.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/not_found_flyout.tsx new file mode 100644 index 0000000000000..b967e54187ced --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/not_found_flyout.tsx @@ -0,0 +1,42 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { FunctionComponent } from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiFlyout, EuiFlyoutBody, EuiCallOut } from '@elastic/eui'; +import { EuiFlyoutHeader, EuiTitle } from '@elastic/eui'; + +interface Props { + onClose: () => void; + pipelineName: string | string[] | null | undefined; +} + +export const PipelineNotFoundFlyout: FunctionComponent = ({ onClose, pipelineName }) => { + return ( + + + {pipelineName && ( + +

{pipelineName}

+
+ )} +
+ + + + } + color="danger" + iconType="alert" + /> + +
+ ); +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/table.tsx b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/table.tsx new file mode 100644 index 0000000000000..c93285289ff39 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/sections/pipelines_list/table.tsx @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { FunctionComponent, useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiInMemoryTable, EuiLink, EuiButton, EuiInMemoryTableProps } from '@elastic/eui'; + +import { BASE_PATH } from '../../../../common/constants'; +import { Pipeline } from '../../../../common/types'; + +export interface Props { + pipelines: Pipeline[]; + onReloadClick: () => void; + onEditPipelineClick: (pipelineName: string) => void; + onClonePipelineClick: (pipelineName: string) => void; + onDeletePipelineClick: (pipelineName: string[]) => void; +} + +export const PipelineTable: FunctionComponent = ({ + pipelines, + onReloadClick, + onEditPipelineClick, + onClonePipelineClick, + onDeletePipelineClick, +}) => { + const [selection, setSelection] = useState([]); + + const tableProps: EuiInMemoryTableProps = { + itemId: 'name', + isSelectable: true, + sorting: { sort: { field: 'name', direction: 'asc' } }, + selection: { + onSelectionChange: setSelection, + }, + search: { + toolsLeft: + selection.length > 0 ? ( + onDeletePipelineClick(selection.map(pipeline => pipeline.name))} + color="danger" + > + + + ) : ( + undefined + ), + toolsRight: [ + + {i18n.translate('xpack.ingestPipelines.list.table.reloadButtonLabel', { + defaultMessage: 'Reload', + })} + , + + {i18n.translate('xpack.ingestPipelines.list.table.createPipelineButtonLabel', { + defaultMessage: 'Create a pipeline', + })} + , + ], + box: { + incremental: true, + }, + }, + pagination: { + initialPageSize: 10, + pageSizeOptions: [10, 20, 50], + }, + columns: [ + { + field: 'name', + name: i18n.translate('xpack.ingestPipelines.list.table.nameColumnTitle', { + defaultMessage: 'Name', + }), + sortable: true, + render: (name: string) => {name}, + }, + { + name: ( + + ), + actions: [ + { + isPrimary: true, + name: i18n.translate('xpack.ingestPipelines.list.table.editActionLabel', { + defaultMessage: 'Edit', + }), + description: i18n.translate('xpack.ingestPipelines.list.table.editActionDescription', { + defaultMessage: 'Edit this pipeline', + }), + type: 'icon', + icon: 'pencil', + onClick: ({ name }) => onEditPipelineClick(name), + }, + { + name: i18n.translate('xpack.ingestPipelines.list.table.cloneActionLabel', { + defaultMessage: 'Clone', + }), + description: i18n.translate('xpack.ingestPipelines.list.table.cloneActionDescription', { + defaultMessage: 'Clone this pipeline', + }), + type: 'icon', + icon: 'copy', + onClick: ({ name }) => onClonePipelineClick(name), + }, + { + isPrimary: true, + name: i18n.translate('xpack.ingestPipelines.list.table.deleteActionLabel', { + defaultMessage: 'Delete', + }), + description: i18n.translate( + 'xpack.ingestPipelines.list.table.deleteActionDescription', + { defaultMessage: 'Delete this pipeline' } + ), + type: 'icon', + icon: 'trash', + color: 'danger', + onClick: ({ name }) => onDeletePipelineClick([name]), + }, + ], + }, + ], + items: pipelines ?? [], + }; + + return ; +}; diff --git a/x-pack/plugins/ingest_pipelines/public/application/services/api.ts b/x-pack/plugins/ingest_pipelines/public/application/services/api.ts new file mode 100644 index 0000000000000..13eb96e78adae --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/services/api.ts @@ -0,0 +1,125 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { HttpSetup } from 'src/core/public'; + +import { Pipeline } from '../../../common/types'; +import { API_BASE_PATH } from '../../../common/constants'; +import { + UseRequestConfig, + SendRequestConfig, + SendRequestResponse, + sendRequest as _sendRequest, + useRequest as _useRequest, +} from '../../shared_imports'; +import { UiMetricService } from './ui_metric'; +import { + UIM_PIPELINE_CREATE, + UIM_PIPELINE_UPDATE, + UIM_PIPELINE_DELETE, + UIM_PIPELINE_DELETE_MANY, + UIM_PIPELINE_SIMULATE, +} from '../constants'; + +export class ApiService { + private client: HttpSetup | undefined; + private uiMetricService: UiMetricService | undefined; + + private useRequest(config: UseRequestConfig) { + if (!this.client) { + throw new Error('Api service has not be initialized.'); + } + return _useRequest(this.client, config); + } + + private sendRequest( + config: SendRequestConfig + ): Promise> { + if (!this.client) { + throw new Error('Api service has not be initialized.'); + } + return _sendRequest(this.client, config); + } + + private trackUiMetric(eventName: string) { + if (!this.uiMetricService) { + throw new Error('UI metric service has not be initialized.'); + } + return this.uiMetricService.trackUiMetric(eventName); + } + + public setup(httpClient: HttpSetup, uiMetricService: UiMetricService): void { + this.client = httpClient; + this.uiMetricService = uiMetricService; + } + + public useLoadPipelines() { + return this.useRequest({ + path: API_BASE_PATH, + method: 'get', + }); + } + + public useLoadPipeline(name: string) { + return this.useRequest({ + path: `${API_BASE_PATH}/${encodeURIComponent(name)}`, + method: 'get', + }); + } + + public async createPipeline(pipeline: Pipeline) { + const result = await this.sendRequest({ + path: API_BASE_PATH, + method: 'post', + body: JSON.stringify(pipeline), + }); + + this.trackUiMetric(UIM_PIPELINE_CREATE); + + return result; + } + + public async updatePipeline(pipeline: Pipeline) { + const { name, ...body } = pipeline; + const result = await this.sendRequest({ + path: `${API_BASE_PATH}/${encodeURIComponent(name)}`, + method: 'put', + body: JSON.stringify(body), + }); + + this.trackUiMetric(UIM_PIPELINE_UPDATE); + + return result; + } + + public async deletePipelines(names: string[]) { + const result = this.sendRequest({ + path: `${API_BASE_PATH}/${names.map(name => encodeURIComponent(name)).join(',')}`, + method: 'delete', + }); + + this.trackUiMetric(names.length > 1 ? UIM_PIPELINE_DELETE_MANY : UIM_PIPELINE_DELETE); + + return result; + } + + public async simulatePipeline(testConfig: { + documents: object[]; + verbose?: boolean; + pipeline: Omit; + }) { + const result = await this.sendRequest({ + path: `${API_BASE_PATH}/simulate`, + method: 'post', + body: JSON.stringify(testConfig), + }); + + this.trackUiMetric(UIM_PIPELINE_SIMULATE); + + return result; + } +} + +export const apiService = new ApiService(); diff --git a/x-pack/plugins/ingest_pipelines/public/application/services/breadcrumbs.ts b/x-pack/plugins/ingest_pipelines/public/application/services/breadcrumbs.ts new file mode 100644 index 0000000000000..1ccdbbad9b1bb --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/services/breadcrumbs.ts @@ -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 { i18n } from '@kbn/i18n'; +import { BASE_PATH } from '../../../common/constants'; +import { ManagementAppMountParams } from '../../../../../../src/plugins/management/public'; + +type SetBreadcrumbs = ManagementAppMountParams['setBreadcrumbs']; + +const homeBreadcrumbText = i18n.translate('xpack.ingestPipelines.breadcrumb.pipelinesLabel', { + defaultMessage: 'Ingest Node Pipelines', +}); + +export class BreadcrumbService { + private breadcrumbs: { + [key: string]: Array<{ + text: string; + href?: string; + }>; + } = { + home: [ + { + text: homeBreadcrumbText, + }, + ], + create: [ + { + text: homeBreadcrumbText, + href: `#${BASE_PATH}`, + }, + { + text: i18n.translate('xpack.ingestPipelines.breadcrumb.createPipelineLabel', { + defaultMessage: 'Create pipeline', + }), + }, + ], + edit: [ + { + text: homeBreadcrumbText, + href: `#${BASE_PATH}`, + }, + { + text: i18n.translate('xpack.ingestPipelines.breadcrumb.editPipelineLabel', { + defaultMessage: 'Edit pipeline', + }), + }, + ], + }; + + private setBreadcrumbsHandler?: SetBreadcrumbs; + + public setup(setBreadcrumbsHandler: SetBreadcrumbs): void { + this.setBreadcrumbsHandler = setBreadcrumbsHandler; + } + + public setBreadcrumbs(type: 'create' | 'home' | 'edit'): void { + if (!this.setBreadcrumbsHandler) { + throw new Error('Breadcrumb service has not been initialized'); + } + + const newBreadcrumbs = this.breadcrumbs[type] + ? [...this.breadcrumbs[type]] + : [...this.breadcrumbs.home]; + + this.setBreadcrumbsHandler(newBreadcrumbs); + } +} + +export const breadcrumbService = new BreadcrumbService(); diff --git a/x-pack/plugins/ingest_pipelines/public/application/services/documentation.ts b/x-pack/plugins/ingest_pipelines/public/application/services/documentation.ts new file mode 100644 index 0000000000000..05fdc4b1dfb84 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/services/documentation.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 { DocLinksStart } from 'src/core/public'; + +export class DocumentationService { + private esDocBasePath: string = ''; + + public setup(docLinks: DocLinksStart): void { + const { DOC_LINK_VERSION, ELASTIC_WEBSITE_URL } = docLinks; + const docsBase = `${ELASTIC_WEBSITE_URL}guide/en`; + + this.esDocBasePath = `${docsBase}/elasticsearch/reference/${DOC_LINK_VERSION}`; + } + + public getIngestNodeUrl() { + return `${this.esDocBasePath}/ingest.html`; + } + + public getProcessorsUrl() { + return `${this.esDocBasePath}/ingest-processors.html`; + } + + public getHandlingFailureUrl() { + return `${this.esDocBasePath}/handling-failure-in-pipelines.html`; + } + + public getPutPipelineApiUrl() { + return `${this.esDocBasePath}/put-pipeline-api.html`; + } + + public getSimulatePipelineApiUrl() { + return `${this.esDocBasePath}/simulate-pipeline-api.html`; + } +} + +export const documentationService = new DocumentationService(); diff --git a/x-pack/plugins/ingest_pipelines/public/application/services/index.ts b/x-pack/plugins/ingest_pipelines/public/application/services/index.ts new file mode 100644 index 0000000000000..f03a7824f8364 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/services/index.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { documentationService, DocumentationService } from './documentation'; + +export { uiMetricService, UiMetricService } from './ui_metric'; + +export { apiService, ApiService } from './api'; + +export { breadcrumbService, BreadcrumbService } from './breadcrumbs'; diff --git a/x-pack/plugins/ingest_pipelines/public/application/services/ui_metric.ts b/x-pack/plugins/ingest_pipelines/public/application/services/ui_metric.ts new file mode 100644 index 0000000000000..f99bb9ba331d2 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/application/services/ui_metric.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 { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; + +import { UIM_APP_NAME } from '../constants'; + +export class UiMetricService { + private usageCollection: UsageCollectionSetup | undefined; + + public setup(usageCollection: UsageCollectionSetup) { + this.usageCollection = usageCollection; + } + + private track(name: string) { + if (!this.usageCollection) { + // Usage collection is an optional plugin and might be disabled + return; + } + + const { reportUiStats, METRIC_TYPE } = this.usageCollection; + reportUiStats(UIM_APP_NAME, METRIC_TYPE.COUNT, name); + } + + public trackUiMetric(eventName: string) { + return this.track(eventName); + } +} + +export const uiMetricService = new UiMetricService(); diff --git a/x-pack/plugins/ingest_pipelines/public/index.ts b/x-pack/plugins/ingest_pipelines/public/index.ts new file mode 100644 index 0000000000000..7247973703804 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/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. + */ + +import { IngestPipelinesPlugin } from './plugin'; + +export function plugin() { + return new IngestPipelinesPlugin(); +} diff --git a/x-pack/plugins/ingest_pipelines/public/plugin.ts b/x-pack/plugins/ingest_pipelines/public/plugin.ts new file mode 100644 index 0000000000000..e9f5fd6c7f57c --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/plugin.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 { i18n } from '@kbn/i18n'; +import { CoreSetup, Plugin } from 'src/core/public'; + +import { PLUGIN_ID } from '../common/constants'; +import { uiMetricService, apiService } from './application/services'; +import { Dependencies } from './types'; + +export class IngestPipelinesPlugin implements Plugin { + public setup(coreSetup: CoreSetup, plugins: Dependencies): void { + const { management, usageCollection } = plugins; + const { http } = coreSetup; + + // Initialize services + uiMetricService.setup(usageCollection); + apiService.setup(http, uiMetricService); + + management.sections.getSection('elasticsearch')!.registerApp({ + id: PLUGIN_ID, + title: i18n.translate('xpack.ingestPipelines.appTitle', { + defaultMessage: 'Ingest Node Pipelines', + }), + mount: async params => { + const { mountManagementSection } = await import('./application/mount_management_section'); + + return await mountManagementSection(coreSetup, params); + }, + }); + } + + public start() {} + + public stop() {} +} diff --git a/x-pack/plugins/ingest_pipelines/public/shared_imports.ts b/x-pack/plugins/ingest_pipelines/public/shared_imports.ts new file mode 100644 index 0000000000000..cfa946ff942ec --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/shared_imports.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 { useKibana as _useKibana } from '../../../../src/plugins/kibana_react/public'; +import { AppServices } from './application'; + +export { + SendRequestConfig, + SendRequestResponse, + UseRequestConfig, + sendRequest, + useRequest, +} from '../../../../src/plugins/es_ui_shared/public/request/np_ready_request'; + +export { + FormSchema, + FIELD_TYPES, + FormConfig, + useForm, + Form, + getUseField, + ValidationFuncArg, + useFormContext, +} from '../../../../src/plugins/es_ui_shared/static/forms/hook_form_lib'; + +export { + fieldFormatters, + fieldValidators, +} from '../../../../src/plugins/es_ui_shared/static/forms/helpers'; + +export { + getFormRow, + Field, + JsonEditorField, +} from '../../../../src/plugins/es_ui_shared/static/forms/components'; + +export { + isJSON, + isEmptyString, +} from '../../../../src/plugins/es_ui_shared/static/validators/string'; + +export { + SectionLoading, + WithPrivileges, + AuthorizationProvider, + SectionError, + Error, + useAuthorizationContext, + NotAuthorizedSection, +} from '../../../../src/plugins/es_ui_shared/public'; + +export const useKibana = () => _useKibana(); diff --git a/x-pack/plugins/ingest_pipelines/public/types.ts b/x-pack/plugins/ingest_pipelines/public/types.ts new file mode 100644 index 0000000000000..91783ea04fa9a --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/public/types.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ManagementSetup } from 'src/plugins/management/public'; +import { UsageCollectionSetup } from 'src/plugins/usage_collection/public'; + +export interface Dependencies { + management: ManagementSetup; + usageCollection: UsageCollectionSetup; +} diff --git a/x-pack/plugins/ingest_pipelines/server/index.ts b/x-pack/plugins/ingest_pipelines/server/index.ts new file mode 100644 index 0000000000000..dc162a5d67cb6 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/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 { PluginInitializerContext } from '../../../../src/core/server'; +import { IngestPipelinesPlugin } from './plugin'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new IngestPipelinesPlugin(initializerContext); +} diff --git a/x-pack/plugins/ingest_pipelines/server/lib/index.ts b/x-pack/plugins/ingest_pipelines/server/lib/index.ts new file mode 100644 index 0000000000000..a9a3c61472d8c --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/lib/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 { isEsError } from './is_es_error'; diff --git a/x-pack/plugins/ingest_pipelines/server/lib/is_es_error.ts b/x-pack/plugins/ingest_pipelines/server/lib/is_es_error.ts new file mode 100644 index 0000000000000..4137293cf39c0 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/lib/is_es_error.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import * as legacyElasticsearch from 'elasticsearch'; + +const esErrorsParent = legacyElasticsearch.errors._Abstract; + +export function isEsError(err: Error) { + return err instanceof esErrorsParent; +} diff --git a/x-pack/plugins/ingest_pipelines/server/plugin.ts b/x-pack/plugins/ingest_pipelines/server/plugin.ts new file mode 100644 index 0000000000000..b27ca417c3e3c --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/plugin.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 { i18n } from '@kbn/i18n'; + +import { PluginInitializerContext, CoreSetup, Plugin, Logger } from 'kibana/server'; + +import { PLUGIN_ID, PLUGIN_MIN_LICENSE_TYPE } from '../common/constants'; + +import { License } from './services'; +import { ApiRoutes } from './routes'; +import { isEsError } from './lib'; +import { Dependencies } from './types'; + +export class IngestPipelinesPlugin implements Plugin { + private readonly logger: Logger; + private readonly license: License; + private readonly apiRoutes: ApiRoutes; + + constructor({ logger }: PluginInitializerContext) { + this.logger = logger.get(); + this.license = new License(); + this.apiRoutes = new ApiRoutes(); + } + + public setup({ http, elasticsearch }: CoreSetup, { licensing }: Dependencies) { + this.logger.debug('ingest_pipelines: setup'); + + const router = http.createRouter(); + + this.license.setup( + { + pluginId: PLUGIN_ID, + minimumLicenseType: PLUGIN_MIN_LICENSE_TYPE, + defaultErrorMessage: i18n.translate('xpack.ingestPipelines.licenseCheckErrorMessage', { + defaultMessage: 'License check failed', + }), + }, + { + licensing, + logger: this.logger, + } + ); + + this.apiRoutes.setup({ + router, + license: this.license, + lib: { + isEsError, + }, + }); + } + + public start() {} + + public stop() {} +} diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/create.ts new file mode 100644 index 0000000000000..63637eaac765d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/create.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 { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; + +import { Pipeline } from '../../../common/types'; +import { API_BASE_PATH } from '../../../common/constants'; +import { RouteDependencies } from '../../types'; + +const bodySchema = schema.object({ + name: schema.string(), + description: schema.string(), + processors: schema.arrayOf(schema.recordOf(schema.string(), schema.any())), + version: schema.maybe(schema.number()), + on_failure: schema.maybe(schema.arrayOf(schema.recordOf(schema.string(), schema.any()))), +}); + +export const registerCreateRoute = ({ + router, + license, + lib: { isEsError }, +}: RouteDependencies): void => { + router.post( + { + path: API_BASE_PATH, + validate: { + body: bodySchema, + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + const pipeline = req.body as Pipeline; + + const { name, description, processors, version, on_failure } = pipeline; + + try { + // Check that a pipeline with the same name doesn't already exist + const pipelineByName = await callAsCurrentUser('ingest.getPipeline', { id: name }); + + if (pipelineByName[name]) { + return res.conflict({ + body: new Error( + i18n.translate('xpack.ingestPipelines.createRoute.duplicatePipelineIdErrorMessage', { + defaultMessage: "There is already a pipeline with name '{name}'.", + values: { + name, + }, + }) + ), + }); + } + } catch (e) { + // Silently swallow error + } + + try { + const response = await callAsCurrentUser('ingest.putPipeline', { + id: name, + body: { + description, + processors, + version, + on_failure, + }, + }); + + return res.ok({ body: response }); + } catch (error) { + if (isEsError(error)) { + return res.customError({ + statusCode: error.statusCode, + body: error, + }); + } + + return res.internalError({ body: error }); + } + }) + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/delete.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/delete.ts new file mode 100644 index 0000000000000..4664b49a08a50 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/delete.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 { schema } from '@kbn/config-schema'; + +import { API_BASE_PATH } from '../../../common/constants'; +import { RouteDependencies } from '../../types'; + +const paramsSchema = schema.object({ + names: schema.string(), +}); + +export const registerDeleteRoute = ({ router, license }: RouteDependencies): void => { + router.delete( + { + path: `${API_BASE_PATH}/{names}`, + validate: { + params: paramsSchema, + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + const { names } = req.params; + const pipelineNames = names.split(','); + + const response: { itemsDeleted: string[]; errors: any[] } = { + itemsDeleted: [], + errors: [], + }; + + await Promise.all( + pipelineNames.map(pipelineName => { + return callAsCurrentUser('ingest.deletePipeline', { id: pipelineName }) + .then(() => response.itemsDeleted.push(pipelineName)) + .catch(e => + response.errors.push({ + name: pipelineName, + error: e, + }) + ); + }) + ); + + return res.ok({ body: response }); + }) + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/get.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/get.ts new file mode 100644 index 0000000000000..ec92262014272 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/get.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 { schema } from '@kbn/config-schema'; + +import { deserializePipelines } from '../../../common/lib'; +import { API_BASE_PATH } from '../../../common/constants'; +import { RouteDependencies } from '../../types'; + +const paramsSchema = schema.object({ + name: schema.string(), +}); + +export const registerGetRoutes = ({ + router, + license, + lib: { isEsError }, +}: RouteDependencies): void => { + // Get all pipelines + router.get( + { path: API_BASE_PATH, validate: false }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + + try { + const pipelines = await callAsCurrentUser('ingest.getPipeline'); + + return res.ok({ body: deserializePipelines(pipelines) }); + } catch (error) { + if (isEsError(error)) { + // ES returns 404 when there are no pipelines + // Instead, we return an empty array and 200 status back to the client + if (error.status === 404) { + return res.ok({ body: [] }); + } + + return res.customError({ + statusCode: error.statusCode, + body: error, + }); + } + + return res.internalError({ body: error }); + } + }) + ); + + // Get single pipeline + router.get( + { + path: `${API_BASE_PATH}/{name}`, + validate: { + params: paramsSchema, + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + const { name } = req.params; + + try { + const pipeline = await callAsCurrentUser('ingest.getPipeline', { id: name }); + + return res.ok({ + body: { + ...pipeline[name], + name, + }, + }); + } catch (error) { + if (isEsError(error)) { + return res.customError({ + statusCode: error.statusCode, + body: error, + }); + } + + return res.internalError({ body: error }); + } + }) + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/index.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/index.ts new file mode 100644 index 0000000000000..58a4bf5617659 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/index.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. + */ + +export { registerGetRoutes } from './get'; + +export { registerCreateRoute } from './create'; + +export { registerUpdateRoute } from './update'; + +export { registerPrivilegesRoute } from './privileges'; + +export { registerDeleteRoute } from './delete'; + +export { registerSimulateRoute } from './simulate'; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts new file mode 100644 index 0000000000000..2e1c11928959f --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/privileges.ts @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { RouteDependencies } from '../../types'; +import { API_BASE_PATH, APP_CLUSTER_REQUIRED_PRIVILEGES } from '../../../common/constants'; +import { Privileges } from '../../../../../../src/plugins/es_ui_shared/public'; + +const extractMissingPrivileges = (privilegesObject: { [key: string]: boolean } = {}): string[] => + Object.keys(privilegesObject).reduce((privileges: string[], privilegeName: string): string[] => { + if (!privilegesObject[privilegeName]) { + privileges.push(privilegeName); + } + return privileges; + }, []); + +export const registerPrivilegesRoute = ({ license, router }: RouteDependencies) => { + router.get( + { + path: `${API_BASE_PATH}/privileges`, + validate: false, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { + core: { + elasticsearch: { dataClient }, + }, + } = ctx; + + const privilegesResult: Privileges = { + hasAllPrivileges: true, + missingPrivileges: { + cluster: [], + }, + }; + + try { + const { has_all_requested: hasAllPrivileges, cluster } = await dataClient.callAsCurrentUser( + 'transport.request', + { + path: '/_security/user/_has_privileges', + method: 'POST', + body: { + cluster: APP_CLUSTER_REQUIRED_PRIVILEGES, + }, + } + ); + + if (!hasAllPrivileges) { + privilegesResult.missingPrivileges.cluster = extractMissingPrivileges(cluster); + } + + privilegesResult.hasAllPrivileges = hasAllPrivileges; + + return res.ok({ body: privilegesResult }); + } catch (e) { + return res.internalError(e); + } + }) + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts new file mode 100644 index 0000000000000..ca5fc78d118fd --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/simulate.ts @@ -0,0 +1,61 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { API_BASE_PATH } from '../../../common/constants'; +import { RouteDependencies } from '../../types'; + +const bodySchema = schema.object({ + pipeline: schema.object({ + description: schema.string(), + processors: schema.arrayOf(schema.recordOf(schema.string(), schema.any())), + version: schema.maybe(schema.number()), + on_failure: schema.maybe(schema.arrayOf(schema.recordOf(schema.string(), schema.any()))), + }), + documents: schema.arrayOf(schema.recordOf(schema.string(), schema.any())), + verbose: schema.maybe(schema.boolean()), +}); + +export const registerSimulateRoute = ({ + router, + license, + lib: { isEsError }, +}: RouteDependencies): void => { + router.post( + { + path: `${API_BASE_PATH}/simulate`, + validate: { + body: bodySchema, + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + + const { pipeline, documents, verbose } = req.body; + + try { + const response = await callAsCurrentUser('ingest.simulate', { + verbose, + body: { + pipeline, + docs: documents, + }, + }); + + return res.ok({ body: response }); + } catch (error) { + if (isEsError(error)) { + return res.customError({ + statusCode: error.statusCode, + body: error, + }); + } + + return res.internalError({ body: error }); + } + }) + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts b/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts new file mode 100644 index 0000000000000..a6fdee47f0ecf --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/routes/api/update.ts @@ -0,0 +1,67 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { API_BASE_PATH } from '../../../common/constants'; +import { RouteDependencies } from '../../types'; + +const bodySchema = schema.object({ + description: schema.string(), + processors: schema.arrayOf(schema.recordOf(schema.string(), schema.any())), + version: schema.maybe(schema.number()), + on_failure: schema.maybe(schema.arrayOf(schema.recordOf(schema.string(), schema.any()))), +}); + +const paramsSchema = schema.object({ + name: schema.string(), +}); + +export const registerUpdateRoute = ({ + router, + license, + lib: { isEsError }, +}: RouteDependencies): void => { + router.put( + { + path: `${API_BASE_PATH}/{name}`, + validate: { + body: bodySchema, + params: paramsSchema, + }, + }, + license.guardApiRoute(async (ctx, req, res) => { + const { callAsCurrentUser } = ctx.core.elasticsearch.dataClient; + const { name } = req.params; + const { description, processors, version, on_failure } = req.body; + + try { + // Verify pipeline exists; ES will throw 404 if it doesn't + await callAsCurrentUser('ingest.getPipeline', { id: name }); + + const response = await callAsCurrentUser('ingest.putPipeline', { + id: name, + body: { + description, + processors, + version, + on_failure, + }, + }); + + return res.ok({ body: response }); + } catch (error) { + if (isEsError(error)) { + return res.customError({ + statusCode: error.statusCode, + body: error, + }); + } + + return res.internalError({ body: error }); + } + }) + ); +}; diff --git a/x-pack/plugins/ingest_pipelines/server/routes/index.ts b/x-pack/plugins/ingest_pipelines/server/routes/index.ts new file mode 100644 index 0000000000000..f703a460143f4 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/routes/index.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 { RouteDependencies } from '../types'; + +import { + registerGetRoutes, + registerCreateRoute, + registerUpdateRoute, + registerPrivilegesRoute, + registerDeleteRoute, + registerSimulateRoute, +} from './api'; + +export class ApiRoutes { + setup(dependencies: RouteDependencies) { + registerGetRoutes(dependencies); + registerCreateRoute(dependencies); + registerUpdateRoute(dependencies); + registerPrivilegesRoute(dependencies); + registerDeleteRoute(dependencies); + registerSimulateRoute(dependencies); + } +} diff --git a/x-pack/plugins/ingest_pipelines/server/services/index.ts b/x-pack/plugins/ingest_pipelines/server/services/index.ts new file mode 100644 index 0000000000000..b7a45e59549eb --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/services/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 { License } from './license'; diff --git a/x-pack/plugins/ingest_pipelines/server/services/license.ts b/x-pack/plugins/ingest_pipelines/server/services/license.ts new file mode 100644 index 0000000000000..0a4748bd0ace0 --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/services/license.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { Logger } from 'src/core/server'; +import { + KibanaRequest, + KibanaResponseFactory, + RequestHandler, + RequestHandlerContext, +} from 'kibana/server'; + +import { LicensingPluginSetup } from '../../../licensing/server'; +import { LicenseType } from '../../../licensing/common/types'; + +export interface LicenseStatus { + isValid: boolean; + message?: string; +} + +interface SetupSettings { + pluginId: string; + minimumLicenseType: LicenseType; + defaultErrorMessage: string; +} + +export class License { + private licenseStatus: LicenseStatus = { + isValid: false, + message: 'Invalid License', + }; + + setup( + { pluginId, minimumLicenseType, defaultErrorMessage }: SetupSettings, + { licensing, logger }: { licensing: LicensingPluginSetup; logger: Logger } + ) { + licensing.license$.subscribe(license => { + const { state, message } = license.check(pluginId, minimumLicenseType); + const hasRequiredLicense = state === 'valid'; + + if (hasRequiredLicense) { + this.licenseStatus = { isValid: true }; + } else { + this.licenseStatus = { + isValid: false, + message: message || defaultErrorMessage, + }; + if (message) { + logger.info(message); + } + } + }); + } + + guardApiRoute(handler: RequestHandler) { + const license = this; + + return function licenseCheck( + ctx: RequestHandlerContext, + request: KibanaRequest, + response: KibanaResponseFactory + ) { + const licenseStatus = license.getStatus(); + + if (!licenseStatus.isValid) { + return response.customError({ + body: { + message: licenseStatus.message || '', + }, + statusCode: 403, + }); + } + + return handler(ctx, request, response); + }; + } + + getStatus() { + return this.licenseStatus; + } +} diff --git a/x-pack/plugins/ingest_pipelines/server/types.ts b/x-pack/plugins/ingest_pipelines/server/types.ts new file mode 100644 index 0000000000000..0135ae8e2f07d --- /dev/null +++ b/x-pack/plugins/ingest_pipelines/server/types.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { IRouter } from 'src/core/server'; +import { LicensingPluginSetup } from '../../licensing/server'; +import { License } from './services'; +import { isEsError } from './lib'; + +export interface Dependencies { + licensing: LicensingPluginSetup; +} + +export interface RouteDependencies { + router: IRouter; + license: License; + lib: { + isEsError: typeof isEsError; + }; +} diff --git a/x-pack/test/api_integration/apis/management/index.js b/x-pack/test/api_integration/apis/management/index.js index 352cd56d0fc9f..cef2caa918620 100644 --- a/x-pack/test/api_integration/apis/management/index.js +++ b/x-pack/test/api_integration/apis/management/index.js @@ -12,5 +12,6 @@ export default function({ loadTestFile }) { loadTestFile(require.resolve('./rollup')); loadTestFile(require.resolve('./index_management')); loadTestFile(require.resolve('./index_lifecycle_management')); + loadTestFile(require.resolve('./ingest_pipelines')); }); } diff --git a/x-pack/test/api_integration/apis/management/ingest_pipelines/index.ts b/x-pack/test/api_integration/apis/management/ingest_pipelines/index.ts new file mode 100644 index 0000000000000..ca222ebc2c1e3 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/ingest_pipelines/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 { FtrProviderContext } from '../../../ftr_provider_context'; + +export default function({ loadTestFile }: FtrProviderContext) { + describe('Ingest Node Pipelines', () => { + loadTestFile(require.resolve('./ingest_pipelines')); + }); +} diff --git a/x-pack/test/api_integration/apis/management/ingest_pipelines/ingest_pipelines.ts b/x-pack/test/api_integration/apis/management/ingest_pipelines/ingest_pipelines.ts new file mode 100644 index 0000000000000..88a78d048a3b6 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/ingest_pipelines/ingest_pipelines.ts @@ -0,0 +1,330 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { registerEsHelpers } from './lib'; + +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const API_BASE_PATH = '/api/ingest_pipelines'; + +export default function({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + const { createPipeline, deletePipeline } = registerEsHelpers(getService); + + describe('Pipelines', function() { + describe('Create', () => { + const PIPELINE_ID = 'test_create_pipeline'; + after(() => deletePipeline(PIPELINE_ID)); + + it('should create a pipeline', async () => { + const { body } = await supertest + .post(API_BASE_PATH) + .set('kbn-xsrf', 'xxx') + .send({ + name: PIPELINE_ID, + description: 'test pipeline description', + processors: [ + { + script: { + source: 'ctx._type = null', + }, + }, + ], + on_failure: [ + { + set: { + field: 'error.message', + value: '{{ failure_message }}', + }, + }, + ], + version: 1, + }) + .expect(200); + + expect(body).to.eql({ + acknowledged: true, + }); + }); + + it('should not allow creation of an existing pipeline', async () => { + const { body } = await supertest + .post(API_BASE_PATH) + .set('kbn-xsrf', 'xxx') + .send({ + name: PIPELINE_ID, + description: 'test pipeline description', + processors: [ + { + script: { + source: 'ctx._type = null', + }, + }, + ], + version: 1, + }) + .expect(409); + + expect(body).to.eql({ + statusCode: 409, + error: 'Conflict', + message: `There is already a pipeline with name '${PIPELINE_ID}'.`, + }); + }); + }); + + describe('Update', () => { + const PIPELINE_ID = 'test_update_pipeline'; + const PIPELINE = { + description: 'test pipeline description', + processors: [ + { + script: { + source: 'ctx._type = null', + }, + }, + ], + version: 1, + }; + + before(() => createPipeline({ body: PIPELINE, id: PIPELINE_ID })); + after(() => deletePipeline(PIPELINE_ID)); + + it('should allow an existing pipeline to be updated', async () => { + const uri = `${API_BASE_PATH}/${PIPELINE_ID}`; + + const { body } = await supertest + .put(uri) + .set('kbn-xsrf', 'xxx') + .send({ + ...PIPELINE, + description: 'updated test pipeline description', + }) + .expect(200); + + expect(body).to.eql({ + acknowledged: true, + }); + }); + + it('should not allow a non-existing pipeline to be updated', async () => { + const uri = `${API_BASE_PATH}/pipeline_does_not_exist`; + + const { body } = await supertest + .put(uri) + .set('kbn-xsrf', 'xxx') + .send({ + ...PIPELINE, + description: 'updated test pipeline description', + }) + .expect(404); + + expect(body).to.eql({ + statusCode: 404, + error: 'Not Found', + message: 'Not Found', + }); + }); + }); + + describe('Get', () => { + const PIPELINE_ID = 'test_pipeline'; + const PIPELINE = { + description: 'test pipeline description', + processors: [ + { + script: { + source: 'ctx._type = null', + }, + }, + ], + version: 1, + }; + + before(() => createPipeline({ body: PIPELINE, id: PIPELINE_ID })); + after(() => deletePipeline(PIPELINE_ID)); + + describe('all pipelines', () => { + it('should return an array of pipelines', async () => { + const { body } = await supertest + .get(API_BASE_PATH) + .set('kbn-xsrf', 'xxx') + .expect(200); + + expect(Array.isArray(body)).to.be(true); + + // There are some pipelines created OOTB with ES + // To not be dependent on these, we only confirm the pipeline we created as part of the test exists + const testPipeline = body.find(({ name }: { name: string }) => name === PIPELINE_ID); + + expect(testPipeline).to.eql({ + ...PIPELINE, + name: PIPELINE_ID, + }); + }); + }); + + describe('one pipeline', () => { + it('should return a single pipeline', async () => { + const uri = `${API_BASE_PATH}/${PIPELINE_ID}`; + + const { body } = await supertest + .get(uri) + .set('kbn-xsrf', 'xxx') + .expect(200); + + expect(body).to.eql({ + ...PIPELINE, + name: PIPELINE_ID, + }); + }); + }); + }); + + describe('Delete', () => { + const PIPELINE = { + description: 'test pipeline description', + processors: [ + { + script: { + source: 'ctx._type = null', + }, + }, + ], + version: 1, + }; + + it('should delete a pipeline', async () => { + // Create pipeline to be deleted + const PIPELINE_ID = 'test_delete_pipeline'; + createPipeline({ body: PIPELINE, id: PIPELINE_ID }); + + const uri = `${API_BASE_PATH}/${PIPELINE_ID}`; + + const { body } = await supertest + .delete(uri) + .set('kbn-xsrf', 'xxx') + .expect(200); + + expect(body).to.eql({ + itemsDeleted: [PIPELINE_ID], + errors: [], + }); + }); + + it('should delete multiple pipelines', async () => { + // Create pipelines to be deleted + const PIPELINE_ONE_ID = 'test_delete_pipeline_1'; + const PIPELINE_TWO_ID = 'test_delete_pipeline_2'; + createPipeline({ body: PIPELINE, id: PIPELINE_ONE_ID }); + createPipeline({ body: PIPELINE, id: PIPELINE_TWO_ID }); + + const uri = `${API_BASE_PATH}/${PIPELINE_ONE_ID},${PIPELINE_TWO_ID}`; + + const { + body: { itemsDeleted, errors }, + } = await supertest + .delete(uri) + .set('kbn-xsrf', 'xxx') + .expect(200); + + expect(errors).to.eql([]); + + // The itemsDeleted array order isn't guaranteed, so we assert against each pipeline name instead + [PIPELINE_ONE_ID, PIPELINE_TWO_ID].forEach(pipelineName => { + expect(itemsDeleted.includes(pipelineName)).to.be(true); + }); + }); + + it('should return an error for any pipelines not sucessfully deleted', async () => { + const PIPELINE_DOES_NOT_EXIST = 'pipeline_does_not_exist'; + + // Create pipeline to be deleted + const PIPELINE_ONE_ID = 'test_delete_pipeline_1'; + createPipeline({ body: PIPELINE, id: PIPELINE_ONE_ID }); + + const uri = `${API_BASE_PATH}/${PIPELINE_ONE_ID},${PIPELINE_DOES_NOT_EXIST}`; + + const { body } = await supertest + .delete(uri) + .set('kbn-xsrf', 'xxx') + .expect(200); + + expect(body).to.eql({ + itemsDeleted: [PIPELINE_ONE_ID], + errors: [ + { + name: PIPELINE_DOES_NOT_EXIST, + error: { + msg: '[resource_not_found_exception] pipeline [pipeline_does_not_exist] is missing', + path: '/_ingest/pipeline/pipeline_does_not_exist', + query: {}, + statusCode: 404, + response: JSON.stringify({ + error: { + root_cause: [ + { + type: 'resource_not_found_exception', + reason: 'pipeline [pipeline_does_not_exist] is missing', + }, + ], + type: 'resource_not_found_exception', + reason: 'pipeline [pipeline_does_not_exist] is missing', + }, + status: 404, + }), + }, + }, + ], + }); + }); + }); + + describe('Simulate', () => { + it('should successfully simulate a pipeline', async () => { + const { body } = await supertest + .post(`${API_BASE_PATH}/simulate`) + .set('kbn-xsrf', 'xxx') + .send({ + pipeline: { + description: 'test simulate pipeline description', + processors: [ + { + set: { + field: 'field2', + value: '_value', + }, + }, + ], + }, + documents: [ + { + _index: 'index', + _id: 'id', + _source: { + foo: 'bar', + }, + }, + { + _index: 'index', + _id: 'id', + _source: { + foo: 'rab', + }, + }, + ], + }) + .expect(200); + + // The simulate ES response is quite long and includes timestamps + // so for now, we just confirm the docs array is returned with the correct length + expect(body.docs?.length).to.eql(2); + }); + }); + }); +} diff --git a/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/elasticsearch.ts b/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/elasticsearch.ts new file mode 100644 index 0000000000000..2f42596a66b54 --- /dev/null +++ b/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/elasticsearch.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 { FtrProviderContext } from '../../../../ftr_provider_context'; + +interface Processor { + [key: string]: { + [key: string]: unknown; + }; +} + +interface Pipeline { + id: string; + body: { + description: string; + processors: Processor[]; + version?: number; + }; +} + +/** + * Helpers to create and delete pipelines on the Elasticsearch instance + * during our tests. + * @param {ElasticsearchClient} es The Elasticsearch client instance + */ +export const registerEsHelpers = (getService: FtrProviderContext['getService']) => { + const es = getService('legacyEs'); + + const createPipeline = (pipeline: Pipeline) => es.ingest.putPipeline(pipeline); + + const deletePipeline = (pipelineId: string) => es.ingest.deletePipeline({ id: pipelineId }); + + return { + createPipeline, + deletePipeline, + }; +}; diff --git a/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/index.ts b/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/index.ts new file mode 100644 index 0000000000000..66ea0fe40c4ce --- /dev/null +++ b/x-pack/test/api_integration/apis/management/ingest_pipelines/lib/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 { registerEsHelpers } from './elasticsearch'; diff --git a/x-pack/test/functional/apps/ingest_pipelines/index.ts b/x-pack/test/functional/apps/ingest_pipelines/index.ts new file mode 100644 index 0000000000000..87e7e70c0b5e0 --- /dev/null +++ b/x-pack/test/functional/apps/ingest_pipelines/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. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ loadTestFile }: FtrProviderContext) => { + describe('Ingest pipelines app', function() { + this.tags('ciGroup3'); + loadTestFile(require.resolve('./ingest_pipelines')); + }); +}; diff --git a/x-pack/test/functional/apps/ingest_pipelines/ingest_pipelines.ts b/x-pack/test/functional/apps/ingest_pipelines/ingest_pipelines.ts new file mode 100644 index 0000000000000..1b22f8f35d7ad --- /dev/null +++ b/x-pack/test/functional/apps/ingest_pipelines/ingest_pipelines.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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default ({ getPageObjects, getService }: FtrProviderContext) => { + const pageObjects = getPageObjects(['common', 'ingestPipelines']); + const log = getService('log'); + + describe('Ingest Pipelines', function() { + this.tags('smoke'); + before(async () => { + await pageObjects.common.navigateToApp('ingestPipelines'); + }); + + it('Loads the app', async () => { + await log.debug('Checking for section heading to say Ingest Node Pipelines.'); + + const headingText = await pageObjects.ingestPipelines.sectionHeadingText(); + expect(headingText).to.be('Ingest Node Pipelines'); + }); + }); +}; diff --git a/x-pack/test/functional/config.js b/x-pack/test/functional/config.js index 2c6238704bea0..f6b80b1b9fc67 100644 --- a/x-pack/test/functional/config.js +++ b/x-pack/test/functional/config.js @@ -53,6 +53,7 @@ export default async function({ readConfigFile }) { resolve(__dirname, './apps/index_patterns'), resolve(__dirname, './apps/index_management'), resolve(__dirname, './apps/index_lifecycle_management'), + resolve(__dirname, './apps/ingest_pipelines'), resolve(__dirname, './apps/snapshot_restore'), resolve(__dirname, './apps/cross_cluster_replication'), resolve(__dirname, './apps/remote_clusters'), @@ -175,6 +176,10 @@ export default async function({ readConfigFile }) { pathname: '/app/kibana', hash: '/management/elasticsearch/index_lifecycle_management', }, + ingestPipelines: { + pathname: '/app/kibana', + hash: '/management/elasticsearch/ingest_pipelines', + }, snapshotRestore: { pathname: '/app/kibana', hash: '/management/elasticsearch/snapshot_restore', diff --git a/x-pack/test/functional/page_objects/index.ts b/x-pack/test/functional/page_objects/index.ts index 4b8c2944ef190..833cc452a5d31 100644 --- a/x-pack/test/functional/page_objects/index.ts +++ b/x-pack/test/functional/page_objects/index.ts @@ -45,6 +45,7 @@ import { LensPageProvider } from './lens_page'; import { InfraMetricExplorerProvider } from './infra_metric_explorer'; import { RoleMappingsPageProvider } from './role_mappings_page'; import { SpaceSelectorPageProvider } from './space_selector_page'; +import { IngestPipelinesPageProvider } from './ingest_pipelines_page'; // just like services, PageObjects are defined as a map of // names to Providers. Merge in Kibana's or pick specific ones @@ -78,4 +79,5 @@ export const pageObjects = { copySavedObjectsToSpace: CopySavedObjectsToSpacePageProvider, lens: LensPageProvider, roleMappings: RoleMappingsPageProvider, + ingestPipelines: IngestPipelinesPageProvider, }; diff --git a/x-pack/test/functional/page_objects/ingest_pipelines_page.ts b/x-pack/test/functional/page_objects/ingest_pipelines_page.ts new file mode 100644 index 0000000000000..abc85277a3617 --- /dev/null +++ b/x-pack/test/functional/page_objects/ingest_pipelines_page.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 { FtrProviderContext } from '../ftr_provider_context'; + +export function IngestPipelinesPageProvider({ getService }: FtrProviderContext) { + const testSubjects = getService('testSubjects'); + + return { + async sectionHeadingText() { + return await testSubjects.getVisibleText('appTitle'); + }, + }; +} From 59315bc84d3fbf8bde3b7bebdf0308b1749ed978 Mon Sep 17 00:00:00 2001 From: igoristic Date: Thu, 30 Apr 2020 15:59:35 -0400 Subject: [PATCH 03/10] [Monitoring] NP Migration complete client cutover (#62908) * Final phase before the complete cutover * NP migration * lint fix * More NP stuff * Moved Stack Monitoring client plugin outside legacy and fixed all tests * ... * Removed unused files * Fix for main links * Fixed more tests * Fixed redirect when clicking on SM icon again * Code review feedback * Addressed code review feedback * Fixed return value --- .eslintignore | 1 + .eslintrc.js | 6 + .github/CODEOWNERS | 1 + src/dev/precommit_hook/casing_check_config.js | 12 +- x-pack/legacy/plugins/monitoring/.agignore | 3 - .../__tests__/format_timestamp_to_duration.js | 128 - .../monitoring/common/cancel_promise.ts | 70 - .../plugins/monitoring/common/constants.ts | 268 -- .../common/format_timestamp_to_duration.js | 54 - .../plugins/monitoring/common/formatting.js | 35 - .../monitoring/{config.js => config.ts} | 2 +- x-pack/legacy/plugins/monitoring/index.js | 57 - x-pack/legacy/plugins/monitoring/index.ts | 41 + .../components/chart/chart_target.test.js | 76 - .../public/components/license/index.js | 91 - .../monitoring/public/directives/all.js | 10 - .../monitoring/public/filters/index.js | 30 - .../hacks/__tests__/toggle_app_link_in_nav.js | 9 - .../public/hacks/toggle_app_link_in_nav.js | 16 - .../monitoring/public/icons/monitoring.svg | 16 - .../plugins/monitoring/public/legacy.ts | 27 - .../np_imports/angular/angular_config.ts | 157 - .../public/np_imports/angular/index.ts | 48 - .../public/np_imports/angular/modules.ts | 148 - .../np_imports/angular/providers/promises.js | 116 - .../public/np_imports/legacy_imports.ts | 22 - .../public/np_imports/ui/capabilities.ts | 8 - .../monitoring/public/np_imports/ui/chrome.ts | 33 - .../public/np_imports/ui/modules.ts | 55 - .../public/np_imports/ui/timefilter.ts | 31 - .../monitoring/public/np_ready/plugin.ts | 28 - .../monitoring/public/register_feature.ts | 30 - .../monitoring/public/services/breadcrumbs.js | 10 - .../monitoring/public/services/executor.js | 10 - .../public/views/kibana/instance/index.js | 153 - .../public/views/loading/index.html | 5 - .../monitoring/public/views/loading/index.js | 51 - .../legacy/plugins/monitoring/ui_exports.js | 65 - .../server/routes/api/v1/settings.js | 2 +- x-pack/plugins/monitoring/kibana.json | 6 +- .../plugins/monitoring/public/_hacks.scss | 0 .../monitoring/public/angular/app_modules.ts | 248 ++ .../public/angular/helpers}/routes.ts | 19 +- .../public/angular/helpers}/utils.ts | 0 .../monitoring/public/angular/index.ts | 68 + .../public}/angular/providers/private.js | 2 + .../public/angular/providers/url.js | 217 ++ .../alerts/__snapshots__/status.test.tsx.snap | 0 .../alerts/__tests__/map_severity.js | 0 .../public/components/alerts/alerts.js | 8 +- .../__snapshots__/configuration.test.tsx.snap | 0 .../__snapshots__/step1.test.tsx.snap | 0 .../__snapshots__/step2.test.tsx.snap | 0 .../__snapshots__/step3.test.tsx.snap | 0 .../configuration/configuration.test.tsx | 16 +- .../alerts/configuration/configuration.tsx | 8 +- .../components/alerts/configuration/index.ts | 0 .../alerts/configuration/step1.test.tsx | 84 +- .../components/alerts/configuration/step1.tsx | 12 +- .../alerts/configuration/step2.test.tsx | 0 .../components/alerts/configuration/step2.tsx | 0 .../alerts/configuration/step3.test.tsx | 0 .../components/alerts/configuration/step3.tsx | 0 .../components/alerts/formatted_alert.js | 0 .../public/components/alerts/index.js | 0 .../components/alerts/manage_email_action.tsx | 2 +- .../public/components/alerts/map_severity.js | 0 .../public/components/alerts/status.test.tsx | 18 +- .../public/components/alerts/status.tsx | 16 +- .../public/components/apm/instance/index.js | 0 .../components/apm/instance/instance.js | 0 .../public/components/apm/instance/status.js | 0 .../public/components/apm/instances/index.js | 0 .../components/apm/instances/instances.js | 0 .../public/components/apm/instances/status.js | 0 .../public/components/apm/overview/index.js | 0 .../public/components/apm/status_icon.js | 2 +- .../public/components/beats/beat/beat.js | 0 .../public/components/beats/beat/index.js | 0 .../public/components/beats/index.js | 0 .../public/components/beats/listing/index.js | 0 .../components/beats/listing/listing.js | 6 +- .../__snapshots__/latest_active.test.js.snap | 0 .../__snapshots__/latest_types.test.js.snap | 0 .../latest_versions.test.js.snap | 0 .../__snapshots__/overview.test.js.snap | 0 .../public/components/beats/overview/index.js | 0 .../beats/overview/latest_active.js | 0 .../beats/overview/latest_active.test.js | 0 .../components/beats/overview/latest_types.js | 0 .../beats/overview/latest_types.test.js | 0 .../beats/overview/latest_versions.js | 0 .../beats/overview/latest_versions.test.js | 0 .../components/beats/overview/overview.js | 0 .../beats/overview/overview.test.js | 8 +- .../public/components/beats/stats.js | 2 +- .../components/chart/__tests__/get_color.js | 0 .../chart/__tests__/get_last_value.js | 0 .../components/chart/__tests__/get_title.js | 0 .../chart/__tests__/get_values_for_legend.js | 0 .../public/components/chart/_chart.scss | 0 .../public/components/chart/_index.scss | 0 .../public/components/chart/chart_target.js | 2 +- .../public/components/chart/event_bus.js | 0 .../components/chart/get_chart_options.js | 4 +- .../public/components/chart/get_color.js | 0 .../public/components/chart/get_last_value.js | 0 .../public/components/chart/get_title.js | 0 .../public/components/chart/get_units.js | 0 .../components/chart/get_values_for_legend.js | 0 .../components/chart/horizontal_legend.js | 0 .../public/components/chart/index.js | 0 .../public/components/chart/info_tooltip.js | 0 .../components/chart/monitoring_timeseries.js | 0 .../chart/monitoring_timeseries_container.js | 0 .../components/chart/timeseries_container.js | 0 .../chart/timeseries_visualization.js | 0 .../cluster/listing/alerts_indicator.js | 2 +- .../components/cluster/listing/index.js | 0 .../components/cluster/listing/listing.js | 19 +- .../__snapshots__/helpers.test.js.snap | 0 .../overview/__tests__/helpers.test.js | 2 +- .../cluster/overview/alerts_panel.js | 4 +- .../components/cluster/overview/apm_panel.js | 2 +- .../cluster/overview/beats_panel.js | 2 +- .../cluster/overview/elasticsearch_panel.js | 2 +- .../components/cluster/overview/helpers.js | 0 .../components/cluster/overview/index.js | 0 .../cluster/overview/kibana_panel.js | 2 +- .../cluster/overview/license_text.js | 0 .../cluster/overview/logstash_panel.js | 2 +- .../public/components/cluster/status_icon.js | 0 .../ccr/__snapshots__/ccr.test.js.snap | 0 .../components/elasticsearch/ccr/ccr.js | 3 +- .../components/elasticsearch/ccr/ccr.test.js | 0 .../components/elasticsearch/ccr/index.js | 0 .../components/elasticsearch/ccr/index.scss} | 0 .../__snapshots__/ccr_shard.test.js.snap | 0 .../elasticsearch/ccr_shard/ccr_shard.js | 4 +- .../elasticsearch/ccr_shard/ccr_shard.test.js | 11 +- .../elasticsearch/ccr_shard/index.js | 0 .../elasticsearch/ccr_shard/status.js | 0 .../elasticsearch/cluster_status/index.js | 0 .../public/components/elasticsearch/index.js | 0 .../elasticsearch/index/advanced.js | 0 .../components/elasticsearch/index/index.js | 0 .../index_detail_status/index.js | 0 .../components/elasticsearch/indices/index.js | 0 .../elasticsearch/indices/indices.js | 0 .../ml_job_listing/status_icon.js | 2 +- .../components/elasticsearch/node/advanced.js | 0 .../components/elasticsearch/node/index.js | 0 .../components/elasticsearch/node/node.js | 0 .../elasticsearch/node/status_icon.js | 0 .../elasticsearch/node_detail_status/index.js | 0 .../__snapshots__/cells.test.js.snap | 0 .../nodes/__tests__/cells.test.js | 2 +- .../components/elasticsearch/nodes/cells.js | 0 .../components/elasticsearch/nodes/index.js | 0 .../components/elasticsearch/nodes/nodes.js | 0 .../elasticsearch/overview/index.js | 0 .../elasticsearch/overview/overview.js | 0 .../elasticsearch/shard_activity/index.js | 0 .../shard_activity/parse_props.js | 6 +- .../elasticsearch/shard_activity/progress.js | 0 .../shard_activity/recovery_index.js | 0 .../shard_activity/shard_activity.js | 2 +- .../elasticsearch/shard_activity/snapshot.js | 0 .../shard_activity/source_destination.js | 0 .../shard_activity/source_tooltip.js | 0 .../shard_activity/total_time.js | 0 .../shard_allocation/_index.scss | 0 .../shard_allocation/_shard_allocation.scss | 0 .../__snapshots__/shard.test.js.snap | 0 .../shard_allocation/components/assigned.js | 0 .../components/cluster_view.js | 0 .../shard_allocation/components/shard.js | 0 .../shard_allocation/components/shard.test.js | 0 .../shard_allocation/components/table_body.js | 0 .../shard_allocation/components/table_head.js | 0 .../shard_allocation/components/unassigned.js | 0 .../elasticsearch/shard_allocation/index.js | 0 .../shard_allocation/lib/calculate_class.js | 0 .../shard_allocation/lib/decorate_shards.js | 0 .../lib/decorate_shards.test.js | 0 .../lib/generate_query_and_link.js | 0 .../lib/has_primary_children.js | 0 .../shard_allocation/lib/has_unassigned.js | 0 .../shard_allocation/lib/labels.js | 0 .../shard_allocation/lib/vents.js | 0 .../shard_allocation/shard_allocation.js | 0 .../transformers/indices_by_nodes.js | 0 .../transformers/nodes_by_indices.js | 0 .../components/elasticsearch/status_icon.js | 0 .../monitoring/public/components/index.js | 0 .../components/kibana/cluster_status/index.js | 0 .../components/kibana/detail_status/index.js | 0 .../components/kibana/instances/index.js | 0 .../components/kibana/instances/instances.js | 2 +- .../public/components/kibana/status_icon.js | 2 +- .../public/components/license/index.js | 201 ++ .../logs/__snapshots__/logs.test.js.snap | 0 .../logs/__snapshots__/reason.test.js.snap | 0 .../public/components/logs/index.js | 0 .../monitoring/public/components/logs/logs.js | 9 +- .../public/components/logs/logs.test.js | 23 +- .../public/components/logs/reason.js | 3 +- .../public/components/logs/reason.test.js | 12 +- .../logstash/cluster_status/index.js | 0 .../logstash/detail_status/index.js | 0 .../__snapshots__/listing.test.js.snap | 0 .../components/logstash/listing/index.js | 0 .../components/logstash/listing/listing.js | 0 .../logstash/listing/listing.test.js | 0 .../components/logstash/overview/index.js | 0 .../components/logstash/overview/overview.js | 0 .../logstash/pipeline_listing/index.js | 0 .../pipeline_listing/pipeline_listing.js | 2 +- .../logstash/pipeline_viewer/index.js | 0 .../models/__tests__/config.js | 0 .../models/__tests__/pipeline_state.js | 0 .../logstash/pipeline_viewer/models/config.js | 0 .../models/graph/__tests__/boolean_edge.js | 0 .../models/graph/__tests__/edge.js | 0 .../models/graph/__tests__/edge_factory.js | 0 .../models/graph/__tests__/if_vertex.js | 0 .../models/graph/__tests__/index.js | 0 .../models/graph/__tests__/plugin_vertex.js | 0 .../models/graph/__tests__/queue_vertex.js | 0 .../models/graph/__tests__/vertex.js | 0 .../models/graph/__tests__/vertex_factory.js | 0 .../models/graph/boolean_edge.js | 0 .../pipeline_viewer/models/graph/edge.js | 0 .../models/graph/edge_factory.js | 0 .../pipeline_viewer/models/graph/if_vertex.js | 0 .../pipeline_viewer/models/graph/index.js | 0 .../models/graph/plugin_vertex.js | 0 .../models/graph/queue_vertex.js | 0 .../pipeline_viewer/models/graph/vertex.js | 0 .../models/graph/vertex_factory.js | 0 .../pipeline_viewer/models/list/element.js | 0 .../models/list/else_element.js | 0 .../models/list/else_element.test.js | 0 .../models/list/flatten_pipeline_section.js | 0 .../list/flatten_pipeline_section.test.js | 0 .../pipeline_viewer/models/list/if_element.js | 0 .../models/list/if_element.test.js | 0 .../pipeline_viewer/models/list/index.js | 0 .../pipeline_viewer/models/list/list.js | 0 .../pipeline_viewer/models/list/list.test.js | 0 .../models/list/plugin_element.js | 0 .../models/list/plugin_element.test.js | 0 .../models/pipeline/__tests__/if_statement.js | 0 .../pipeline/__tests__/make_statement.js | 0 .../models/pipeline/__tests__/pipeline.js | 0 .../pipeline/__tests__/plugin_statement.js | 0 .../models/pipeline/__tests__/queue.js | 0 .../models/pipeline/__tests__/statement.js | 0 .../models/pipeline/__tests__/utils.js | 0 .../models/pipeline/if_statement.js | 0 .../pipeline_viewer/models/pipeline/index.js | 0 .../models/pipeline/make_statement.js | 0 .../models/pipeline/pipeline.js | 0 .../models/pipeline/plugin_statement.js | 0 .../pipeline_viewer/models/pipeline/queue.js | 0 .../models/pipeline/statement.js | 0 .../pipeline_viewer/models/pipeline/utils.js | 0 .../pipeline_viewer/models/pipeline_state.js | 0 .../collapsible_statement.test.js.snap | 0 .../__snapshots__/detail_drawer.test.js.snap | 0 .../__snapshots__/metric.test.js.snap | 0 .../pipeline_viewer.test.js.snap | 0 .../plugin_statement.test.js.snap | 0 .../__test__/__snapshots__/queue.test.js.snap | 0 .../__snapshots__/statement.test.js.snap | 0 .../__snapshots__/statement_list.test.js.snap | 0 .../statement_list_heading.test.js.snap | 0 .../statement_section.test.js.snap | 0 .../__test__/collapsible_statement.test.js | 0 .../views/__test__/detail_drawer.test.js | 4 + .../views/__test__/metric.test.js | 0 .../views/__test__/pipeline_viewer.test.js | 4 + .../views/__test__/plugin_statement.test.js | 0 .../views/__test__/queue.test.js | 0 .../views/__test__/statement.test.js | 0 .../views/__test__/statement_list.test.js | 0 .../__test__/statement_list_heading.test.js | 0 .../views/__test__/statement_section.test.js | 0 .../pipeline_viewer/views/_index.scss | 0 .../views/_pipeline_viewer.scss | 0 .../views/collapsible_statement.js | 0 .../pipeline_viewer/views/detail_drawer.js | 0 .../logstash/pipeline_viewer/views/index.js | 0 .../logstash/pipeline_viewer/views/metric.js | 0 .../pipeline_viewer/views/pipeline_viewer.js | 0 .../pipeline_viewer/views/plugin_statement.js | 0 .../logstash/pipeline_viewer/views/queue.js | 0 .../pipeline_viewer/views/statement.js | 0 .../pipeline_viewer/views/statement_list.js | 0 .../views/statement_list_heading.js | 0 .../views/statement_section.js | 0 .../metricbeat_migration/constants.js | 0 .../flyout/__snapshots__/flyout.test.js.snap | 0 .../metricbeat_migration/flyout/flyout.js | 5 +- .../flyout/flyout.test.js | 13 +- .../metricbeat_migration/flyout/index.js | 0 ...isable_internal_collection_instructions.js | 0 .../apm/enable_metricbeat_instructions.js | 3 +- .../instruction_steps/apm/index.js | 0 .../beats/common_beats_instructions.js | 0 ...isable_internal_collection_instructions.js | 0 .../beats/enable_metricbeat_instructions.js | 3 +- .../instruction_steps/beats/index.js | 0 .../instruction_steps/common_instructions.js | 0 .../components/monospace/index.js | 0 .../components/monospace/monospace.js | 0 ...isable_internal_collection_instructions.js | 0 .../enable_metricbeat_instructions.js | 3 +- .../instruction_steps/elasticsearch/index.js | 0 .../get_instruction_steps.js | 0 .../instruction_steps/index.js | 0 ...isable_internal_collection_instructions.js | 0 .../kibana/enable_metricbeat_instructions.js | 3 +- .../instruction_steps/kibana/index.js | 0 ...isable_internal_collection_instructions.js | 0 .../enable_metricbeat_instructions.js | 3 +- .../instruction_steps/logstash/index.js | 0 .../__snapshots__/checker_errors.test.js.snap | 0 .../__snapshots__/no_data.test.js.snap | 0 .../no_data/__tests__/checker_errors.test.js | 2 +- .../no_data/__tests__/no_data.test.js | 8 +- .../public/components/no_data/_index.scss | 0 .../public/components/no_data/_no_data.scss | 0 .../no_data/blurbs/changes_needed.js | 0 .../no_data/blurbs/cloud_deployment.js | 0 .../public/components/no_data/blurbs/index.js | 0 .../components/no_data/blurbs/looking_for.js | 0 .../components/no_data/blurbs/what_is.js | 0 .../components/no_data/checker_errors.js | 0 .../components/no_data/checking_settings.js | 0 .../collection_enabled.test.js.snap | 0 .../__tests__/collection_enabled.test.js | 2 +- .../collection_enabled/collection_enabled.js | 0 .../collection_interval.test.js.snap | 0 .../__tests__/collection_interval.test.js | 2 +- .../collection_interval.js | 0 .../__snapshots__/exporters.test.js.snap | 0 .../exporters/__tests__/exporters.test.js | 2 +- .../explanations/exporters/exporters.js | 0 .../components/no_data/explanations/index.js | 0 .../__snapshots__/plugin_enabled.test.js.snap | 0 .../__tests__/plugin_enabled.test.js | 2 +- .../plugin_enabled/plugin_enabled.js | 0 .../public/components/no_data/index.js | 0 .../public/components/no_data/no_data.js | 0 .../__snapshots__/reason_found.test.js.snap | 0 .../__snapshots__/we_tried.test.js.snap | 0 .../reasons/__tests__/reason_found.test.js | 2 +- .../reasons/__tests__/we_tried.test.js | 2 +- .../components/no_data/reasons/index.js | 0 .../no_data/reasons/reason_found.js | 0 .../components/no_data/reasons/we_tried.js | 0 .../__snapshots__/page_loading.test.js.snap | 0 .../__tests__/page_loading.test.js | 2 +- .../public/components/page_loading/index.js | 0 .../__snapshots__/setup_mode.test.js.snap | 0 .../public/components/renderers/index.js | 0 .../components/renderers/lib/find_new_uuid.js | 0 .../public/components/renderers/setup_mode.js | 0 .../components/renderers/setup_mode.test.js | 0 .../__snapshots__/badge.test.js.snap | 0 .../__snapshots__/enter_button.test.tsx.snap | 0 .../__snapshots__/formatting.test.js.snap | 0 .../listing_callout.test.js.snap | 0 .../__snapshots__/tooltip.test.js.snap | 0 .../components/setup_mode/_enter_button.scss | 0 .../public/components/setup_mode/_index.scss | 0 .../public/components/setup_mode/badge.js | 0 .../components/setup_mode/badge.test.js | 0 .../setup_mode/enter_button.test.tsx | 0 .../components/setup_mode/enter_button.tsx | 0 .../components/setup_mode/formatting.js | 0 .../components/setup_mode/formatting.test.js | 0 .../components/setup_mode/listing_callout.js | 0 .../setup_mode/listing_callout.test.js | 0 .../public/components/setup_mode/tooltip.js | 0 .../components/setup_mode/tooltip.test.js | 0 .../plugins/xpack_main/jquery_flot.js | 0 .../__test__/__snapshots__/index.test.js.snap | 0 .../sparkline/__test__/index.test.js | 4 + .../public/components/sparkline/_index.scss | 0 .../components/sparkline/_sparkline.scss | 0 .../public/components/sparkline/index.js | 0 .../sparkline/sparkline_flot_chart.js | 2 +- .../public/components/status_icon/_index.scss | 0 .../components/status_icon/_status_icon.scss | 0 .../public/components/status_icon/index.js | 0 .../__snapshots__/summary_status.test.js.snap | 0 .../components/summary_status/_index.scss | 0 .../summary_status/_summary_status.scss | 0 .../public/components/summary_status/index.js | 0 .../summary_status/summary_status.js | 0 .../summary_status/summary_status.test.js | 2 +- .../public/components/table/_index.scss | 0 .../public/components/table/_table.scss | 0 .../public/components/table/eui_table.js | 0 .../public/components/table/eui_table_ssp.js | 0 .../public/components/table/index.js | 0 .../public/components/table/storage.js | 0 .../public/directives/beats/beat}/index.js | 19 +- .../directives/beats/overview}/index.js | 18 +- .../elasticsearch/ml_job_listing/index.js | 94 +- .../__tests__/monitoring_main_controller.js | 0 .../public/directives/main/index.html | 0 .../public/directives/main/index.js | 25 +- .../monitoring/public/icons/health-gray.svg | 0 .../monitoring/public/icons/health-green.svg | 0 .../monitoring/public/icons/health-red.svg | 0 .../monitoring/public/icons/health-yellow.svg | 0 .../plugins/monitoring/public/index.scss | 7 + .../monitoring/public}/index.ts | 2 +- .../plugins/monitoring/public/jest.helpers.ts | 9 - .../plugins/monitoring/public/legacy_shims.ts | 83 + .../public/lib/__tests__/format_number.js | 0 .../public/lib/ajax_error_handler.tsx | 11 +- .../public/lib/calculate_shard_stats.js | 0 .../__tests__/enabler.test.js | 0 .../__tests__/settings_checker.test.js | 0 .../__tests__/start_checks.test.js | 0 .../checkers/cluster_settings.js | 0 .../checkers/node_settings.js | 0 .../checkers/settings_checker.js | 0 .../lib/elasticsearch_settings/enabler.js | 0 .../lib/elasticsearch_settings/index.js | 0 .../elasticsearch_settings/start_checks.js | 0 .../public/lib/ensure_minimum_time.js | 0 .../public/lib/ensure_minimum_time.test.js | 0 .../monitoring/public/lib/extract_ip.js | 0 .../monitoring/public/lib/form_validation.ts | 0 .../monitoring/public/lib/format_number.js | 0 .../public/lib/get_cluster_from_clusters.js | 0 .../monitoring/public/lib/get_page_data.js | 4 +- .../public/lib/get_safe_for_external_link.ts | 0 .../public/lib/jquery_flot/flot-charts/API.md | 1498 ++++++++ .../lib/jquery_flot/flot-charts/index.js | 48 + .../flot-charts/jquery.colorhelpers.js | 180 + .../flot-charts/jquery.flot.canvas.js | 345 ++ .../flot-charts/jquery.flot.categories.js | 190 + .../flot-charts/jquery.flot.crosshair.js | 176 + .../flot-charts/jquery.flot.errorbars.js | 353 ++ .../flot-charts/jquery.flot.fillbetween.js | 226 ++ .../flot-charts/jquery.flot.image.js | 241 ++ .../jquery_flot/flot-charts/jquery.flot.js | 3168 +++++++++++++++++ .../flot-charts/jquery.flot.log.js | 163 + .../flot-charts/jquery.flot.navigate.js | 346 ++ .../flot-charts/jquery.flot.pie.js | 824 +++++ .../flot-charts/jquery.flot.resize.js | 59 + .../flot-charts/jquery.flot.selection.js | 360 ++ .../flot-charts/jquery.flot.stack.js | 188 + .../flot-charts/jquery.flot.symbol.js | 71 + .../flot-charts/jquery.flot.threshold.js | 142 + .../flot-charts/jquery.flot.time.js | 473 +++ .../public/lib/jquery_flot}/index.js | 2 +- .../public/lib/jquery_flot/jquery_flot.js | 19 + .../lib/logstash/__tests__/pipelines.js | 0 .../public/lib/logstash/pipelines.js | 0 .../monitoring/public/lib/route_init.js | 2 +- .../monitoring/public/lib/setup_mode.test.js | 112 +- .../monitoring/public/lib/setup_mode.tsx | 39 +- x-pack/plugins/monitoring/public/plugin.ts | 147 + .../public/services/__tests__/breadcrumbs.js | 4 +- .../public/services/__tests__/executor.js} | 12 +- .../public/services/breadcrumbs.js} | 4 +- .../monitoring/public/services/clusters.js | 12 +- .../monitoring/public/services/executor.js} | 55 +- .../monitoring/public/services/features.js | 6 +- .../monitoring/public/services/license.js | 6 +- .../monitoring/public/services/title.js | 23 +- x-pack/plugins/monitoring/public/types.ts | 21 + x-pack/plugins/monitoring/public/url_state.ts | 169 + .../public/views/__tests__/base_controller.js | 7 +- .../views/__tests__/base_table_controller.js | 0 .../public/views/access_denied/index.html | 0 .../public/views/access_denied/index.js | 6 +- .../monitoring/public/views/alerts/index.html | 0 .../monitoring/public/views/alerts/index.js | 41 +- .../plugins/monitoring/public/views/all.js | 1 - .../public/views/apm/instance/index.html | 0 .../public/views/apm/instance/index.js | 19 +- .../public/views/apm/instances/index.html | 0 .../public/views/apm/instances/index.js | 47 +- .../public/views/apm/overview/index.html | 0 .../public/views/apm/overview/index.js | 11 +- .../public/views/base_controller.js | 100 +- .../public/views/base_eui_table_controller.js | 2 +- .../public/views/base_table_controller.js | 2 +- .../public/views/beats/beat/get_page_data.js | 6 +- .../public/views/beats/beat/index.html | 0 .../public/views/beats/beat/index.js | 4 +- .../views/beats/listing/get_page_data.js | 6 +- .../public/views/beats/listing/index.html | 0 .../public/views/beats/listing/index.js | 53 +- .../views/beats/overview/get_page_data.js | 6 +- .../public/views/beats/overview/index.html | 0 .../public/views/beats/overview/index.js | 4 +- .../public/views/cluster/listing/index.html | 0 .../public/views/cluster/listing/index.js | 35 +- .../public/views/cluster/overview/index.html | 0 .../public/views/cluster/overview/index.js | 47 +- .../views/elasticsearch/ccr/get_page_data.js | 6 +- .../public/views/elasticsearch/ccr/index.html | 0 .../public/views/elasticsearch/ccr/index.js | 11 +- .../elasticsearch/ccr/shard/get_page_data.js | 6 +- .../views/elasticsearch/ccr/shard/index.html | 0 .../views/elasticsearch/ccr/shard/index.js | 11 +- .../elasticsearch/index/advanced/index.html | 0 .../elasticsearch/index/advanced/index.js | 25 +- .../views/elasticsearch/index/index.html | 0 .../public/views/elasticsearch/index/index.js | 31 +- .../views/elasticsearch/indices/index.html | 0 .../views/elasticsearch/indices/index.js | 25 +- .../elasticsearch/ml_jobs/get_page_data.js | 6 +- .../views/elasticsearch/ml_jobs/index.html | 0 .../views/elasticsearch/ml_jobs/index.js | 4 +- .../elasticsearch/node/advanced/index.html | 0 .../elasticsearch/node/advanced/index.js | 25 +- .../views/elasticsearch/node/get_page_data.js | 6 +- .../views/elasticsearch/node/index.html | 0 .../public/views/elasticsearch/node/index.js | 25 +- .../views/elasticsearch/nodes/index.html | 0 .../public/views/elasticsearch/nodes/index.js | 49 +- .../elasticsearch/overview/controller.js | 27 +- .../views/elasticsearch/overview/index.html | 0 .../views/elasticsearch/overview/index.js | 4 +- .../plugins/monitoring/public/views/index.js | 0 .../public/views/kibana/instance/index.html | 0 .../public/views/kibana/instance/index.js | 150 + .../views/kibana/instances/get_page_data.js | 6 +- .../public/views/kibana/instances/index.html | 0 .../public/views/kibana/instances/index.js | 55 +- .../public/views/kibana/overview/index.html | 0 .../public/views/kibana/overview/index.js | 65 +- .../public/views/license/controller.js | 34 +- .../public/views/license/index.html | 0 .../monitoring/public/views/license/index.js | 4 +- .../views/logstash/node/advanced/index.html | 0 .../views/logstash/node/advanced/index.js | 61 +- .../public/views/logstash/node/index.html | 0 .../public/views/logstash/node/index.js | 61 +- .../views/logstash/node/pipelines/index.html | 0 .../views/logstash/node/pipelines/index.js | 45 +- .../views/logstash/nodes/get_page_data.js | 6 +- .../public/views/logstash/nodes/index.html | 0 .../public/views/logstash/nodes/index.js | 47 +- .../public/views/logstash/overview/index.html | 0 .../public/views/logstash/overview/index.js | 25 +- .../public/views/logstash/pipeline/index.html | 0 .../public/views/logstash/pipeline/index.js | 47 +- .../views/logstash/pipelines/index.html | 0 .../public/views/logstash/pipelines/index.js | 41 +- .../no_data/__tests__/model_updater.test.js | 0 .../public/views/no_data/controller.js | 25 +- .../public/views/no_data/index.html | 0 .../monitoring/public/views/no_data/index.js | 12 +- .../public/views/no_data/model_updater.js | 0 x-pack/plugins/monitoring/server/index.ts | 6 + .../spaces_usage_collector.ts | 2 +- .../translations/translations/ja-JP.json | 2 - .../translations/translations/zh-CN.json | 2 - 569 files changed, 11410 insertions(+), 2967 deletions(-) delete mode 100644 x-pack/legacy/plugins/monitoring/.agignore delete mode 100644 x-pack/legacy/plugins/monitoring/common/__tests__/format_timestamp_to_duration.js delete mode 100644 x-pack/legacy/plugins/monitoring/common/cancel_promise.ts delete mode 100644 x-pack/legacy/plugins/monitoring/common/constants.ts delete mode 100644 x-pack/legacy/plugins/monitoring/common/format_timestamp_to_duration.js delete mode 100644 x-pack/legacy/plugins/monitoring/common/formatting.js rename x-pack/legacy/plugins/monitoring/{config.js => config.ts} (99%) delete mode 100644 x-pack/legacy/plugins/monitoring/index.js create mode 100644 x-pack/legacy/plugins/monitoring/index.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/components/chart/chart_target.test.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/components/license/index.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/directives/all.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/filters/index.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/hacks/__tests__/toggle_app_link_in_nav.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/hacks/toggle_app_link_in_nav.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/icons/monitoring.svg delete mode 100644 x-pack/legacy/plugins/monitoring/public/legacy.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/angular/angular_config.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/angular/index.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/angular/providers/promises.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/ui/capabilities.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/ui/chrome.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/ui/modules.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_imports/ui/timefilter.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/np_ready/plugin.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/register_feature.ts delete mode 100644 x-pack/legacy/plugins/monitoring/public/services/breadcrumbs.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/services/executor.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/views/kibana/instance/index.js delete mode 100644 x-pack/legacy/plugins/monitoring/public/views/loading/index.html delete mode 100644 x-pack/legacy/plugins/monitoring/public/views/loading/index.js delete mode 100644 x-pack/legacy/plugins/monitoring/ui_exports.js rename x-pack/{legacy => }/plugins/monitoring/public/_hacks.scss (100%) create mode 100644 x-pack/plugins/monitoring/public/angular/app_modules.ts rename x-pack/{legacy/plugins/monitoring/public/np_imports/ui => plugins/monitoring/public/angular/helpers}/routes.ts (62%) rename x-pack/{legacy/plugins/monitoring/public/np_imports/ui => plugins/monitoring/public/angular/helpers}/utils.ts (100%) create mode 100644 x-pack/plugins/monitoring/public/angular/index.ts rename x-pack/{legacy/plugins/monitoring/public/np_imports => plugins/monitoring/public}/angular/providers/private.js (99%) create mode 100644 x-pack/plugins/monitoring/public/angular/providers/url.js rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/__snapshots__/status.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/__tests__/map_severity.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/alerts.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/__snapshots__/configuration.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step1.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step2.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step3.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/configuration.test.tsx (91%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/configuration.tsx (96%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/index.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/step1.test.tsx (83%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/step1.tsx (97%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/step2.test.tsx (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/step2.tsx (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/step3.test.tsx (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/configuration/step3.tsx (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/formatted_alert.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/manage_email_action.tsx (99%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/map_severity.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/status.test.tsx (83%) rename x-pack/{legacy => }/plugins/monitoring/public/components/alerts/status.tsx (93%) rename x-pack/{legacy => }/plugins/monitoring/public/components/apm/instance/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/apm/instance/instance.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/apm/instance/status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/apm/instances/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/apm/instances/instances.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/apm/instances/status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/apm/overview/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/apm/status_icon.js (91%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/beat/beat.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/beat/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/listing/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/listing/listing.js (96%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_active.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_types.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_versions.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/latest_active.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/latest_active.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/latest_types.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/latest_types.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/latest_versions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/latest_versions.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/overview.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/overview/overview.test.js (93%) rename x-pack/{legacy => }/plugins/monitoring/public/components/beats/stats.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/__tests__/get_color.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/__tests__/get_last_value.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/__tests__/get_title.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/__tests__/get_values_for_legend.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/_chart.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/chart_target.js (99%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/event_bus.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/get_chart_options.js (92%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/get_color.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/get_last_value.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/get_title.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/get_units.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/get_values_for_legend.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/horizontal_legend.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/info_tooltip.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/monitoring_timeseries.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/monitoring_timeseries_container.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/timeseries_container.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/chart/timeseries_visualization.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/listing/alerts_indicator.js (97%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/listing/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/listing/listing.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/__tests__/__snapshots__/helpers.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/__tests__/helpers.test.js (93%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/alerts_panel.js (97%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/apm_panel.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/beats_panel.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/elasticsearch_panel.js (99%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/helpers.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/kibana_panel.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/license_text.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/overview/logstash_panel.js (99%) rename x-pack/{legacy => }/plugins/monitoring/public/components/cluster/status_icon.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr/__snapshots__/ccr.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr/ccr.js (99%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr/ccr.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr/index.js (100%) rename x-pack/{legacy/plugins/monitoring/public/components/elasticsearch/ccr/ccr.css => plugins/monitoring/public/components/elasticsearch/ccr/index.scss} (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.js (97%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.test.js (88%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr_shard/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/index/advanced.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/index/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/indices/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/indices/indices.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.js (93%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/node/advanced.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/node/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/node/node.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/node/status_icon.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/cells.test.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/nodes/cells.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/nodes/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/overview/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/overview/overview.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js (92%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/progress.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/snapshot.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/source_destination.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/source_tooltip.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_activity/total_time.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/_shard_allocation.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/__snapshots__/shard.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_body.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_head.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/unassigned.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/calculate_class.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/generate_query_and_link.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_primary_children.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_unassigned.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/labels.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/shard_allocation.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/indices_by_nodes.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/elasticsearch/status_icon.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/kibana/cluster_status/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/kibana/detail_status/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/kibana/instances/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/kibana/instances/instances.js (99%) rename x-pack/{legacy => }/plugins/monitoring/public/components/kibana/status_icon.js (91%) create mode 100644 x-pack/plugins/monitoring/public/components/license/index.js rename x-pack/{legacy => }/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logs/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logs/logs.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logs/logs.test.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logs/reason.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logs/reason.test.js (93%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/cluster_status/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/detail_status/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/listing/__snapshots__/listing.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/listing/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/listing/listing.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/listing/listing.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/overview/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/overview/overview.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_listing/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/config.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/plugin_vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/plugin_vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/queue_vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/element.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/if_statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/make_statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/pipeline.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/plugin_statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/queue.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/utils.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/if_statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/make_statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/pipeline.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/plugin_statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/queue.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/utils.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline_state.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/collapsible_statement.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/detail_drawer.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/metric.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/pipeline_viewer.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/plugin_statement.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/queue.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list_heading.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_section.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/collapsible_statement.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/metric.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js (94%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/plugin_statement.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/queue.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list_heading.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_section.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_pipeline_viewer.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/detail_drawer.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/metric.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/pipeline_viewer.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list_heading.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/constants.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.test.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/flyout/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/disable_internal_collection_instructions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/enable_metricbeat_instructions.js (97%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/common_beats_instructions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/disable_internal_collection_instructions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/enable_metricbeat_instructions.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/common_instructions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/monospace.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/disable_internal_collection_instructions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/enable_metricbeat_instructions.js (97%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/get_instruction_steps.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/enable_metricbeat_instructions.js (97%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/disable_internal_collection_instructions.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/enable_metricbeat_instructions.js (97%) rename x-pack/{legacy => }/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/checker_errors.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/__tests__/checker_errors.test.js (92%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/__tests__/no_data.test.js (84%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/_no_data.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/blurbs/changes_needed.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/blurbs/cloud_deployment.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/blurbs/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/blurbs/looking_for.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/blurbs/what_is.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/checker_errors.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/checking_settings.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/collection_enabled.test.js (93%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/collection_interval.test.js (96%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/collection_interval/collection_interval.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js (93%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js (92%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/no_data.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/we_tried.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js (96%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/reasons/__tests__/we_tried.test.js (85%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/reasons/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/reasons/reason_found.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/no_data/reasons/we_tried.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/page_loading/__tests__/page_loading.test.js (85%) rename x-pack/{legacy => }/plugins/monitoring/public/components/page_loading/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/renderers/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/renderers/lib/find_new_uuid.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/renderers/setup_mode.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/renderers/setup_mode.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/__snapshots__/badge.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/__snapshots__/enter_button.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/__snapshots__/formatting.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/__snapshots__/listing_callout.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/__snapshots__/tooltip.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/_enter_button.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/badge.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/badge.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/enter_button.test.tsx (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/enter_button.tsx (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/formatting.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/formatting.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/listing_callout.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/listing_callout.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/tooltip.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/setup_mode/tooltip.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/sparkline/__mocks__/plugins/xpack_main/jquery_flot.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/sparkline/__test__/__snapshots__/index.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/sparkline/__test__/index.test.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/sparkline/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/sparkline/_sparkline.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/sparkline/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/sparkline/sparkline_flot_chart.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/components/status_icon/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/status_icon/_status_icon.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/status_icon/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/summary_status/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/summary_status/_summary_status.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/summary_status/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/summary_status/summary_status.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/summary_status/summary_status.test.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/components/table/_index.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/table/_table.scss (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/table/eui_table.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/table/eui_table_ssp.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/table/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/components/table/storage.js (100%) rename x-pack/{legacy/plugins/monitoring/public/directives/beats/overview => plugins/monitoring/public/directives/beats/beat}/index.js (59%) rename x-pack/{legacy/plugins/monitoring/public/directives/beats/beat => plugins/monitoring/public/directives/beats/overview}/index.js (55%) rename x-pack/{legacy => }/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js (63%) rename x-pack/{legacy => }/plugins/monitoring/public/directives/main/__tests__/monitoring_main_controller.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/directives/main/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/directives/main/index.js (93%) rename x-pack/{legacy => }/plugins/monitoring/public/icons/health-gray.svg (100%) rename x-pack/{legacy => }/plugins/monitoring/public/icons/health-green.svg (100%) rename x-pack/{legacy => }/plugins/monitoring/public/icons/health-red.svg (100%) rename x-pack/{legacy => }/plugins/monitoring/public/icons/health-yellow.svg (100%) rename x-pack/{legacy => }/plugins/monitoring/public/index.scss (83%) rename x-pack/{legacy/plugins/monitoring/public/np_ready => plugins/monitoring/public}/index.ts (84%) rename x-pack/{legacy => }/plugins/monitoring/public/jest.helpers.ts (80%) create mode 100644 x-pack/plugins/monitoring/public/legacy_shims.ts rename x-pack/{legacy => }/plugins/monitoring/public/lib/__tests__/format_number.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/ajax_error_handler.tsx (88%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/calculate_shard_stats.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/__tests__/enabler.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/__tests__/settings_checker.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/__tests__/start_checks.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/checkers/cluster_settings.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/checkers/node_settings.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/checkers/settings_checker.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/enabler.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/elasticsearch_settings/start_checks.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/ensure_minimum_time.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/ensure_minimum_time.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/extract_ip.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/form_validation.ts (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/format_number.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/get_cluster_from_clusters.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/get_page_data.js (87%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/get_safe_for_external_link.ts (100%) create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/API.md create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/index.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.colorhelpers.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.canvas.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.categories.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.crosshair.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.errorbars.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.fillbetween.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.image.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.log.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.navigate.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.pie.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.resize.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.selection.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.stack.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.symbol.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.threshold.js create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.time.js rename x-pack/{legacy/plugins/monitoring/common => plugins/monitoring/public/lib/jquery_flot}/index.js (76%) create mode 100644 x-pack/plugins/monitoring/public/lib/jquery_flot/jquery_flot.js rename x-pack/{legacy => }/plugins/monitoring/public/lib/logstash/__tests__/pipelines.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/logstash/pipelines.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/route_init.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/setup_mode.test.js (72%) rename x-pack/{legacy => }/plugins/monitoring/public/lib/setup_mode.tsx (82%) create mode 100644 x-pack/plugins/monitoring/public/plugin.ts rename x-pack/{legacy => }/plugins/monitoring/public/services/__tests__/breadcrumbs.js (96%) rename x-pack/{legacy/plugins/monitoring/public/services/__tests__/executor_provider.js => plugins/monitoring/public/services/__tests__/executor.js} (87%) rename x-pack/{legacy/plugins/monitoring/public/services/breadcrumbs_provider.js => plugins/monitoring/public/services/breadcrumbs.js} (98%) rename x-pack/{legacy => }/plugins/monitoring/public/services/clusters.js (77%) rename x-pack/{legacy/plugins/monitoring/public/services/executor_provider.js => plugins/monitoring/public/services/executor.js} (66%) rename x-pack/{legacy => }/plugins/monitoring/public/services/features.js (86%) rename x-pack/{legacy => }/plugins/monitoring/public/services/license.js (88%) rename x-pack/{legacy => }/plugins/monitoring/public/services/title.js (54%) create mode 100644 x-pack/plugins/monitoring/public/types.ts create mode 100644 x-pack/plugins/monitoring/public/url_state.ts rename x-pack/{legacy => }/plugins/monitoring/public/views/__tests__/base_controller.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/views/__tests__/base_table_controller.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/access_denied/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/access_denied/index.js (89%) rename x-pack/{legacy => }/plugins/monitoring/public/views/alerts/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/alerts/index.js (77%) rename x-pack/{legacy => }/plugins/monitoring/public/views/all.js (98%) rename x-pack/{legacy => }/plugins/monitoring/public/views/apm/instance/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/apm/instance/index.js (83%) rename x-pack/{legacy => }/plugins/monitoring/public/views/apm/instances/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/apm/instances/index.js (70%) rename x-pack/{legacy => }/plugins/monitoring/public/views/apm/overview/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/apm/overview/index.js (81%) rename x-pack/{legacy => }/plugins/monitoring/public/views/base_controller.js (77%) rename x-pack/{legacy => }/plugins/monitoring/public/views/base_eui_table_controller.js (97%) rename x-pack/{legacy => }/plugins/monitoring/public/views/base_table_controller.js (95%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/beat/get_page_data.js (82%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/beat/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/beat/index.js (92%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/listing/get_page_data.js (80%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/listing/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/listing/index.js (66%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/overview/get_page_data.js (80%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/overview/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/beats/overview/index.js (91%) rename x-pack/{legacy => }/plugins/monitoring/public/views/cluster/listing/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/cluster/listing/index.js (75%) rename x-pack/{legacy => }/plugins/monitoring/public/views/cluster/overview/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/cluster/overview/index.js (68%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ccr/get_page_data.js (80%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ccr/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ccr/index.js (83%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ccr/shard/get_page_data.js (82%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js (86%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js (79%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/index/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/index/index.js (80%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/indices/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/indices/index.js (80%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ml_jobs/get_page_data.js (80%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js (92%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js (78%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/node/get_page_data.js (84%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/node/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/node/index.js (84%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/nodes/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/nodes/index.js (74%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/overview/controller.js (83%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/overview/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/elasticsearch/overview/index.js (84%) rename x-pack/{legacy => }/plugins/monitoring/public/views/index.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/kibana/instance/index.html (100%) create mode 100644 x-pack/plugins/monitoring/public/views/kibana/instance/index.js rename x-pack/{legacy => }/plugins/monitoring/public/views/kibana/instances/get_page_data.js (80%) rename x-pack/{legacy => }/plugins/monitoring/public/views/kibana/instances/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/kibana/instances/index.js (56%) rename x-pack/{legacy => }/plugins/monitoring/public/views/kibana/overview/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/kibana/overview/index.js (58%) rename x-pack/{legacy => }/plugins/monitoring/public/views/license/controller.js (71%) rename x-pack/{legacy => }/plugins/monitoring/public/views/license/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/license/index.js (83%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/node/advanced/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/node/advanced/index.js (65%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/node/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/node/index.js (65%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/node/pipelines/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/node/pipelines/index.js (74%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/nodes/get_page_data.js (80%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/nodes/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/nodes/index.js (57%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/overview/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/overview/index.js (73%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/pipeline/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/pipeline/index.js (77%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/pipelines/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/logstash/pipelines/index.js (75%) rename x-pack/{legacy => }/plugins/monitoring/public/views/no_data/__tests__/model_updater.test.js (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/no_data/controller.js (87%) rename x-pack/{legacy => }/plugins/monitoring/public/views/no_data/index.html (100%) rename x-pack/{legacy => }/plugins/monitoring/public/views/no_data/index.js (63%) rename x-pack/{legacy => }/plugins/monitoring/public/views/no_data/model_updater.js (100%) diff --git a/.eslintignore b/.eslintignore index 2ed9ecf971ff3..4913192e81c1d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -30,6 +30,7 @@ target /x-pack/legacy/plugins/canvas/canvas_plugin_src/lib/flot-charts /x-pack/legacy/plugins/canvas/shareable_runtime/build /x-pack/legacy/plugins/canvas/storybook +/x-pack/plugins/monitoring/public/lib/jquery_flot /x-pack/legacy/plugins/infra/common/graphql/types.ts /x-pack/legacy/plugins/infra/public/graphql/types.ts /x-pack/legacy/plugins/infra/server/graphql/types.ts diff --git a/.eslintrc.js b/.eslintrc.js index c9b41ec711b7f..8b33ec83347a8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -963,6 +963,12 @@ module.exports = { jquery: true, }, }, + { + files: ['x-pack/plugins/monitoring/public/lib/jquery_flot/**/*.js'], + env: { + jquery: true, + }, + }, /** * TSVB overrides diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c17538849660e..3981a8e1e9afe 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -84,6 +84,7 @@ /x-pack/legacy/plugins/ingest_manager/ @elastic/ingest-management /x-pack/plugins/observability/ @elastic/logs-metrics-ui @elastic/apm-ui @elastic/uptime @elastic/ingest-management /x-pack/legacy/plugins/monitoring/ @elastic/stack-monitoring-ui +/x-pack/plugins/monitoring/ @elastic/stack-monitoring-ui /x-pack/plugins/uptime @elastic/uptime # Machine Learning diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index 66296736b3ad0..14e25ab863dbc 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -38,6 +38,7 @@ export const IGNORE_FILE_GLOBS = [ 'x-pack/legacy/plugins/apm/**/*', 'x-pack/legacy/plugins/canvas/tasks/**/*', 'x-pack/legacy/plugins/canvas/canvas_plugin_src/**/*', + 'x-pack/plugins/monitoring/public/lib/jquery_flot/**/*', '**/.*', '**/{webpackShims,__mocks__}/**/*', 'x-pack/docs/**/*', @@ -160,12 +161,11 @@ export const TEMPORARILY_IGNORED_PATHS = [ 'webpackShims/ui-bootstrap.js', 'x-pack/legacy/plugins/index_management/public/lib/editSettings.js', 'x-pack/legacy/plugins/license_management/public/store/reducers/licenseManagement.js', - 'x-pack/legacy/plugins/monitoring/public/components/sparkline/__mocks__/plugins/xpack_main/jquery_flot.js', - 'x-pack/legacy/plugins/monitoring/public/icons/alert-blue.svg', - 'x-pack/legacy/plugins/monitoring/public/icons/health-gray.svg', - 'x-pack/legacy/plugins/monitoring/public/icons/health-green.svg', - 'x-pack/legacy/plugins/monitoring/public/icons/health-red.svg', - 'x-pack/legacy/plugins/monitoring/public/icons/health-yellow.svg', + 'x-pack/plugins/monitoring/public/components/sparkline/__mocks__/plugins/xpack_main/jquery_flot.js', + 'x-pack/plugins/monitoring/public/icons/health-gray.svg', + 'x-pack/plugins/monitoring/public/icons/health-green.svg', + 'x-pack/plugins/monitoring/public/icons/health-red.svg', + 'x-pack/plugins/monitoring/public/icons/health-yellow.svg', 'x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/lib/pdf/assets/fonts/noto/NotoSansCJKtc-Medium.ttf', 'x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/lib/pdf/assets/fonts/noto/NotoSansCJKtc-Regular.ttf', 'x-pack/legacy/plugins/reporting/export_types/printable_pdf/server/lib/pdf/assets/fonts/roboto/Roboto-Italic.ttf', diff --git a/x-pack/legacy/plugins/monitoring/.agignore b/x-pack/legacy/plugins/monitoring/.agignore deleted file mode 100644 index 10fb4038cbdc2..0000000000000 --- a/x-pack/legacy/plugins/monitoring/.agignore +++ /dev/null @@ -1,3 +0,0 @@ -agent -node_modules -bower_components diff --git a/x-pack/legacy/plugins/monitoring/common/__tests__/format_timestamp_to_duration.js b/x-pack/legacy/plugins/monitoring/common/__tests__/format_timestamp_to_duration.js deleted file mode 100644 index 470d596bd2bdc..0000000000000 --- a/x-pack/legacy/plugins/monitoring/common/__tests__/format_timestamp_to_duration.js +++ /dev/null @@ -1,128 +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 moment from 'moment'; -import { formatTimestampToDuration } from '../format_timestamp_to_duration'; -import { CALCULATE_DURATION_SINCE, CALCULATE_DURATION_UNTIL } from '../constants'; - -const testTime = moment('2010-05-01'); // pick a date where adding/subtracting 2 months formats roundly to '2 months 0 days' -const getTestTime = () => moment(testTime); // clones the obj so it's not mutated with .adds and .subtracts - -/** - * Test the moment-duration-format template - */ -describe('formatTimestampToDuration', () => { - describe('format timestamp to duration - time since', () => { - it('should format timestamp to human-readable duration', () => { - // time inputs are a few "moments" extra from the time advertised by name - const fiftyNineSeconds = getTestTime().subtract(59, 'seconds'); - expect( - formatTimestampToDuration(fiftyNineSeconds, CALCULATE_DURATION_SINCE, getTestTime()) - ).to.be('59 seconds'); - - const fiveMins = getTestTime() - .subtract(5, 'minutes') - .subtract(30, 'seconds'); - expect(formatTimestampToDuration(fiveMins, CALCULATE_DURATION_SINCE, getTestTime())).to.be( - '6 mins' - ); - - const sixHours = getTestTime() - .subtract(6, 'hours') - .subtract(30, 'minutes'); - expect(formatTimestampToDuration(sixHours, CALCULATE_DURATION_SINCE, getTestTime())).to.be( - '6 hrs 30 mins' - ); - - const sevenDays = getTestTime() - .subtract(7, 'days') - .subtract(6, 'hours') - .subtract(18, 'minutes'); - expect(formatTimestampToDuration(sevenDays, CALCULATE_DURATION_SINCE, getTestTime())).to.be( - '7 days 6 hrs 18 mins' - ); - - const eightWeeks = getTestTime() - .subtract(8, 'weeks') - .subtract(7, 'days') - .subtract(6, 'hours') - .subtract(18, 'minutes'); - expect(formatTimestampToDuration(eightWeeks, CALCULATE_DURATION_SINCE, getTestTime())).to.be( - '2 months 2 days' - ); - - const oneHour = getTestTime().subtract(1, 'hour'); // should trim 0 min - expect(formatTimestampToDuration(oneHour, CALCULATE_DURATION_SINCE, getTestTime())).to.be( - '1 hr' - ); - - const oneDay = getTestTime().subtract(1, 'day'); // should trim 0 hrs - expect(formatTimestampToDuration(oneDay, CALCULATE_DURATION_SINCE, getTestTime())).to.be( - '1 day' - ); - - const twoMonths = getTestTime().subtract(2, 'month'); // should trim 0 days - expect(formatTimestampToDuration(twoMonths, CALCULATE_DURATION_SINCE, getTestTime())).to.be( - '2 months' - ); - }); - }); - - describe('format timestamp to duration - time until', () => { - it('should format timestamp to human-readable duration', () => { - // time inputs are a few "moments" extra from the time advertised by name - const fiftyNineSeconds = getTestTime().add(59, 'seconds'); - expect( - formatTimestampToDuration(fiftyNineSeconds, CALCULATE_DURATION_UNTIL, getTestTime()) - ).to.be('59 seconds'); - - const fiveMins = getTestTime().add(10, 'minutes'); - expect(formatTimestampToDuration(fiveMins, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( - '10 mins' - ); - - const sixHours = getTestTime() - .add(6, 'hours') - .add(30, 'minutes'); - expect(formatTimestampToDuration(sixHours, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( - '6 hrs 30 mins' - ); - - const sevenDays = getTestTime() - .add(7, 'days') - .add(6, 'hours') - .add(18, 'minutes'); - expect(formatTimestampToDuration(sevenDays, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( - '7 days 6 hrs 18 mins' - ); - - const eightWeeks = getTestTime() - .add(8, 'weeks') - .add(7, 'days') - .add(6, 'hours') - .add(18, 'minutes'); - expect(formatTimestampToDuration(eightWeeks, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( - '2 months 2 days' - ); - - const oneHour = getTestTime().add(1, 'hour'); // should trim 0 min - expect(formatTimestampToDuration(oneHour, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( - '1 hr' - ); - - const oneDay = getTestTime().add(1, 'day'); // should trim 0 hrs - expect(formatTimestampToDuration(oneDay, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( - '1 day' - ); - - const twoMonths = getTestTime().add(2, 'month'); // should trim 0 days - expect(formatTimestampToDuration(twoMonths, CALCULATE_DURATION_UNTIL, getTestTime())).to.be( - '2 months' - ); - }); - }); -}); diff --git a/x-pack/legacy/plugins/monitoring/common/cancel_promise.ts b/x-pack/legacy/plugins/monitoring/common/cancel_promise.ts deleted file mode 100644 index f100edda50796..0000000000000 --- a/x-pack/legacy/plugins/monitoring/common/cancel_promise.ts +++ /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. - */ - -export enum Status { - Canceled, - Failed, - Resolved, - Awaiting, - Idle, -} - -/** - * Simple [PromiseWithCancel] factory - */ -export class PromiseWithCancel { - private _promise: Promise; - private _status: Status = Status.Idle; - - /** - * @param {Promise} promise Promise you want to cancel / track - */ - constructor(promise: Promise) { - this._promise = promise; - } - - /** - * Cancel the promise in any state - */ - public cancel = (): void => { - this._status = Status.Canceled; - }; - - /** - * @returns status based on [Status] - */ - public status = (): Status => { - return this._status; - }; - - /** - * @returns promise passed in [constructor] - * This sets the state to Status.Awaiting - */ - public promise = (): Promise => { - if (this._status === Status.Canceled) { - throw Error('Getting a canceled promise is not allowed'); - } else if (this._status !== Status.Idle) { - return this._promise; - } - return new Promise((resolve, reject) => { - this._status = Status.Awaiting; - return this._promise - .then(response => { - if (this._status !== Status.Canceled) { - this._status = Status.Resolved; - return resolve(response); - } - }) - .catch(error => { - if (this._status !== Status.Canceled) { - this._status = Status.Failed; - return reject(error); - } - }); - }); - }; -} diff --git a/x-pack/legacy/plugins/monitoring/common/constants.ts b/x-pack/legacy/plugins/monitoring/common/constants.ts deleted file mode 100644 index 36030e1fa7f2a..0000000000000 --- a/x-pack/legacy/plugins/monitoring/common/constants.ts +++ /dev/null @@ -1,268 +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. - */ - -/** - * Helper string to add as a tag in every logging call - */ -export const LOGGING_TAG = 'monitoring'; -/** - * Helper string to add as a tag in every logging call related to Kibana monitoring - */ -export const KIBANA_MONITORING_LOGGING_TAG = 'kibana-monitoring'; - -/** - * The Monitoring API version is the expected API format that we export and expect to import. - * @type {string} - */ -export const MONITORING_SYSTEM_API_VERSION = '7'; -/** - * The type name used within the Monitoring index to publish Kibana ops stats. - * @type {string} - */ -export const KIBANA_STATS_TYPE_MONITORING = 'kibana_stats'; // similar to KIBANA_STATS_TYPE but rolled up into 10s stats from 5s intervals through ops_buffer -/** - * The type name used within the Monitoring index to publish Kibana stats. - * @type {string} - */ -export const KIBANA_SETTINGS_TYPE = 'kibana_settings'; -/** - * The type name used within the Monitoring index to publish Kibana usage stats. - * NOTE: this string shows as-is in the stats API as a field name for the kibana usage stats - * @type {string} - */ -export const KIBANA_USAGE_TYPE = 'kibana'; - -/* - * Key for the localStorage service - */ -export const STORAGE_KEY = 'xpack.monitoring.data'; - -/** - * Units for derivative metric values - */ -export const NORMALIZED_DERIVATIVE_UNIT = '1s'; - -/* - * Values for column sorting in table options - * @type {number} 1 or -1 - */ -export const EUI_SORT_ASCENDING = 'asc'; -export const EUI_SORT_DESCENDING = 'desc'; -export const SORT_ASCENDING = 1; -export const SORT_DESCENDING = -1; - -/* - * Chart colors - * @type {string} - */ -export const CHART_LINE_COLOR = '#d2d2d2'; -export const CHART_TEXT_COLOR = '#9c9c9c'; - -/* - * Number of cluster alerts to show on overview page - * @type {number} - */ -export const CLUSTER_ALERTS_SEARCH_SIZE = 3; - -/* - * Format for moment-duration-format timestamp-to-duration template if the time diffs are gte 1 month - * @type {string} - */ -export const FORMAT_DURATION_TEMPLATE_LONG = 'M [months] d [days]'; - -/* - * Format for moment-duration-format timestamp-to-duration template if the time diffs are lt 1 month but gt 1 minute - * @type {string} - */ -export const FORMAT_DURATION_TEMPLATE_SHORT = ' d [days] h [hrs] m [min]'; - -/* - * Format for moment-duration-format timestamp-to-duration template if the time diffs are lt 1 minute - * @type {string} - */ -export const FORMAT_DURATION_TEMPLATE_TINY = ' s [seconds]'; - -/* - * Simple unique values for Timestamp to duration flags. These are used for - * determining if calculation should be formatted as "time until" (now to - * timestamp) or "time since" (timestamp to now) - */ -export const CALCULATE_DURATION_SINCE = 'since'; -export const CALCULATE_DURATION_UNTIL = 'until'; - -/** - * In order to show ML Jobs tab in the Elasticsearch section / tab navigation, license must be supported - */ -export const ML_SUPPORTED_LICENSES = ['trial', 'platinum', 'enterprise']; - -/** - * Metadata service URLs for the different cloud services that have constant URLs (e.g., unlike GCP, which is a constant prefix). - * - * @type {Object} - */ -export const CLOUD_METADATA_SERVICES = { - // We explicitly call out the version, 2016-09-02, rather than 'latest' to avoid unexpected changes - AWS_URL: 'http://169.254.169.254/2016-09-02/dynamic/instance-identity/document', - - // 2017-04-02 is the first GA release of this API - AZURE_URL: 'http://169.254.169.254/metadata/instance?api-version=2017-04-02', - - // GCP documentation shows both 'metadata.google.internal' (mostly) and '169.254.169.254' (sometimes) - // To bypass potential DNS changes, the IP was used because it's shared with other cloud services - GCP_URL_PREFIX: 'http://169.254.169.254/computeMetadata/v1/instance', -}; - -/** - * Constants used by Logstash monitoring code - */ -export const LOGSTASH = { - MAJOR_VER_REQD_FOR_PIPELINES: 6, - - /* - * Names ES keys on for different Logstash pipeline queues. - * @type {string} - */ - QUEUE_TYPES: { - MEMORY: 'memory', - PERSISTED: 'persisted', - }, -}; - -export const DEBOUNCE_SLOW_MS = 17; // roughly how long it takes to render a frame at 60fps -export const DEBOUNCE_FAST_MS = 10; // roughly how long it takes to render a frame at 100fps - -/** - * Configuration key for setting the email address used for cluster alert notifications. - */ -export const CLUSTER_ALERTS_ADDRESS_CONFIG_KEY = 'cluster_alerts.email_notifications.email_address'; - -export const STANDALONE_CLUSTER_CLUSTER_UUID = '__standalone_cluster__'; - -export const INDEX_PATTERN = '.monitoring-*-6-*,.monitoring-*-7-*'; -export const INDEX_PATTERN_KIBANA = '.monitoring-kibana-6-*,.monitoring-kibana-7-*'; -export const INDEX_PATTERN_LOGSTASH = '.monitoring-logstash-6-*,.monitoring-logstash-7-*'; -export const INDEX_PATTERN_BEATS = '.monitoring-beats-6-*,.monitoring-beats-7-*'; -export const INDEX_ALERTS = '.monitoring-alerts-6,.monitoring-alerts-7'; -export const INDEX_PATTERN_ELASTICSEARCH = '.monitoring-es-6-*,.monitoring-es-7-*'; - -// This is the unique token that exists in monitoring indices collected by metricbeat -export const METRICBEAT_INDEX_NAME_UNIQUE_TOKEN = '-mb-'; - -// We use this for metricbeat migration to identify specific products that we do not have constants for -export const ELASTICSEARCH_SYSTEM_ID = 'elasticsearch'; - -/** - * The id of the infra source owned by the monitoring plugin. - */ -export const INFRA_SOURCE_ID = 'internal-stack-monitoring'; - -/* - * These constants represent code paths within `getClustersFromRequest` - * that an api call wants to invoke. This is meant as an optimization to - * avoid unnecessary ES queries (looking at you logstash) when the data - * is not used. In the long term, it'd be nice to have separate api calls - * instead of this path logic. - */ -export const CODE_PATH_ALL = 'all'; -export const CODE_PATH_ALERTS = 'alerts'; -export const CODE_PATH_KIBANA = 'kibana'; -export const CODE_PATH_ELASTICSEARCH = 'elasticsearch'; -export const CODE_PATH_ML = 'ml'; -export const CODE_PATH_BEATS = 'beats'; -export const CODE_PATH_LOGSTASH = 'logstash'; -export const CODE_PATH_APM = 'apm'; -export const CODE_PATH_LICENSE = 'license'; -export const CODE_PATH_LOGS = 'logs'; - -/** - * The header sent by telemetry service when hitting Elasticsearch to identify query source - * @type {string} - */ -export const TELEMETRY_QUERY_SOURCE = 'TELEMETRY'; - -/** - * The name of the Kibana System ID used to publish and look up Kibana stats through the Monitoring system. - * @type {string} - */ -export const KIBANA_SYSTEM_ID = 'kibana'; - -/** - * The name of the Beats System ID used to publish and look up Beats stats through the Monitoring system. - * @type {string} - */ -export const BEATS_SYSTEM_ID = 'beats'; - -/** - * The name of the Apm System ID used to publish and look up Apm stats through the Monitoring system. - * @type {string} - */ -export const APM_SYSTEM_ID = 'apm'; - -/** - * The name of the Kibana System ID used to look up Logstash stats through the Monitoring system. - * @type {string} - */ -export const LOGSTASH_SYSTEM_ID = 'logstash'; - -/** - * The name of the Kibana System ID used to look up Reporting stats through the Monitoring system. - * @type {string} - */ -export const REPORTING_SYSTEM_ID = 'reporting'; - -/** - * The amount of time, in milliseconds, to wait between collecting kibana stats from es. - * - * Currently 24 hours kept in sync with reporting interval. - * @type {Number} - */ -export const TELEMETRY_COLLECTION_INTERVAL = 86400000; - -/** - * We want to slowly rollout the migration from watcher-based cluster alerts to - * kibana alerts and we only want to enable the kibana alerts once all - * watcher-based cluster alerts have been migrated so this flag will serve - * as the only way to see the new UI and actually run Kibana alerts. It will - * be false until all alerts have been migrated, then it will be removed - */ -export const KIBANA_ALERTING_ENABLED = false; - -/** - * The prefix for all alert types used by monitoring - */ -export const ALERT_TYPE_PREFIX = 'monitoring_'; - -/** - * This is the alert type id for the license expiration alert - */ -export const ALERT_TYPE_LICENSE_EXPIRATION = `${ALERT_TYPE_PREFIX}alert_type_license_expiration`; -/** - * This is the alert type id for the cluster state alert - */ -export const ALERT_TYPE_CLUSTER_STATE = `${ALERT_TYPE_PREFIX}alert_type_cluster_state`; - -/** - * A listing of all alert types - */ -export const ALERT_TYPES = [ALERT_TYPE_LICENSE_EXPIRATION, ALERT_TYPE_CLUSTER_STATE]; - -/** - * Matches the id for the built-in in email action type - * See x-pack/plugins/actions/server/builtin_action_types/email.ts - */ -export const ALERT_ACTION_TYPE_EMAIL = '.email'; - -/** - * The number of alerts that have been migrated - */ -export const NUMBER_OF_MIGRATED_ALERTS = 2; - -/** - * The advanced settings config name for the email address - */ -export const MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS = 'monitoring:alertingEmailAddress'; - -export const ALERT_EMAIL_SERVICES = ['gmail', 'hotmail', 'icloud', 'outlook365', 'ses', 'yahoo']; diff --git a/x-pack/legacy/plugins/monitoring/common/format_timestamp_to_duration.js b/x-pack/legacy/plugins/monitoring/common/format_timestamp_to_duration.js deleted file mode 100644 index 46c8f7db49b0f..0000000000000 --- a/x-pack/legacy/plugins/monitoring/common/format_timestamp_to_duration.js +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import moment from 'moment'; -import 'moment-duration-format'; -import { - FORMAT_DURATION_TEMPLATE_TINY, - FORMAT_DURATION_TEMPLATE_SHORT, - FORMAT_DURATION_TEMPLATE_LONG, - CALCULATE_DURATION_SINCE, - CALCULATE_DURATION_UNTIL, -} from './constants'; - -/* - * Formats a timestamp string - * @param timestamp: ISO time string - * @param calculationFlag: control "since" or "until" logic - * @param initialTime {Object} moment object (not required) - * @return string - */ -export function formatTimestampToDuration(timestamp, calculationFlag, initialTime) { - initialTime = initialTime || moment(); - let timeDuration; - if (calculationFlag === CALCULATE_DURATION_SINCE) { - timeDuration = moment.duration(initialTime - moment(timestamp)); // since: now - timestamp - } else if (calculationFlag === CALCULATE_DURATION_UNTIL) { - timeDuration = moment.duration(moment(timestamp) - initialTime); // until: timestamp - now - } else { - throw new Error( - '[formatTimestampToDuration] requires a [calculationFlag] parameter to specify format as "since" or "until" the given time.' - ); - } - - // See https://github.com/elastic/x-pack-kibana/issues/3554 - let duration; - if (Math.abs(initialTime.diff(timestamp, 'months')) >= 1) { - // time diff is greater than 1 month, show months / days - duration = moment.duration(timeDuration).format(FORMAT_DURATION_TEMPLATE_LONG); - } else if (Math.abs(initialTime.diff(timestamp, 'minutes')) >= 1) { - // time diff is less than 1 month but greater than a minute, show days / hours / minutes - duration = moment.duration(timeDuration).format(FORMAT_DURATION_TEMPLATE_SHORT); - } else { - // time diff is less than a minute, show seconds - duration = moment.duration(timeDuration).format(FORMAT_DURATION_TEMPLATE_TINY); - } - - return duration - .replace(/ 0 mins$/, '') - .replace(/ 0 hrs$/, '') - .replace(/ 0 days$/, ''); // See https://github.com/jsmreese/moment-duration-format/issues/64 -} diff --git a/x-pack/legacy/plugins/monitoring/common/formatting.js b/x-pack/legacy/plugins/monitoring/common/formatting.js deleted file mode 100644 index ed5d68f942dfd..0000000000000 --- a/x-pack/legacy/plugins/monitoring/common/formatting.js +++ /dev/null @@ -1,35 +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 moment from 'moment-timezone'; - -export const LARGE_FLOAT = '0,0.[00]'; -export const SMALL_FLOAT = '0.[00]'; -export const LARGE_BYTES = '0,0.0 b'; -export const SMALL_BYTES = '0.0 b'; -export const LARGE_ABBREVIATED = '0,0.[0]a'; - -/** - * Format the {@code date} in the user's expected date/time format using their dateFormat:tz defined time zone. - * @param date Either a numeric Unix timestamp or a {@code Date} object - * @returns The date formatted using 'LL LTS' - */ -export function formatDateTimeLocal(date, timezone) { - if (timezone === 'Browser') { - timezone = moment.tz.guess() || 'utc'; - } - - return moment.tz(date, timezone).format('LL LTS'); -} - -/** - * Shorten a Logstash Pipeline's hash for display purposes - * @param {string} hash The complete hash - * @return {string} The shortened hash - */ -export function shortenPipelineHash(hash) { - return hash.substr(0, 6); -} diff --git a/x-pack/legacy/plugins/monitoring/config.js b/x-pack/legacy/plugins/monitoring/config.ts similarity index 99% rename from x-pack/legacy/plugins/monitoring/config.js rename to x-pack/legacy/plugins/monitoring/config.ts index fd4e6512c5063..0c664fbe1c00c 100644 --- a/x-pack/legacy/plugins/monitoring/config.js +++ b/x-pack/legacy/plugins/monitoring/config.ts @@ -9,7 +9,7 @@ * @param {Object} Joi - HapiJS Joi module that allows for schema validation * @return {Object} config schema */ -export const config = Joi => { +export const config = (Joi: any) => { const DEFAULT_REQUEST_HEADERS = ['authorization']; return Joi.object({ diff --git a/x-pack/legacy/plugins/monitoring/index.js b/x-pack/legacy/plugins/monitoring/index.js deleted file mode 100644 index ccb45dc1f446f..0000000000000 --- a/x-pack/legacy/plugins/monitoring/index.js +++ /dev/null @@ -1,57 +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 { resolve } from 'path'; -import { config } from './config'; -import { getUiExports } from './ui_exports'; -import { KIBANA_ALERTING_ENABLED } from './common/constants'; - -/** - * Invokes plugin modules to instantiate the Monitoring plugin for Kibana - * @param kibana {Object} Kibana plugin instance - * @return {Object} Monitoring UI Kibana plugin object - */ -const deps = ['kibana', 'elasticsearch', 'xpack_main']; -if (KIBANA_ALERTING_ENABLED) { - deps.push(...['alerting', 'actions']); -} -export const monitoring = kibana => { - return new kibana.Plugin({ - require: deps, - id: 'monitoring', - configPrefix: 'monitoring', - publicDir: resolve(__dirname, 'public'), - init(server) { - const serverConfig = server.config(); - const npMonitoring = server.newPlatform.setup.plugins.monitoring; - if (npMonitoring) { - const kbnServerStatus = this.kbnServer.status; - npMonitoring.registerLegacyAPI({ - getServerStatus: () => { - const status = kbnServerStatus.toJSON(); - return get(status, 'overall.state'); - }, - }); - } - - server.injectUiAppVars('monitoring', () => { - return { - maxBucketSize: serverConfig.get('monitoring.ui.max_bucket_size'), - minIntervalSeconds: serverConfig.get('monitoring.ui.min_interval_seconds'), - kbnIndex: serverConfig.get('kibana.index'), - showLicenseExpiration: serverConfig.get('monitoring.ui.show_license_expiration'), - showCgroupMetricsElasticsearch: serverConfig.get( - 'monitoring.ui.container.elasticsearch.enabled' - ), - showCgroupMetricsLogstash: serverConfig.get('monitoring.ui.container.logstash.enabled'), // Note, not currently used, but see https://github.com/elastic/x-pack-kibana/issues/1559 part 2 - }; - }); - }, - config, - uiExports: getUiExports(), - }); -}; diff --git a/x-pack/legacy/plugins/monitoring/index.ts b/x-pack/legacy/plugins/monitoring/index.ts new file mode 100644 index 0000000000000..1a0fecb9ef5b5 --- /dev/null +++ b/x-pack/legacy/plugins/monitoring/index.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 { config } from './config'; +import { KIBANA_ALERTING_ENABLED } from '../../../plugins/monitoring/common/constants'; + +/** + * Invokes plugin modules to instantiate the Monitoring plugin for Kibana + * @param kibana {Object} Kibana plugin instance + * @return {Object} Monitoring UI Kibana plugin object + */ +const deps = ['kibana', 'elasticsearch', 'xpack_main']; +if (KIBANA_ALERTING_ENABLED) { + deps.push(...['alerting', 'actions']); +} +export const monitoring = (kibana: any) => { + return new kibana.Plugin({ + require: deps, + id: 'monitoring', + configPrefix: 'monitoring', + init(server: Hapi.Server) { + const npMonitoring = server.newPlatform.setup.plugins.monitoring as object & { + registerLegacyAPI: (api: unknown) => void; + }; + if (npMonitoring) { + const kbnServerStatus = this.kbnServer.status; + npMonitoring.registerLegacyAPI({ + getServerStatus: () => { + const status = kbnServerStatus.toJSON(); + return status?.overall?.state; + }, + }); + } + }, + config, + }); +}; diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/chart_target.test.js b/x-pack/legacy/plugins/monitoring/public/components/chart/chart_target.test.js deleted file mode 100644 index d8a6f1ad6bd9e..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/components/chart/chart_target.test.js +++ /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 expect from '@kbn/expect'; -import { shallow } from 'enzyme'; -import { ChartTarget } from './chart_target'; - -const props = { - seriesToShow: ['Max Heap', 'Max Heap Used'], - series: [ - { - color: '#3ebeb0', - label: 'Max Heap', - id: 'Max Heap', - data: [ - [1562958960000, 1037959168], - [1562958990000, 1037959168], - [1562959020000, 1037959168], - ], - }, - { - color: '#3b73ac', - label: 'Max Heap Used', - id: 'Max Heap Used', - data: [ - [1562958960000, 639905768], - [1562958990000, 622312416], - [1562959020000, 555967504], - ], - }, - ], - timeRange: { - min: 1562958939851, - max: 1562962539851, - }, - hasLegend: true, - onBrush: () => void 0, - tickFormatter: () => void 0, - updateLegend: () => void 0, -}; - -jest.mock('../../np_imports/ui/chrome', () => { - return { - getBasePath: () => '', - }; -}); - -// TODO: Skipping for now, seems flaky in New Platform (needs more investigation) -describe.skip('Test legends to toggle series: ', () => { - const ids = props.series.map(item => item.id); - - describe('props.series: ', () => { - it('should toggle based on seriesToShow array', () => { - const component = shallow(); - - const componentClass = component.instance(); - - const seriesA = componentClass.filterData(props.series, [ids[0]]); - expect(seriesA.length).to.be(1); - expect(seriesA[0].id).to.be(ids[0]); - - const seriesB = componentClass.filterData(props.series, [ids[1]]); - expect(seriesB.length).to.be(1); - expect(seriesB[0].id).to.be(ids[1]); - - const seriesAB = componentClass.filterData(props.series, ids); - expect(seriesAB.length).to.be(2); - expect(seriesAB[0].id).to.be(ids[0]); - expect(seriesAB[1].id).to.be(ids[1]); - }); - }); -}); diff --git a/x-pack/legacy/plugins/monitoring/public/components/license/index.js b/x-pack/legacy/plugins/monitoring/public/components/license/index.js deleted file mode 100644 index d43896d5f8d84..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/components/license/index.js +++ /dev/null @@ -1,91 +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 { - EuiPage, - EuiPageBody, - EuiSpacer, - EuiCodeBlock, - EuiPanel, - EuiText, - EuiLink, - EuiFlexGroup, - EuiFlexItem, - EuiScreenReaderOnly, -} from '@elastic/eui'; -import { LicenseStatus, AddLicense } from 'plugins/xpack_main/components'; -import { FormattedMessage } from '@kbn/i18n/react'; -import chrome from 'plugins/monitoring/np_imports/ui/chrome'; - -const licenseManagement = `${chrome.getBasePath()}/app/kibana#/management/elasticsearch/license_management`; - -const LicenseUpdateInfoForPrimary = ({ isPrimaryCluster, uploadLicensePath }) => { - if (!isPrimaryCluster) { - return null; - } - - // viewed license is for the cluster directly connected to Kibana - return ; -}; - -const LicenseUpdateInfoForRemote = ({ isPrimaryCluster }) => { - if (isPrimaryCluster) { - return null; - } - - // viewed license is for a remote monitored cluster not directly connected to Kibana - return ( - -

- -

- - - {`curl -XPUT -u 'https://:/_license' -H 'Content-Type: application/json' -d @license.json`} - -
- ); -}; - -export function License(props) { - const { status, type, isExpired, expiryDate } = props; - return ( - - -

- -

-
- - - - - - - - - - - - - -

- For more license options please visit  - License Management. -

-
-
-
- ); -} diff --git a/x-pack/legacy/plugins/monitoring/public/directives/all.js b/x-pack/legacy/plugins/monitoring/public/directives/all.js deleted file mode 100644 index 43ad80a7a7e94..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/directives/all.js +++ /dev/null @@ -1,10 +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 './main'; -import './elasticsearch/ml_job_listing'; -import './beats/overview'; -import './beats/beat'; diff --git a/x-pack/legacy/plugins/monitoring/public/filters/index.js b/x-pack/legacy/plugins/monitoring/public/filters/index.js deleted file mode 100644 index a67770ff50dc8..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/filters/index.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 { capitalize } from 'lodash'; -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -import { formatNumber, formatMetric } from 'plugins/monitoring/lib/format_number'; -import { extractIp } from 'plugins/monitoring/lib/extract_ip'; - -const uiModule = uiModules.get('monitoring/filters', []); - -uiModule.filter('capitalize', function() { - return function(input) { - return capitalize(input.toLowerCase()); - }; -}); - -uiModule.filter('formatNumber', function() { - return formatNumber; -}); - -uiModule.filter('formatMetric', function() { - return formatMetric; -}); - -uiModule.filter('extractIp', function() { - return extractIp; -}); diff --git a/x-pack/legacy/plugins/monitoring/public/hacks/__tests__/toggle_app_link_in_nav.js b/x-pack/legacy/plugins/monitoring/public/hacks/__tests__/toggle_app_link_in_nav.js deleted file mode 100644 index 6ed3371486740..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/hacks/__tests__/toggle_app_link_in_nav.js +++ /dev/null @@ -1,9 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { uiModules } from 'ui/modules'; - -uiModules.get('kibana').constant('monitoringUiEnabled', true); diff --git a/x-pack/legacy/plugins/monitoring/public/hacks/toggle_app_link_in_nav.js b/x-pack/legacy/plugins/monitoring/public/hacks/toggle_app_link_in_nav.js deleted file mode 100644 index 9448e826f3723..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/hacks/toggle_app_link_in_nav.js +++ /dev/null @@ -1,16 +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 { uiModules } from 'ui/modules'; -import { npStart } from 'ui/new_platform'; - -uiModules.get('monitoring/hacks').run(monitoringUiEnabled => { - if (monitoringUiEnabled) { - return; - } - - npStart.core.chrome.navLinks.update('monitoring', { hidden: true }); -}); diff --git a/x-pack/legacy/plugins/monitoring/public/icons/monitoring.svg b/x-pack/legacy/plugins/monitoring/public/icons/monitoring.svg deleted file mode 100644 index e00faca26a251..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/icons/monitoring.svg +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - diff --git a/x-pack/legacy/plugins/monitoring/public/legacy.ts b/x-pack/legacy/plugins/monitoring/public/legacy.ts deleted file mode 100644 index 293b6ac7bd821..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/legacy.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 'plugins/monitoring/filters'; -import 'plugins/monitoring/services/clusters'; -import 'plugins/monitoring/services/features'; -import 'plugins/monitoring/services/executor'; -import 'plugins/monitoring/services/license'; -import 'plugins/monitoring/services/title'; -import 'plugins/monitoring/services/breadcrumbs'; -import 'plugins/monitoring/directives/all'; -import 'plugins/monitoring/views/all'; -import { npSetup, npStart } from '../public/np_imports/legacy_imports'; -import { plugin } from './np_ready'; -import { localApplicationService } from '../../../../../src/legacy/core_plugins/kibana/public/local_application_service'; - -const pluginInstance = plugin({} as any); -pluginInstance.setup(npSetup.core, npSetup.plugins); -pluginInstance.start(npStart.core, { - ...npStart.plugins, - __LEGACY: { - localApplicationService, - }, -}); diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/angular_config.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/angular_config.ts deleted file mode 100644 index d1849d9247985..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/angular_config.ts +++ /dev/null @@ -1,157 +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 { - ICompileProvider, - IHttpProvider, - IHttpService, - ILocationProvider, - IModule, - IRootScopeService, -} from 'angular'; -import $ from 'jquery'; -import _, { cloneDeep, forOwn, get, set } from 'lodash'; -import * as Rx from 'rxjs'; -import { CoreStart, LegacyCoreStart } from 'kibana/public'; - -const isSystemApiRequest = (request: any) => - Boolean(request && request.headers && !!request.headers['kbn-system-api']); - -export const configureAppAngularModule = (angularModule: IModule, newPlatform: LegacyCoreStart) => { - const legacyMetadata = newPlatform.injectedMetadata.getLegacyMetadata(); - - forOwn(newPlatform.injectedMetadata.getInjectedVars(), (val, name) => { - if (name !== undefined) { - // The legacy platform modifies some of these values, clone to an unfrozen object. - angularModule.value(name, cloneDeep(val)); - } - }); - - angularModule - .value('kbnVersion', newPlatform.injectedMetadata.getKibanaVersion()) - .value('buildNum', legacyMetadata.buildNum) - .value('buildSha', legacyMetadata.buildSha) - .value('serverName', legacyMetadata.serverName) - .value('esUrl', getEsUrl(newPlatform)) - .value('uiCapabilities', newPlatform.application.capabilities) - .config(setupCompileProvider(newPlatform)) - .config(setupLocationProvider()) - .config($setupXsrfRequestInterceptor(newPlatform)) - .run(capture$httpLoadingCount(newPlatform)) - .run($setupUICapabilityRedirect(newPlatform)); -}; - -const getEsUrl = (newPlatform: CoreStart) => { - const a = document.createElement('a'); - a.href = newPlatform.http.basePath.prepend('/elasticsearch'); - const protocolPort = /https/.test(a.protocol) ? 443 : 80; - const port = a.port || protocolPort; - return { - host: a.hostname, - port, - protocol: a.protocol, - pathname: a.pathname, - }; -}; - -const setupCompileProvider = (newPlatform: LegacyCoreStart) => ( - $compileProvider: ICompileProvider -) => { - if (!newPlatform.injectedMetadata.getLegacyMetadata().devMode) { - $compileProvider.debugInfoEnabled(false); - } -}; - -const setupLocationProvider = () => ($locationProvider: ILocationProvider) => { - $locationProvider.html5Mode({ - enabled: false, - requireBase: false, - rewriteLinks: false, - }); - - $locationProvider.hashPrefix(''); -}; - -const $setupXsrfRequestInterceptor = (newPlatform: LegacyCoreStart) => { - const version = newPlatform.injectedMetadata.getLegacyMetadata().version; - - // Configure jQuery prefilter - $.ajaxPrefilter(({ kbnXsrfToken = true }: any, originalOptions, jqXHR) => { - if (kbnXsrfToken) { - jqXHR.setRequestHeader('kbn-version', version); - } - }); - - return ($httpProvider: IHttpProvider) => { - // Configure $httpProvider interceptor - $httpProvider.interceptors.push(() => { - return { - request(opts) { - const { kbnXsrfToken = true } = opts as any; - if (kbnXsrfToken) { - set(opts, ['headers', 'kbn-version'], version); - } - return opts; - }, - }; - }); - }; -}; - -/** - * Injected into angular module by ui/chrome angular integration - * and adds a root-level watcher that will capture the count of - * active $http requests on each digest loop and expose the count to - * the core.loadingCount api - * @param {Angular.Scope} $rootScope - * @param {HttpService} $http - * @return {undefined} - */ -const capture$httpLoadingCount = (newPlatform: CoreStart) => ( - $rootScope: IRootScopeService, - $http: IHttpService -) => { - newPlatform.http.addLoadingCountSource( - new Rx.Observable(observer => { - const unwatch = $rootScope.$watch(() => { - const reqs = $http.pendingRequests || []; - observer.next(reqs.filter(req => !isSystemApiRequest(req)).length); - }); - - return unwatch; - }) - ); -}; - -/** - * integrates with angular to automatically redirect to home if required - * capability is not met - */ -const $setupUICapabilityRedirect = (newPlatform: CoreStart) => ( - $rootScope: IRootScopeService, - $injector: any -) => { - const isKibanaAppRoute = window.location.pathname.endsWith('/app/kibana'); - // this feature only works within kibana app for now after everything is - // switched to the application service, this can be changed to handle all - // apps. - if (!isKibanaAppRoute) { - return; - } - $rootScope.$on( - '$routeChangeStart', - (event, { $$route: route }: { $$route?: { requireUICapability: boolean } } = {}) => { - if (!route || !route.requireUICapability) { - return; - } - - if (!get(newPlatform.application.capabilities, route.requireUICapability)) { - $injector.get('kbnUrl').change('/home'); - event.preventDefault(); - } - } - ); -}; diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/index.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/index.ts deleted file mode 100644 index 8fd8d170bbb40..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/index.ts +++ /dev/null @@ -1,48 +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 angular, { IModule } from 'angular'; - -import { AppMountContext, LegacyCoreStart } from 'kibana/public'; - -// @ts-ignore TODO: change to absolute path -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -// @ts-ignore TODO: change to absolute path -import chrome from 'plugins/monitoring/np_imports/ui/chrome'; -// @ts-ignore TODO: change to absolute path -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -// @ts-ignore TODO: change to absolute path -import { registerTimefilterWithGlobalState } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { configureAppAngularModule } from './angular_config'; - -import { localAppModule, appModuleName } from './modules'; - -export class AngularApp { - private injector?: angular.auto.IInjectorService; - - constructor({ core }: AppMountContext, { element }: { element: HTMLElement }) { - uiModules.addToModule(); - const app: IModule = localAppModule(core); - app.config(($routeProvider: any) => { - $routeProvider.eagerInstantiationEnabled(false); - uiRoutes.addToProvider($routeProvider); - }); - configureAppAngularModule(app, core as LegacyCoreStart); - registerTimefilterWithGlobalState(app); - const appElement = document.createElement('div'); - appElement.setAttribute('style', 'height: 100%'); - appElement.innerHTML = '
'; - this.injector = angular.bootstrap(appElement, [appModuleName]); - chrome.setInjector(this.injector); - angular.element(element).append(appElement); - } - - public destroy = () => { - if (this.injector) { - this.injector.get('$rootScope').$destroy(); - } - }; -} diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts deleted file mode 100644 index c6031cb220334..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/modules.ts +++ /dev/null @@ -1,148 +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 angular, { IWindowService } from 'angular'; -// required for `ngSanitize` angular module -import 'angular-sanitize'; -import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; - -import { AppMountContext } from 'kibana/public'; -import { Storage } from '../../../../../../../src/plugins/kibana_utils/public'; -import { - createTopNavDirective, - createTopNavHelper, -} from '../../../../../../../src/plugins/kibana_legacy/public'; - -import { - GlobalStateProvider, - StateManagementConfigProvider, - AppStateProvider, - KbnUrlProvider, - npStart, -} from '../legacy_imports'; - -// @ts-ignore -import { PromiseServiceCreator } from './providers/promises'; -// @ts-ignore -import { PrivateProvider } from './providers/private'; -import { getSafeForExternalLink } from '../../lib/get_safe_for_external_link'; - -type IPrivate = (provider: (...injectable: any[]) => T) => T; - -export const appModuleName = 'monitoring'; -const thirdPartyAngularDependencies = ['ngSanitize', 'ngRoute', 'react']; - -export const localAppModule = (core: AppMountContext['core']) => { - createLocalI18nModule(); - createLocalPrivateModule(); - createLocalPromiseModule(); - createLocalStorage(); - createLocalConfigModule(core); - createLocalKbnUrlModule(); - createLocalStateModule(); - createLocalTopNavModule(npStart.plugins.navigation); - createHrefModule(core); - - const appModule = angular.module(appModuleName, [ - ...thirdPartyAngularDependencies, - 'monitoring/Config', - 'monitoring/I18n', - 'monitoring/Private', - 'monitoring/TopNav', - 'monitoring/State', - 'monitoring/Storage', - 'monitoring/href', - 'monitoring/services', - 'monitoring/filters', - 'monitoring/directives', - ]); - return appModule; -}; - -function createLocalStateModule() { - angular - .module('monitoring/State', [ - 'monitoring/Private', - 'monitoring/Config', - 'monitoring/KbnUrl', - 'monitoring/Promise', - ]) - .factory('AppState', function(Private: IPrivate) { - return Private(AppStateProvider); - }) - .service('globalState', function(Private: IPrivate) { - return Private(GlobalStateProvider); - }); -} - -function createLocalKbnUrlModule() { - angular - .module('monitoring/KbnUrl', ['monitoring/Private', 'ngRoute']) - .service('kbnUrl', (Private: IPrivate) => Private(KbnUrlProvider)); -} - -function createLocalConfigModule(core: AppMountContext['core']) { - angular - .module('monitoring/Config', ['monitoring/Private']) - .provider('stateManagementConfig', StateManagementConfigProvider) - .provider('config', () => { - return { - $get: () => ({ - get: core.uiSettings.get.bind(core.uiSettings), - }), - }; - }); -} - -function createLocalPromiseModule() { - angular.module('monitoring/Promise', []).service('Promise', PromiseServiceCreator); -} - -function createLocalStorage() { - angular - .module('monitoring/Storage', []) - .service('localStorage', ($window: IWindowService) => new Storage($window.localStorage)) - .service('sessionStorage', ($window: IWindowService) => new Storage($window.sessionStorage)) - .service('sessionTimeout', () => {}); -} - -function createLocalPrivateModule() { - angular.module('monitoring/Private', []).provider('Private', PrivateProvider); -} - -function createLocalTopNavModule({ ui }: any) { - angular - .module('monitoring/TopNav', ['react']) - .directive('kbnTopNav', createTopNavDirective) - .directive('kbnTopNavHelper', createTopNavHelper(ui)); -} - -function createLocalI18nModule() { - angular - .module('monitoring/I18n', []) - .provider('i18n', I18nProvider) - .filter('i18n', i18nFilter) - .directive('i18nId', i18nDirective); -} - -function createHrefModule(core: AppMountContext['core']) { - const name: string = 'kbnHref'; - angular.module('monitoring/href', []).directive(name, () => { - return { - restrict: 'A', - link: { - pre: (_$scope, _$el, $attr) => { - $attr.$observe(name, val => { - if (val) { - const url = getSafeForExternalLink(val as string); - $attr.$set('href', core.http.basePath.prepend(url)); - } - }); - }, - }, - }; - }); -} diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/providers/promises.js b/x-pack/legacy/plugins/monitoring/public/np_imports/angular/providers/promises.js deleted file mode 100644 index 22adccaf3db7f..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/providers/promises.js +++ /dev/null @@ -1,116 +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'; - -export function PromiseServiceCreator($q, $timeout) { - function Promise(fn) { - if (typeof this === 'undefined') - throw new Error('Promise constructor must be called with "new"'); - - const defer = $q.defer(); - try { - fn(defer.resolve, defer.reject); - } catch (e) { - defer.reject(e); - } - return defer.promise; - } - - Promise.all = Promise.props = $q.all; - Promise.resolve = function(val) { - const defer = $q.defer(); - defer.resolve(val); - return defer.promise; - }; - Promise.reject = function(reason) { - const defer = $q.defer(); - defer.reject(reason); - return defer.promise; - }; - Promise.cast = $q.when; - Promise.delay = function(ms) { - return $timeout(_.noop, ms); - }; - Promise.method = function(fn) { - return function() { - const args = Array.prototype.slice.call(arguments); - return Promise.try(fn, args, this); - }; - }; - Promise.nodeify = function(promise, cb) { - promise.then(function(val) { - cb(void 0, val); - }, cb); - }; - Promise.map = function(arr, fn) { - return Promise.all( - arr.map(function(i, el, list) { - return Promise.try(fn, [i, el, list]); - }) - ); - }; - Promise.each = function(arr, fn) { - const queue = arr.slice(0); - let i = 0; - return (function next() { - if (!queue.length) return arr; - return Promise.try(fn, [arr.shift(), i++]).then(next); - })(); - }; - Promise.is = function(obj) { - // $q doesn't create instances of any constructor, promises are just objects with a then function - // https://github.com/angular/angular.js/blob/58f5da86645990ef984353418cd1ed83213b111e/src/ng/q.js#L335 - return obj && typeof obj.then === 'function'; - }; - Promise.halt = _.once(function() { - const promise = new Promise(() => {}); - promise.then = _.constant(promise); - promise.catch = _.constant(promise); - return promise; - }); - Promise.try = function(fn, args, ctx) { - if (typeof fn !== 'function') { - return Promise.reject(new TypeError('fn must be a function')); - } - - let value; - - if (Array.isArray(args)) { - try { - value = fn.apply(ctx, args); - } catch (e) { - return Promise.reject(e); - } - } else { - try { - value = fn.call(ctx, args); - } catch (e) { - return Promise.reject(e); - } - } - - return Promise.resolve(value); - }; - Promise.fromNode = function(takesCbFn) { - return new Promise(function(resolve, reject) { - takesCbFn(function(err, ...results) { - if (err) reject(err); - else if (results.length > 1) resolve(results); - else resolve(results[0]); - }); - }); - }; - Promise.race = function(iterable) { - return new Promise((resolve, reject) => { - for (const i of iterable) { - Promise.resolve(i).then(resolve, reject); - } - }); - }; - - return Promise; -} diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.ts deleted file mode 100644 index 208b7e2acdb0f..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/legacy_imports.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. - */ - -/** - * Last remaining 'ui/*' imports that will eventually be shimmed with their np alternatives - */ - -export { npSetup, npStart } from 'ui/new_platform'; -// @ts-ignore -export { GlobalStateProvider } from 'ui/state_management/global_state'; -// @ts-ignore -export { StateManagementConfigProvider } from 'ui/state_management/config_provider'; -// @ts-ignore -export { AppStateProvider } from 'ui/state_management/app_state'; -// @ts-ignore -export { EventsProvider } from 'ui/events'; -// @ts-ignore -export { KbnUrlProvider } from 'ui/url'; -export { registerTimefilterWithGlobalStateFactory } from 'ui/timefilter/setup_router'; diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/capabilities.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/ui/capabilities.ts deleted file mode 100644 index 5aff302501401..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/capabilities.ts +++ /dev/null @@ -1,8 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import { npStart } from '../legacy_imports'; -export const capabilities = { get: () => npStart.core.application.capabilities }; diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/chrome.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/ui/chrome.ts deleted file mode 100644 index f0c5bacabecbf..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/chrome.ts +++ /dev/null @@ -1,33 +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 angular from 'angular'; -import { npStart, npSetup } from '../legacy_imports'; - -type OptionalInjector = void | angular.auto.IInjectorService; - -class Chrome { - private injector?: OptionalInjector; - - public setInjector = (injector: OptionalInjector): void => void (this.injector = injector); - public dangerouslyGetActiveInjector = (): OptionalInjector => this.injector; - - public getBasePath = (): string => npStart.core.http.basePath.get(); - - public getInjected = (name?: string, defaultValue?: any): string | unknown => { - const { getInjectedVar, getInjectedVars } = npSetup.core.injectedMetadata; - return name ? getInjectedVar(name, defaultValue) : getInjectedVars(); - }; - - public get breadcrumbs() { - const set = (...args: any[]) => npStart.core.chrome.setBreadcrumbs.apply(this, args as any); - return { set }; - } -} - -const chrome = new Chrome(); - -export default chrome; // eslint-disable-line import/no-default-export diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/modules.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/ui/modules.ts deleted file mode 100644 index 70201a7906110..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/modules.ts +++ /dev/null @@ -1,55 +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 angular from 'angular'; - -type PrivateProvider = (...args: any) => any; -interface Provider { - name: string; - provider: PrivateProvider; -} - -class Modules { - private _services: Provider[] = []; - private _filters: Provider[] = []; - private _directives: Provider[] = []; - - public get = (_name: string, _dep?: string[]) => { - return this; - }; - - public service = (...args: any) => { - this._services.push(args); - }; - - public filter = (...args: any) => { - this._filters.push(args); - }; - - public directive = (...args: any) => { - this._directives.push(args); - }; - - public addToModule = () => { - angular.module('monitoring/services', []); - angular.module('monitoring/filters', []); - angular.module('monitoring/directives', []); - - this._services.forEach(args => { - angular.module('monitoring/services').service.apply(null, args as any); - }); - - this._filters.forEach(args => { - angular.module('monitoring/filters').filter.apply(null, args as any); - }); - - this._directives.forEach(args => { - angular.module('monitoring/directives').directive.apply(null, args as any); - }); - }; -} - -export const uiModules = new Modules(); diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/timefilter.ts b/x-pack/legacy/plugins/monitoring/public/np_imports/ui/timefilter.ts deleted file mode 100644 index e28699bd126b9..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/timefilter.ts +++ /dev/null @@ -1,31 +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 { IModule, IRootScopeService } from 'angular'; -import { npStart, registerTimefilterWithGlobalStateFactory } from '../legacy_imports'; - -const { - core: { uiSettings }, -} = npStart; -export const { timefilter } = npStart.plugins.data.query.timefilter; - -uiSettings.overrideLocalDefault( - 'timepicker:refreshIntervalDefaults', - JSON.stringify({ value: 10000, pause: false }) -); -uiSettings.overrideLocalDefault( - 'timepicker:timeDefaults', - JSON.stringify({ from: 'now-1h', to: 'now' }) -); - -export const registerTimefilterWithGlobalState = (app: IModule) => { - app.run((globalState: any, $rootScope: IRootScopeService) => { - globalState.fetch(); - globalState.$inheritedGlobalState = true; - globalState.save(); - registerTimefilterWithGlobalStateFactory(timefilter, globalState, $rootScope); - }); -}; diff --git a/x-pack/legacy/plugins/monitoring/public/np_ready/plugin.ts b/x-pack/legacy/plugins/monitoring/public/np_ready/plugin.ts deleted file mode 100644 index 5598a7a51cf42..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/np_ready/plugin.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. - */ - -import { App, CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'kibana/public'; - -export class MonitoringPlugin implements Plugin { - constructor(ctx: PluginInitializerContext) {} - - public setup(core: CoreSetup, plugins: any) { - const app: App = { - id: 'monitoring', - title: 'Monitoring', - mount: async (context, params) => { - const { AngularApp } = await import('../np_imports/angular'); - const monitoringApp = new AngularApp(context, params); - return monitoringApp.destroy; - }, - }; - - core.application.register(app); - } - - public start(core: CoreStart, plugins: any) {} - public stop() {} -} diff --git a/x-pack/legacy/plugins/monitoring/public/register_feature.ts b/x-pack/legacy/plugins/monitoring/public/register_feature.ts deleted file mode 100644 index 9b72e01a19394..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/register_feature.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 { i18n } from '@kbn/i18n'; -import chrome from 'ui/chrome'; -import { npSetup } from 'ui/new_platform'; -import { FeatureCatalogueCategory } from '../../../../../src/plugins/home/public'; - -const { - plugins: { home }, -} = npSetup; - -if (chrome.getInjected('monitoringUiEnabled')) { - home.featureCatalogue.register({ - id: 'monitoring', - title: i18n.translate('xpack.monitoring.monitoringTitle', { - defaultMessage: 'Monitoring', - }), - description: i18n.translate('xpack.monitoring.monitoringDescription', { - defaultMessage: 'Track the real-time health and performance of your Elastic Stack.', - }), - icon: 'monitoringApp', - path: '/app/monitoring', - showOnHomePage: true, - category: FeatureCatalogueCategory.ADMIN, - }); -} diff --git a/x-pack/legacy/plugins/monitoring/public/services/breadcrumbs.js b/x-pack/legacy/plugins/monitoring/public/services/breadcrumbs.js deleted file mode 100644 index d0fe600386307..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/services/breadcrumbs.js +++ /dev/null @@ -1,10 +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 { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -import { breadcrumbsProvider } from './breadcrumbs_provider'; -const uiModule = uiModules.get('monitoring/breadcrumbs', []); -uiModule.service('breadcrumbs', breadcrumbsProvider); diff --git a/x-pack/legacy/plugins/monitoring/public/services/executor.js b/x-pack/legacy/plugins/monitoring/public/services/executor.js deleted file mode 100644 index 5004cd0238012..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/services/executor.js +++ /dev/null @@ -1,10 +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 { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -import { executorProvider } from './executor_provider'; -const uiModule = uiModules.get('monitoring/executor', []); -uiModule.service('$executor', executorProvider); diff --git a/x-pack/legacy/plugins/monitoring/public/views/kibana/instance/index.js b/x-pack/legacy/plugins/monitoring/public/views/kibana/instance/index.js deleted file mode 100644 index 6535bd7410445..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/views/kibana/instance/index.js +++ /dev/null @@ -1,153 +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. - */ - -/* - * Kibana Instance - */ -import React from 'react'; -import { get } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { - EuiPage, - EuiPageBody, - EuiPageContent, - EuiSpacer, - EuiFlexGrid, - EuiFlexItem, - EuiPanel, -} from '@elastic/eui'; -import { MonitoringTimeseriesContainer } from '../../../components/chart'; -import { DetailStatus } from 'plugins/monitoring/components/kibana/detail_status'; -import { I18nContext } from 'ui/i18n'; -import { MonitoringViewBaseController } from '../../base_controller'; -import { CODE_PATH_KIBANA } from '../../../../common/constants'; - -function getPageData($injector) { - const $http = $injector.get('$http'); - const globalState = $injector.get('globalState'); - const $route = $injector.get('$route'); - const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/kibana/${$route.current.params.uuid}`; - const timeBounds = timefilter.getBounds(); - - return $http - .post(url, { - ccs: globalState.ccs, - timeRange: { - min: timeBounds.min.toISOString(), - max: timeBounds.max.toISOString(), - }, - }) - .then(response => response.data) - .catch(err => { - const Private = $injector.get('Private'); - const ajaxErrorHandlers = Private(ajaxErrorHandlersProvider); - return ajaxErrorHandlers(err); - }); -} - -uiRoutes.when('/kibana/instances/:uuid', { - template, - resolve: { - clusters(Private) { - const routeInit = Private(routeInitProvider); - return routeInit({ codePaths: [CODE_PATH_KIBANA] }); - }, - pageData: getPageData, - }, - controllerAs: 'monitoringKibanaInstanceApp', - controller: class extends MonitoringViewBaseController { - constructor($injector, $scope) { - super({ - title: `Kibana - ${get($scope.pageData, 'kibanaSummary.name')}`, - defaultData: {}, - getPageData, - reactNodeId: 'monitoringKibanaInstanceApp', - $scope, - $injector, - }); - - $scope.$watch( - () => this.data, - data => { - if (!data || !data.metrics) { - return; - } - - this.setTitle(`Kibana - ${get(data, 'kibanaSummary.name')}`); - - this.renderReact( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); - } - ); - } - }, -}); diff --git a/x-pack/legacy/plugins/monitoring/public/views/loading/index.html b/x-pack/legacy/plugins/monitoring/public/views/loading/index.html deleted file mode 100644 index 11da26a0ceed2..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/views/loading/index.html +++ /dev/null @@ -1,5 +0,0 @@ - -
-
-
-
diff --git a/x-pack/legacy/plugins/monitoring/public/views/loading/index.js b/x-pack/legacy/plugins/monitoring/public/views/loading/index.js deleted file mode 100644 index 0488683845a7d..0000000000000 --- a/x-pack/legacy/plugins/monitoring/public/views/loading/index.js +++ /dev/null @@ -1,51 +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 { render, unmountComponentAtNode } from 'react-dom'; -import { PageLoading } from 'plugins/monitoring/components'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { I18nContext } from 'ui/i18n'; -import template from './index.html'; -import { CODE_PATH_LICENSE } from '../../../common/constants'; - -const REACT_DOM_ID = 'monitoringLoadingReactApp'; - -uiRoutes.when('/loading', { - template, - controller: class { - constructor($injector, $scope) { - const monitoringClusters = $injector.get('monitoringClusters'); - const kbnUrl = $injector.get('kbnUrl'); - - $scope.$on('$destroy', () => { - unmountComponentAtNode(document.getElementById(REACT_DOM_ID)); - }); - - $scope.$$postDigest(() => { - this.renderReact(); - }); - - monitoringClusters(undefined, undefined, [CODE_PATH_LICENSE]).then(clusters => { - if (clusters && clusters.length) { - kbnUrl.changePath('/home'); - return; - } - kbnUrl.changePath('/no-data'); - return; - }); - } - - renderReact() { - render( - - - , - document.getElementById(REACT_DOM_ID) - ); - } - }, -}); diff --git a/x-pack/legacy/plugins/monitoring/ui_exports.js b/x-pack/legacy/plugins/monitoring/ui_exports.js deleted file mode 100644 index e0c04411ef46b..0000000000000 --- a/x-pack/legacy/plugins/monitoring/ui_exports.js +++ /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 { i18n } from '@kbn/i18n'; -import { resolve } from 'path'; -import { - MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS, - KIBANA_ALERTING_ENABLED, -} from './common/constants'; -import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; - -/** - * Configuration of dependency objects for the UI, which are needed for the - * Monitoring UI app and views and data for outside the monitoring - * app (injectDefaultVars and hacks) - * @return {Object} data per Kibana plugin uiExport schema - */ -export const getUiExports = () => { - const uiSettingDefaults = {}; - if (KIBANA_ALERTING_ENABLED) { - uiSettingDefaults[MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS] = { - name: i18n.translate('xpack.monitoring.alertingEmailAddress.name', { - defaultMessage: 'Alerting email address', - }), - value: '', - description: i18n.translate('xpack.monitoring.alertingEmailAddress.description', { - defaultMessage: `The default email address to receive alerts from Stack Monitoring`, - }), - category: ['monitoring'], - }; - } - - return { - app: { - title: i18n.translate('xpack.monitoring.stackMonitoringTitle', { - defaultMessage: 'Stack Monitoring', - }), - order: 9002, - description: i18n.translate('xpack.monitoring.uiExportsDescription', { - defaultMessage: 'Monitoring for Elastic Stack', - }), - icon: 'plugins/monitoring/icons/monitoring.svg', - euiIconType: 'monitoringApp', - linkToLastSubUrl: false, - main: 'plugins/monitoring/legacy', - category: DEFAULT_APP_CATEGORIES.management, - }, - injectDefaultVars(server) { - const config = server.config(); - return { - monitoringUiEnabled: config.get('monitoring.ui.enabled'), - monitoringLegacyEmailAddress: config.get( - 'monitoring.cluster_alerts.email_notifications.email_address' - ), - }; - }, - uiSettingDefaults, - hacks: ['plugins/monitoring/hacks/toggle_app_link_in_nav'], - home: ['plugins/monitoring/register_feature'], - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - }; -}; diff --git a/x-pack/legacy/plugins/xpack_main/server/routes/api/v1/settings.js b/x-pack/legacy/plugins/xpack_main/server/routes/api/v1/settings.js index c830fc9fcd483..99071a2f85e13 100644 --- a/x-pack/legacy/plugins/xpack_main/server/routes/api/v1/settings.js +++ b/x-pack/legacy/plugins/xpack_main/server/routes/api/v1/settings.js @@ -6,7 +6,7 @@ import { boomify } from 'boom'; import { get } from 'lodash'; -import { KIBANA_SETTINGS_TYPE } from '../../../../../monitoring/common/constants'; +import { KIBANA_SETTINGS_TYPE } from '../../../../../../../plugins/monitoring/common/constants'; const getClusterUuid = async callCluster => { const { cluster_uuid: uuid } = await callCluster('info', { filterPath: 'cluster_uuid' }); diff --git a/x-pack/plugins/monitoring/kibana.json b/x-pack/plugins/monitoring/kibana.json index bbdf1a2e7cb76..115cc08871ea4 100644 --- a/x-pack/plugins/monitoring/kibana.json +++ b/x-pack/plugins/monitoring/kibana.json @@ -3,8 +3,8 @@ "version": "8.0.0", "kibanaVersion": "kibana", "configPath": ["monitoring"], - "requiredPlugins": ["licensing", "features"], - "optionalPlugins": ["alerting", "actions", "infra", "telemetryCollectionManager", "usageCollection"], + "requiredPlugins": ["licensing", "features", "data", "navigation", "kibanaLegacy"], + "optionalPlugins": ["alerting", "actions", "infra", "telemetryCollectionManager", "usageCollection", "home"], "server": true, - "ui": false + "ui": true } diff --git a/x-pack/legacy/plugins/monitoring/public/_hacks.scss b/x-pack/plugins/monitoring/public/_hacks.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/_hacks.scss rename to x-pack/plugins/monitoring/public/_hacks.scss diff --git a/x-pack/plugins/monitoring/public/angular/app_modules.ts b/x-pack/plugins/monitoring/public/angular/app_modules.ts new file mode 100644 index 0000000000000..3fa79cedf4ce7 --- /dev/null +++ b/x-pack/plugins/monitoring/public/angular/app_modules.ts @@ -0,0 +1,248 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import angular, { IWindowService } from 'angular'; +import '../views/all'; +// required for `ngSanitize` angular module +import 'angular-sanitize'; +import 'angular-route'; +import '../index.scss'; +import { capitalize } from 'lodash'; +import { i18nDirective, i18nFilter, I18nProvider } from '@kbn/i18n/angular'; +import { AppMountContext } from 'kibana/public'; +import { Storage } from '../../../../../src/plugins/kibana_utils/public'; +import { + createTopNavDirective, + createTopNavHelper, +} from '../../../../../src/plugins/kibana_legacy/public'; +import { MonitoringPluginDependencies } from '../types'; +import { GlobalState } from '../url_state'; +import { getSafeForExternalLink } from '../lib/get_safe_for_external_link'; + +// @ts-ignore +import { formatNumber, formatMetric } from '../lib/format_number'; +// @ts-ignore +import { extractIp } from '../lib/extract_ip'; +// @ts-ignore +import { PrivateProvider } from './providers/private'; +// @ts-ignore +import { KbnUrlProvider } from './providers/url'; +// @ts-ignore +import { breadcrumbsProvider } from '../services/breadcrumbs'; +// @ts-ignore +import { monitoringClustersProvider } from '../services/clusters'; +// @ts-ignore +import { executorProvider } from '../services/executor'; +// @ts-ignore +import { featuresProvider } from '../services/features'; +// @ts-ignore +import { licenseProvider } from '../services/license'; +// @ts-ignore +import { titleProvider } from '../services/title'; +// @ts-ignore +import { monitoringBeatsBeatProvider } from '../directives/beats/beat'; +// @ts-ignore +import { monitoringBeatsOverviewProvider } from '../directives/beats/overview'; +// @ts-ignore +import { monitoringMlListingProvider } from '../directives/elasticsearch/ml_job_listing'; +// @ts-ignore +import { monitoringMainProvider } from '../directives/main'; + +export const appModuleName = 'monitoring'; + +type IPrivate = (provider: (...injectable: unknown[]) => T) => T; + +const thirdPartyAngularDependencies = ['ngSanitize', 'ngRoute', 'react', 'ui.bootstrap']; + +export const localAppModule = ({ + core, + data: { query }, + navigation, + externalConfig, +}: MonitoringPluginDependencies) => { + createLocalI18nModule(); + createLocalPrivateModule(); + createLocalStorage(); + createLocalConfigModule(core); + createLocalKbnUrlModule(); + createLocalStateModule(query); + createLocalTopNavModule(navigation); + createHrefModule(core); + createMonitoringAppServices(); + createMonitoringAppDirectives(); + createMonitoringAppConfigConstants(externalConfig); + createMonitoringAppFilters(); + + const appModule = angular.module(appModuleName, [ + ...thirdPartyAngularDependencies, + 'monitoring/I18n', + 'monitoring/Private', + 'monitoring/KbnUrl', + 'monitoring/Storage', + 'monitoring/Config', + 'monitoring/State', + 'monitoring/TopNav', + 'monitoring/href', + 'monitoring/constants', + 'monitoring/services', + 'monitoring/filters', + 'monitoring/directives', + ]); + return appModule; +}; + +function createMonitoringAppConfigConstants(keys: MonitoringPluginDependencies['externalConfig']) { + let constantsModule = angular.module('monitoring/constants', []); + keys.map(([key, value]) => (constantsModule = constantsModule.constant(key as string, value))); +} + +function createLocalStateModule(query: any) { + angular + .module('monitoring/State', ['monitoring/Private']) + .service('globalState', function( + Private: IPrivate, + $rootScope: ng.IRootScopeService, + $location: ng.ILocationService + ) { + function GlobalStateProvider(this: any) { + const state = new GlobalState(query, $rootScope, $location, this); + const initialState: any = state.getState(); + for (const key in initialState) { + if (!initialState.hasOwnProperty(key)) { + continue; + } + this[key] = initialState[key]; + } + this.save = () => { + const newState = { ...this }; + delete newState.save; + state.setState(newState); + }; + } + return Private(GlobalStateProvider); + }); +} + +function createLocalKbnUrlModule() { + angular + .module('monitoring/KbnUrl', ['monitoring/Private', 'ngRoute']) + .service('kbnUrl', function(Private: IPrivate) { + return Private(KbnUrlProvider); + }); +} + +function createMonitoringAppServices() { + angular + .module('monitoring/services', ['monitoring/Private']) + .service('breadcrumbs', function(Private: IPrivate) { + return Private(breadcrumbsProvider); + }) + .service('monitoringClusters', function(Private: IPrivate) { + return Private(monitoringClustersProvider); + }) + .service('$executor', function(Private: IPrivate) { + return Private(executorProvider); + }) + .service('features', function(Private: IPrivate) { + return Private(featuresProvider); + }) + .service('license', function(Private: IPrivate) { + return Private(licenseProvider); + }) + .service('title', function(Private: IPrivate) { + return Private(titleProvider); + }); +} + +function createMonitoringAppDirectives() { + angular + .module('monitoring/directives', []) + .directive('monitoringBeatsBeat', monitoringBeatsBeatProvider) + .directive('monitoringBeatsOverview', monitoringBeatsOverviewProvider) + .directive('monitoringMlListing', monitoringMlListingProvider) + .directive('monitoringMain', monitoringMainProvider); +} + +function createMonitoringAppFilters() { + angular + .module('monitoring/filters', []) + .filter('capitalize', function() { + return function(input: string) { + return capitalize(input?.toLowerCase()); + }; + }) + .filter('formatNumber', function() { + return formatNumber; + }) + .filter('formatMetric', function() { + return formatMetric; + }) + .filter('extractIp', function() { + return extractIp; + }); +} + +function createLocalConfigModule(core: MonitoringPluginDependencies['core']) { + angular.module('monitoring/Config', []).provider('config', function() { + return { + $get: () => ({ + get: (key: string) => core.uiSettings?.get(key), + }), + }; + }); +} + +function createLocalStorage() { + angular + .module('monitoring/Storage', []) + .service('localStorage', function($window: IWindowService) { + return new Storage($window.localStorage); + }) + .service('sessionStorage', function($window: IWindowService) { + return new Storage($window.sessionStorage); + }) + .service('sessionTimeout', function() { + return {}; + }); +} + +function createLocalPrivateModule() { + angular.module('monitoring/Private', []).provider('Private', PrivateProvider); +} + +function createLocalTopNavModule({ ui }: MonitoringPluginDependencies['navigation']) { + angular + .module('monitoring/TopNav', ['react']) + .directive('kbnTopNav', createTopNavDirective) + .directive('kbnTopNavHelper', createTopNavHelper(ui)); +} + +function createLocalI18nModule() { + angular + .module('monitoring/I18n', []) + .provider('i18n', I18nProvider) + .filter('i18n', i18nFilter) + .directive('i18nId', i18nDirective); +} + +function createHrefModule(core: AppMountContext['core']) { + const name: string = 'kbnHref'; + angular.module('monitoring/href', []).directive(name, function() { + return { + restrict: 'A', + link: { + pre: (_$scope, _$el, $attr) => { + $attr.$observe(name, val => { + if (val) { + const url = getSafeForExternalLink(val as string); + $attr.$set('href', core.http.basePath.prepend(url)); + } + }); + }, + }, + }; + }); +} diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/routes.ts b/x-pack/plugins/monitoring/public/angular/helpers/routes.ts similarity index 62% rename from x-pack/legacy/plugins/monitoring/public/np_imports/ui/routes.ts rename to x-pack/plugins/monitoring/public/angular/helpers/routes.ts index 22da56a8d184a..b9307e8594a7a 100644 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/routes.ts +++ b/x-pack/plugins/monitoring/public/angular/helpers/routes.ts @@ -4,36 +4,35 @@ * you may not use this file except in compliance with the Elastic License. */ -type RouteObject = [string, any]; +type RouteObject = [string, { reloadOnSearch: boolean }]; interface Redirect { redirectTo: string; } class Routes { - private _routes: RouteObject[] = []; - private _redirect?: Redirect; + private routes: RouteObject[] = []; + public redirect?: Redirect = { redirectTo: '/no-data' }; public when = (...args: RouteObject) => { const [, routeOptions] = args; routeOptions.reloadOnSearch = false; - this._routes.push(args); + this.routes.push(args); return this; }; public otherwise = (redirect: Redirect) => { - this._redirect = redirect; + this.redirect = redirect; return this; }; public addToProvider = ($routeProvider: any) => { - this._routes.forEach(args => { + this.routes.forEach(args => { $routeProvider.when.apply(this, args); }); - if (this._redirect) { - $routeProvider.otherwise(this._redirect); + if (this.redirect) { + $routeProvider.otherwise(this.redirect); } }; } -const uiRoutes = new Routes(); -export default uiRoutes; // eslint-disable-line import/no-default-export +export const uiRoutes = new Routes(); diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/ui/utils.ts b/x-pack/plugins/monitoring/public/angular/helpers/utils.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/np_imports/ui/utils.ts rename to x-pack/plugins/monitoring/public/angular/helpers/utils.ts diff --git a/x-pack/plugins/monitoring/public/angular/index.ts b/x-pack/plugins/monitoring/public/angular/index.ts new file mode 100644 index 0000000000000..b371503fdb7c9 --- /dev/null +++ b/x-pack/plugins/monitoring/public/angular/index.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 angular, { IModule } from 'angular'; +import { uiRoutes } from './helpers/routes'; +import { Legacy } from '../legacy_shims'; +import { configureAppAngularModule } from '../../../../../src/plugins/kibana_legacy/public'; +import { localAppModule, appModuleName } from './app_modules'; + +import { MonitoringPluginDependencies } from '../types'; + +const APP_WRAPPER_CLASS = 'monitoringApplicationWrapper'; +export class AngularApp { + private injector?: angular.auto.IInjectorService; + + constructor(deps: MonitoringPluginDependencies) { + const { + core, + element, + data, + navigation, + isCloud, + pluginInitializerContext, + externalConfig, + } = deps; + const app: IModule = localAppModule(deps); + app.run(($injector: angular.auto.IInjectorService) => { + this.injector = $injector; + Legacy.init( + { core, element, data, navigation, isCloud, pluginInitializerContext, externalConfig }, + this.injector + ); + }); + + app.config(($routeProvider: unknown) => uiRoutes.addToProvider($routeProvider)); + + const np = { core, env: pluginInitializerContext.env }; + configureAppAngularModule(app, np, true); + const appElement = document.createElement('div'); + appElement.setAttribute('style', 'height: 100%'); + appElement.innerHTML = '
'; + + if (!element.classList.contains(APP_WRAPPER_CLASS)) { + element.classList.add(APP_WRAPPER_CLASS); + } + + angular.bootstrap(appElement, [appModuleName]); + angular.element(element).append(appElement); + } + + public destroy = () => { + if (this.injector) { + this.injector.get('$rootScope').$destroy(); + } + }; + + public applyScope = () => { + if (!this.injector) { + return; + } + + const rootScope = this.injector.get('$rootScope'); + rootScope.$applyAsync(); + }; +} diff --git a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/providers/private.js b/x-pack/plugins/monitoring/public/angular/providers/private.js similarity index 99% rename from x-pack/legacy/plugins/monitoring/public/np_imports/angular/providers/private.js rename to x-pack/plugins/monitoring/public/angular/providers/private.js index 6eae978b828b3..e456f2617f7b8 100644 --- a/x-pack/legacy/plugins/monitoring/public/np_imports/angular/providers/private.js +++ b/x-pack/plugins/monitoring/public/angular/providers/private.js @@ -193,4 +193,6 @@ export function PrivateProvider() { return Private; }, ]; + + return provider; } diff --git a/x-pack/plugins/monitoring/public/angular/providers/url.js b/x-pack/plugins/monitoring/public/angular/providers/url.js new file mode 100644 index 0000000000000..57b63708b546e --- /dev/null +++ b/x-pack/plugins/monitoring/public/angular/providers/url.js @@ -0,0 +1,217 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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'; + +export function KbnUrlProvider($injector, $location, $rootScope, $parse) { + /** + * the `kbnUrl` service was created to smooth over some of the + * inconsistent behavior that occurs when modifying the url via + * the `$location` api. In general it is recommended that you use + * the `kbnUrl` service any time you want to modify the url. + * + * "features" that `kbnUrl` does it's best to guarantee, which + * are not guaranteed with the `$location` service: + * - calling `kbnUrl.change()` with a url that resolves to the current + * route will force a full transition (rather than just updating the + * properties of the $route object) + * + * Additional features of `kbnUrl` + * - parameterized urls + * - easily include an app state with the url + * + * @type {KbnUrl} + */ + const self = this; + + /** + * Navigate to a url + * + * @param {String} url - the new url, can be a template. See #eval + * @param {Object} [paramObj] - optional set of parameters for the url template + * @return {undefined} + */ + self.change = function(url, paramObj, appState) { + self._changeLocation('url', url, paramObj, false, appState); + }; + + /** + * Same as #change except only changes the url's path, + * leaving the search string and such intact + * + * @param {String} path - the new path, can be a template. See #eval + * @param {Object} [paramObj] - optional set of parameters for the path template + * @return {undefined} + */ + self.changePath = function(path, paramObj) { + self._changeLocation('path', path, paramObj); + }; + + /** + * Same as #change except that it removes the current url from history + * + * @param {String} url - the new url, can be a template. See #eval + * @param {Object} [paramObj] - optional set of parameters for the url template + * @return {undefined} + */ + self.redirect = function(url, paramObj, appState) { + self._changeLocation('url', url, paramObj, true, appState); + }; + + /** + * Same as #redirect except only changes the url's path, + * leaving the search string and such intact + * + * @param {String} path - the new path, can be a template. See #eval + * @param {Object} [paramObj] - optional set of parameters for the path template + * @return {undefined} + */ + self.redirectPath = function(path, paramObj) { + self._changeLocation('path', path, paramObj, true); + }; + + /** + * Evaluate a url template. templates can contain double-curly wrapped + * expressions that are evaluated in the context of the paramObj + * + * @param {String} template - the url template to evaluate + * @param {Object} [paramObj] - the variables to expose to the template + * @return {String} - the evaluated result + * @throws {Error} If any of the expressions can't be parsed. + */ + self.eval = function(template, paramObj) { + paramObj = paramObj || {}; + + return template.replace(/\{\{([^\}]+)\}\}/g, function(match, expr) { + // remove filters + const key = expr.split('|')[0].trim(); + + // verify that the expression can be evaluated + const p = $parse(key)(paramObj); + + // if evaluation can't be made, throw + if (_.isUndefined(p)) { + throw new Error(`Replacement failed, unresolved expression: ${expr}`); + } + + return encodeURIComponent($parse(expr)(paramObj)); + }); + }; + + /** + * convert an object's route to an href, compatible with + * window.location.href= and + * + * @param {Object} obj - any object that list's it's routes at obj.routes{} + * @param {string} route - the route name + * @return {string} - the computed href + */ + self.getRouteHref = function(obj, route) { + return '#' + self.getRouteUrl(obj, route); + }; + + /** + * convert an object's route to a url, compatible with url.change() or $location.url() + * + * @param {Object} obj - any object that list's it's routes at obj.routes{} + * @param {string} route - the route name + * @return {string} - the computed url + */ + self.getRouteUrl = function(obj, route) { + const template = obj && obj.routes && obj.routes[route]; + if (template) return self.eval(template, obj); + }; + + /** + * Similar to getRouteUrl, supports objects which list their routes, + * and redirects to the named route. See #redirect + * + * @param {Object} obj - any object that list's it's routes at obj.routes{} + * @param {string} route - the route name + * @return {undefined} + */ + self.redirectToRoute = function(obj, route) { + self.redirect(self.getRouteUrl(obj, route)); + }; + + /** + * Similar to getRouteUrl, supports objects which list their routes, + * and changes the url to the named route. See #change + * + * @param {Object} obj - any object that list's it's routes at obj.routes{} + * @param {string} route - the route name + * @return {undefined} + */ + self.changeToRoute = function(obj, route) { + self.change(self.getRouteUrl(obj, route)); + }; + + /** + * Removes the given parameter from the url. Does so without modifying the browser + * history. + * @param param + */ + self.removeParam = function(param) { + $location.search(param, null).replace(); + }; + + ///// + // private api + ///// + let reloading; + + self._changeLocation = function(type, url, paramObj, replace, appState) { + const prev = { + path: $location.path(), + search: $location.search(), + }; + + url = self.eval(url, paramObj); + $location[type](url); + if (replace) $location.replace(); + + if (appState) { + $location.search(appState.getQueryParamName(), appState.toQueryParam()); + } + + const next = { + path: $location.path(), + search: $location.search(), + }; + + if ($injector.has('$route')) { + const $route = $injector.get('$route'); + + if (self._shouldForceReload(next, prev, $route)) { + reloading = $rootScope.$on('$locationChangeSuccess', function() { + // call the "unlisten" function returned by $on + reloading(); + reloading = false; + + $route.reload(); + }); + } + } + }; + + // determine if the router will automatically reload the route + self._shouldForceReload = function(next, prev, $route) { + if (reloading) return false; + + const route = $route.current && $route.current.$$route; + if (!route) return false; + + // for the purposes of determining whether the router will + // automatically be reloading, '' and '/' are equal + const nextPath = next.path || '/'; + const prevPath = prev.path || '/'; + if (nextPath !== prevPath) return false; + + const reloadOnSearch = route.reloadOnSearch; + const searchSame = _.isEqual(next.search, prev.search); + return (reloadOnSearch && searchSame) || !reloadOnSearch; + }; +} diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/__snapshots__/status.test.tsx.snap b/x-pack/plugins/monitoring/public/components/alerts/__snapshots__/status.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/__snapshots__/status.test.tsx.snap rename to x-pack/plugins/monitoring/public/components/alerts/__snapshots__/status.test.tsx.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/__tests__/map_severity.js b/x-pack/plugins/monitoring/public/components/alerts/__tests__/map_severity.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/__tests__/map_severity.js rename to x-pack/plugins/monitoring/public/components/alerts/__tests__/map_severity.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/alerts.js b/x-pack/plugins/monitoring/public/components/alerts/alerts.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/alerts.js rename to x-pack/plugins/monitoring/public/components/alerts/alerts.js index 95c1af5549198..a86fdb1041a5c 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/alerts/alerts.js +++ b/x-pack/plugins/monitoring/public/components/alerts/alerts.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import chrome from '../../np_imports/ui/chrome'; +import { Legacy } from '../../legacy_shims'; import { capitalize, get } from 'lodash'; import { formatDateTimeLocal } from '../../../common/formatting'; import { formatTimestampToDuration } from '../../../common'; @@ -16,8 +16,8 @@ import { ALERT_TYPE_CLUSTER_STATE, } from '../../../common/constants'; import { mapSeverity } from './map_severity'; -import { FormattedAlert } from 'plugins/monitoring/components/alerts/formatted_alert'; -import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; +import { FormattedAlert } from '../../components/alerts/formatted_alert'; +import { EuiMonitoringTable } from '../../components/table'; import { EuiHealth, EuiIcon, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; @@ -162,7 +162,7 @@ export const Alerts = ({ alerts, angular, sorting, pagination, onTableChange }) category: get(alert, 'metadata.link', get(alert, 'type', null)), })); - const injector = chrome.dangerouslyGetActiveInjector(); + const injector = Legacy.shims.getAngularInjector(); const timezone = injector.get('config').get('dateFormat:tz'); return ( diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/__snapshots__/configuration.test.tsx.snap b/x-pack/plugins/monitoring/public/components/alerts/configuration/__snapshots__/configuration.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/__snapshots__/configuration.test.tsx.snap rename to x-pack/plugins/monitoring/public/components/alerts/configuration/__snapshots__/configuration.test.tsx.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step1.test.tsx.snap b/x-pack/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step1.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step1.test.tsx.snap rename to x-pack/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step1.test.tsx.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step2.test.tsx.snap b/x-pack/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step2.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step2.test.tsx.snap rename to x-pack/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step2.test.tsx.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step3.test.tsx.snap b/x-pack/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step3.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step3.test.tsx.snap rename to x-pack/plugins/monitoring/public/components/alerts/configuration/__snapshots__/step3.test.tsx.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/configuration.test.tsx b/x-pack/plugins/monitoring/public/components/alerts/configuration/configuration.test.tsx similarity index 91% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/configuration.test.tsx rename to x-pack/plugins/monitoring/public/components/alerts/configuration/configuration.test.tsx index 6b7e2391e0301..2c2d7c6464e1b 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/configuration.test.tsx +++ b/x-pack/plugins/monitoring/public/components/alerts/configuration/configuration.test.tsx @@ -7,11 +7,15 @@ import React from 'react'; import { mockUseEffects } from '../../../jest.helpers'; import { shallow, ShallowWrapper } from 'enzyme'; -import { kfetch } from 'ui/kfetch'; +import { Legacy } from '../../../legacy_shims'; import { AlertsConfiguration, AlertsConfigurationProps } from './configuration'; -jest.mock('ui/kfetch', () => ({ - kfetch: jest.fn(), +jest.mock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch: jest.fn(), + }, + }, })); const defaultProps: AlertsConfigurationProps = { @@ -61,7 +65,7 @@ describe('Configuration', () => { beforeEach(async () => { mockUseEffects(2); - (kfetch as jest.Mock).mockImplementation(() => { + (Legacy.shims.kfetch as jest.Mock).mockImplementation(() => { return { data: [ { @@ -101,7 +105,7 @@ describe('Configuration', () => { describe('edit action', () => { let component: ShallowWrapper; beforeEach(async () => { - (kfetch as jest.Mock).mockImplementation(() => { + (Legacy.shims.kfetch as jest.Mock).mockImplementation(() => { return { data: [], }; @@ -124,7 +128,7 @@ describe('Configuration', () => { describe('no email address', () => { let component: ShallowWrapper; beforeEach(async () => { - (kfetch as jest.Mock).mockImplementation(() => { + (Legacy.shims.kfetch as jest.Mock).mockImplementation(() => { return { data: [ { diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/configuration.tsx b/x-pack/plugins/monitoring/public/components/alerts/configuration/configuration.tsx similarity index 96% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/configuration.tsx rename to x-pack/plugins/monitoring/public/components/alerts/configuration/configuration.tsx index eaa474ba177b1..61f86b0f9b609 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/configuration.tsx +++ b/x-pack/plugins/monitoring/public/components/alerts/configuration/configuration.tsx @@ -5,10 +5,10 @@ */ import React, { ReactNode } from 'react'; -import { kfetch } from 'ui/kfetch'; import { EuiSteps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ActionResult } from '../../../../../../../plugins/actions/common'; +import { Legacy } from '../../../legacy_shims'; +import { ActionResult } from '../../../../../../plugins/actions/common'; import { ALERT_ACTION_TYPE_EMAIL } from '../../../../common/constants'; import { getMissingFieldErrors } from '../../../lib/form_validation'; import { Step1 } from './step1'; @@ -59,7 +59,7 @@ export const AlertsConfiguration: React.FC = ( }, [emailAddress]); async function fetchEmailActions() { - const kibanaActions = await kfetch({ + const kibanaActions = await Legacy.shims.kfetch({ method: 'GET', pathname: `/api/action/_getAll`, }); @@ -84,7 +84,7 @@ export const AlertsConfiguration: React.FC = ( setShowFormErrors(false); try { - await kfetch({ + await Legacy.shims.kfetch({ method: 'POST', pathname: `/api/monitoring/v1/alerts`, body: JSON.stringify({ selectedEmailActionId, emailAddress }), diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/index.ts b/x-pack/plugins/monitoring/public/components/alerts/configuration/index.ts similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/index.ts rename to x-pack/plugins/monitoring/public/components/alerts/configuration/index.ts diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step1.test.tsx b/x-pack/plugins/monitoring/public/components/alerts/configuration/step1.test.tsx similarity index 83% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step1.test.tsx rename to x-pack/plugins/monitoring/public/components/alerts/configuration/step1.test.tsx index 19a1a61d00a42..5734d379dfb0c 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step1.test.tsx +++ b/x-pack/plugins/monitoring/public/components/alerts/configuration/step1.test.tsx @@ -49,9 +49,13 @@ describe('Step1', () => { beforeEach(() => { jest.isolateModules(() => { - jest.doMock('ui/kfetch', () => ({ - kfetch: () => { - return {}; + jest.doMock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch: () => { + return {}; + }, + }, }, })); setModules(); @@ -97,8 +101,12 @@ describe('Step1', () => { it('should send up the create to the server', async () => { const kfetch = jest.fn().mockImplementation(() => {}); jest.isolateModules(() => { - jest.doMock('ui/kfetch', () => ({ - kfetch, + jest.doMock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch, + }, + }, })); setModules(); }); @@ -152,8 +160,12 @@ describe('Step1', () => { it('should send up the edit to the server', async () => { const kfetch = jest.fn().mockImplementation(() => {}); jest.isolateModules(() => { - jest.doMock('ui/kfetch', () => ({ - kfetch, + jest.doMock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch, + }, + }, })); setModules(); }); @@ -194,13 +206,17 @@ describe('Step1', () => { describe('testing', () => { it('should allow for testing', async () => { jest.isolateModules(() => { - jest.doMock('ui/kfetch', () => ({ - kfetch: jest.fn().mockImplementation(arg => { - if (arg.pathname === '/api/action/1/_execute') { - return { status: 'ok' }; - } - return {}; - }), + jest.doMock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch: jest.fn().mockImplementation(arg => { + if (arg.pathname === '/api/action/1/_execute') { + return { status: 'ok' }; + } + return {}; + }), + }, + }, })); setModules(); }); @@ -234,12 +250,16 @@ describe('Step1', () => { it('should show a successful test', async () => { jest.isolateModules(() => { - jest.doMock('ui/kfetch', () => ({ - kfetch: (arg: any) => { - if (arg.pathname === '/api/action/1/_execute') { - return { status: 'ok' }; - } - return {}; + jest.doMock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch: (arg: any) => { + if (arg.pathname === '/api/action/1/_execute') { + return { status: 'ok' }; + } + return {}; + }, + }, }, })); setModules(); @@ -257,12 +277,16 @@ describe('Step1', () => { it('should show a failed test error', async () => { jest.isolateModules(() => { - jest.doMock('ui/kfetch', () => ({ - kfetch: (arg: any) => { - if (arg.pathname === '/api/action/1/_execute') { - return { message: 'Very detailed error message' }; - } - return {}; + jest.doMock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch: (arg: any) => { + if (arg.pathname === '/api/action/1/_execute') { + return { message: 'Very detailed error message' }; + } + return {}; + }, + }, }, })); setModules(); @@ -304,8 +328,12 @@ describe('Step1', () => { it('should send up the delete to the server', async () => { const kfetch = jest.fn().mockImplementation(() => {}); jest.isolateModules(() => { - jest.doMock('ui/kfetch', () => ({ - kfetch, + jest.doMock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch, + }, + }, })); setModules(); }); diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step1.tsx b/x-pack/plugins/monitoring/public/components/alerts/configuration/step1.tsx similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step1.tsx rename to x-pack/plugins/monitoring/public/components/alerts/configuration/step1.tsx index a69bf29dd9874..7953010005885 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step1.tsx +++ b/x-pack/plugins/monitoring/public/components/alerts/configuration/step1.tsx @@ -16,10 +16,10 @@ import { EuiToolTip, EuiCallOut, } from '@elastic/eui'; -import { kfetch } from 'ui/kfetch'; import { omit, pick } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { ActionResult, BASE_ACTION_API_PATH } from '../../../../../../../plugins/actions/common'; +import { Legacy } from '../../../legacy_shims'; +import { ActionResult, BASE_ACTION_API_PATH } from '../../../../../../plugins/actions/common'; import { ManageEmailAction, EmailActionData } from '../manage_email_action'; import { ALERT_ACTION_TYPE_EMAIL } from '../../../../common/constants'; import { NEW_ACTION_ID } from './configuration'; @@ -42,7 +42,7 @@ export const Step1: React.FC = (props: GetStep1Props) => { async function createEmailAction(data: EmailActionData) { if (props.editAction) { - await kfetch({ + await Legacy.shims.kfetch({ method: 'PUT', pathname: `${BASE_ACTION_API_PATH}/${props.editAction.id}`, body: JSON.stringify({ @@ -53,7 +53,7 @@ export const Step1: React.FC = (props: GetStep1Props) => { }); props.setEditAction(null); } else { - await kfetch({ + await Legacy.shims.kfetch({ method: 'POST', pathname: BASE_ACTION_API_PATH, body: JSON.stringify({ @@ -73,7 +73,7 @@ export const Step1: React.FC = (props: GetStep1Props) => { async function deleteEmailAction(id: string) { setIsDeleting(true); - await kfetch({ + await Legacy.shims.kfetch({ method: 'DELETE', pathname: `${BASE_ACTION_API_PATH}/${id}`, }); @@ -99,7 +99,7 @@ export const Step1: React.FC = (props: GetStep1Props) => { to: [props.emailAddress], }; - const result = await kfetch({ + const result = await Legacy.shims.kfetch({ method: 'POST', pathname: `${BASE_ACTION_API_PATH}/${props.selectedEmailActionId}/_execute`, body: JSON.stringify({ params }), diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step2.test.tsx b/x-pack/plugins/monitoring/public/components/alerts/configuration/step2.test.tsx similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step2.test.tsx rename to x-pack/plugins/monitoring/public/components/alerts/configuration/step2.test.tsx diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step2.tsx b/x-pack/plugins/monitoring/public/components/alerts/configuration/step2.tsx similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step2.tsx rename to x-pack/plugins/monitoring/public/components/alerts/configuration/step2.tsx diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step3.test.tsx b/x-pack/plugins/monitoring/public/components/alerts/configuration/step3.test.tsx similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step3.test.tsx rename to x-pack/plugins/monitoring/public/components/alerts/configuration/step3.test.tsx diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step3.tsx b/x-pack/plugins/monitoring/public/components/alerts/configuration/step3.tsx similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/configuration/step3.tsx rename to x-pack/plugins/monitoring/public/components/alerts/configuration/step3.tsx diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/formatted_alert.js b/x-pack/plugins/monitoring/public/components/alerts/formatted_alert.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/formatted_alert.js rename to x-pack/plugins/monitoring/public/components/alerts/formatted_alert.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/index.js b/x-pack/plugins/monitoring/public/components/alerts/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/index.js rename to x-pack/plugins/monitoring/public/components/alerts/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/manage_email_action.tsx b/x-pack/plugins/monitoring/public/components/alerts/manage_email_action.tsx similarity index 99% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/manage_email_action.tsx rename to x-pack/plugins/monitoring/public/components/alerts/manage_email_action.tsx index 2bd9804795cb5..3ef9654076340 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/alerts/manage_email_action.tsx +++ b/x-pack/plugins/monitoring/public/components/alerts/manage_email_action.tsx @@ -21,7 +21,7 @@ import { EuiText, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ActionResult } from '../../../../../../plugins/actions/common'; +import { ActionResult } from '../../../../../plugins/actions/common'; import { getMissingFieldErrors, hasErrors, getRequiredFieldError } from '../../lib/form_validation'; import { ALERT_EMAIL_SERVICES } from '../../../common/constants'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/map_severity.js b/x-pack/plugins/monitoring/public/components/alerts/map_severity.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/map_severity.js rename to x-pack/plugins/monitoring/public/components/alerts/map_severity.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/status.test.tsx b/x-pack/plugins/monitoring/public/components/alerts/status.test.tsx similarity index 83% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/status.test.tsx rename to x-pack/plugins/monitoring/public/components/alerts/status.test.tsx index d3cf4b463a2cc..a0031f50951bd 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/alerts/status.test.tsx +++ b/x-pack/plugins/monitoring/public/components/alerts/status.test.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { kfetch } from 'ui/kfetch'; +import { Legacy } from '../../legacy_shims'; import { AlertsStatus, AlertsStatusProps } from './status'; import { ALERT_TYPES } from '../../../common/constants'; import { getSetupModeState } from '../../lib/setup_mode'; @@ -18,8 +18,16 @@ jest.mock('../../lib/setup_mode', () => ({ toggleSetupMode: jest.fn(), })); -jest.mock('ui/kfetch', () => ({ - kfetch: jest.fn(), +jest.mock('../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch: jest.fn(), + docLinks: { + ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', + DOC_LINK_VERSION: 'current', + }, + }, + }, })); const defaultProps: AlertsStatusProps = { @@ -35,7 +43,7 @@ describe('Status', () => { enabled: false, }); - (kfetch as jest.Mock).mockImplementation(({ pathname }) => { + (Legacy.shims.kfetch as jest.Mock).mockImplementation(({ pathname }) => { if (pathname === '/internal/security/api_key/privileges') { return { areApiKeysEnabled: true }; } @@ -62,7 +70,7 @@ describe('Status', () => { }); it('should render a success message if all alerts have been migrated and in setup mode', async () => { - (kfetch as jest.Mock).mockReturnValue({ + (Legacy.shims.kfetch as jest.Mock).mockReturnValue({ data: ALERT_TYPES.map(type => ({ alertTypeId: type })), }); diff --git a/x-pack/legacy/plugins/monitoring/public/components/alerts/status.tsx b/x-pack/plugins/monitoring/public/components/alerts/status.tsx similarity index 93% rename from x-pack/legacy/plugins/monitoring/public/components/alerts/status.tsx rename to x-pack/plugins/monitoring/public/components/alerts/status.tsx index 5f5329bf7fff8..cdddbf1031303 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/alerts/status.tsx +++ b/x-pack/plugins/monitoring/public/components/alerts/status.tsx @@ -5,7 +5,6 @@ */ import React, { Fragment } from 'react'; -import { kfetch } from 'ui/kfetch'; import { EuiSpacer, EuiCallOut, @@ -18,8 +17,8 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; -import { Alert, BASE_ALERT_API_PATH } from '../../../../../../plugins/alerting/common'; +import { Legacy } from '../../legacy_shims'; +import { Alert, BASE_ALERT_API_PATH } from '../../../../../plugins/alerting/common'; import { getSetupModeState, addSetupModeCallback, toggleSetupMode } from '../../lib/setup_mode'; import { NUMBER_OF_MIGRATED_ALERTS, ALERT_TYPE_PREFIX } from '../../../common/constants'; import { AlertsConfiguration } from './configuration'; @@ -39,7 +38,10 @@ export const AlertsStatus: React.FC = (props: AlertsStatusPro React.useEffect(() => { async function fetchAlertsStatus() { - const alerts = await kfetch({ method: 'GET', pathname: `${BASE_ALERT_API_PATH}/_find` }); + const alerts = await Legacy.shims.kfetch({ + method: 'GET', + pathname: `${BASE_ALERT_API_PATH}/_find`, + }); const monitoringAlerts = alerts.data.filter((alert: Alert) => alert.alertTypeId.startsWith(ALERT_TYPE_PREFIX) ); @@ -57,7 +59,9 @@ export const AlertsStatus: React.FC = (props: AlertsStatusPro }, [setupModeEnabled, showMigrationFlyout]); async function fetchSecurityConfigured() { - const response = await kfetch({ pathname: '/internal/security/api_key/privileges' }); + const response = await Legacy.shims.kfetch({ + pathname: '/internal/security/api_key/privileges', + }); setIsSecurityConfigured(response.areApiKeysEnabled); } @@ -72,7 +76,7 @@ export const AlertsStatus: React.FC = (props: AlertsStatusPro if (isSecurityConfigured) { return null; } - + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; const link = `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/security-settings.html#api-key-service-settings`; return ( diff --git a/x-pack/legacy/plugins/monitoring/public/components/apm/instance/index.js b/x-pack/plugins/monitoring/public/components/apm/instance/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/apm/instance/index.js rename to x-pack/plugins/monitoring/public/components/apm/instance/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/apm/instance/instance.js b/x-pack/plugins/monitoring/public/components/apm/instance/instance.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/apm/instance/instance.js rename to x-pack/plugins/monitoring/public/components/apm/instance/instance.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/apm/instance/status.js b/x-pack/plugins/monitoring/public/components/apm/instance/status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/apm/instance/status.js rename to x-pack/plugins/monitoring/public/components/apm/instance/status.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/apm/instances/index.js b/x-pack/plugins/monitoring/public/components/apm/instances/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/apm/instances/index.js rename to x-pack/plugins/monitoring/public/components/apm/instances/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/apm/instances/instances.js b/x-pack/plugins/monitoring/public/components/apm/instances/instances.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/apm/instances/instances.js rename to x-pack/plugins/monitoring/public/components/apm/instances/instances.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/apm/instances/status.js b/x-pack/plugins/monitoring/public/components/apm/instances/status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/apm/instances/status.js rename to x-pack/plugins/monitoring/public/components/apm/instances/status.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/apm/overview/index.js b/x-pack/plugins/monitoring/public/components/apm/overview/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/apm/overview/index.js rename to x-pack/plugins/monitoring/public/components/apm/overview/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/apm/status_icon.js b/x-pack/plugins/monitoring/public/components/apm/status_icon.js similarity index 91% rename from x-pack/legacy/plugins/monitoring/public/components/apm/status_icon.js rename to x-pack/plugins/monitoring/public/components/apm/status_icon.js index 2de77b70df646..073c56217e8df 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/apm/status_icon.js +++ b/x-pack/plugins/monitoring/public/components/apm/status_icon.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { StatusIcon } from 'plugins/monitoring/components/status_icon'; +import { StatusIcon } from '../../components/status_icon'; import { i18n } from '@kbn/i18n'; export function ApmStatusIcon({ status, availability = true }) { diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/beat/beat.js b/x-pack/plugins/monitoring/public/components/beats/beat/beat.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/beat/beat.js rename to x-pack/plugins/monitoring/public/components/beats/beat/beat.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/beat/index.js b/x-pack/plugins/monitoring/public/components/beats/beat/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/beat/index.js rename to x-pack/plugins/monitoring/public/components/beats/beat/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/index.js b/x-pack/plugins/monitoring/public/components/beats/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/index.js rename to x-pack/plugins/monitoring/public/components/beats/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/listing/index.js b/x-pack/plugins/monitoring/public/components/beats/listing/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/listing/index.js rename to x-pack/plugins/monitoring/public/components/beats/listing/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/listing/listing.js b/x-pack/plugins/monitoring/public/components/beats/listing/listing.js similarity index 96% rename from x-pack/legacy/plugins/monitoring/public/components/beats/listing/listing.js rename to x-pack/plugins/monitoring/public/components/beats/listing/listing.js index a20728eb9a58f..5863f6e5161ad 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/beats/listing/listing.js +++ b/x-pack/plugins/monitoring/public/components/beats/listing/listing.js @@ -14,9 +14,9 @@ import { EuiLink, EuiScreenReaderOnly, } from '@elastic/eui'; -import { Stats } from 'plugins/monitoring/components/beats'; -import { formatMetric } from 'plugins/monitoring/lib/format_number'; -import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; +import { Stats } from '../../beats'; +import { formatMetric } from '../../../lib/format_number'; +import { EuiMonitoringTable } from '../../table'; import { i18n } from '@kbn/i18n'; import { BEATS_SYSTEM_ID } from '../../../../common/constants'; import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_active.test.js.snap b/x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_active.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_active.test.js.snap rename to x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_active.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_types.test.js.snap b/x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_types.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_types.test.js.snap rename to x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_types.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_versions.test.js.snap b/x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_versions.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_versions.test.js.snap rename to x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/latest_versions.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap b/x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap rename to x-pack/plugins/monitoring/public/components/beats/overview/__snapshots__/overview.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/index.js b/x-pack/plugins/monitoring/public/components/beats/overview/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/index.js rename to x-pack/plugins/monitoring/public/components/beats/overview/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_active.js b/x-pack/plugins/monitoring/public/components/beats/overview/latest_active.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_active.js rename to x-pack/plugins/monitoring/public/components/beats/overview/latest_active.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_active.test.js b/x-pack/plugins/monitoring/public/components/beats/overview/latest_active.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_active.test.js rename to x-pack/plugins/monitoring/public/components/beats/overview/latest_active.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_types.js b/x-pack/plugins/monitoring/public/components/beats/overview/latest_types.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_types.js rename to x-pack/plugins/monitoring/public/components/beats/overview/latest_types.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_types.test.js b/x-pack/plugins/monitoring/public/components/beats/overview/latest_types.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_types.test.js rename to x-pack/plugins/monitoring/public/components/beats/overview/latest_types.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_versions.js b/x-pack/plugins/monitoring/public/components/beats/overview/latest_versions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_versions.js rename to x-pack/plugins/monitoring/public/components/beats/overview/latest_versions.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_versions.test.js b/x-pack/plugins/monitoring/public/components/beats/overview/latest_versions.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/latest_versions.test.js rename to x-pack/plugins/monitoring/public/components/beats/overview/latest_versions.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/overview.js b/x-pack/plugins/monitoring/public/components/beats/overview/overview.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/overview.js rename to x-pack/plugins/monitoring/public/components/beats/overview/overview.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/overview.test.js b/x-pack/plugins/monitoring/public/components/beats/overview/overview.test.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/public/components/beats/overview/overview.test.js rename to x-pack/plugins/monitoring/public/components/beats/overview/overview.test.js index 1947f042b09b7..006f6ce3db975 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/beats/overview/overview.test.js +++ b/x-pack/plugins/monitoring/public/components/beats/overview/overview.test.js @@ -10,16 +10,10 @@ import { shallow } from 'enzyme'; jest.mock('../stats', () => ({ Stats: () => 'Stats', })); -jest.mock('../../', () => ({ +jest.mock('../../chart', () => ({ MonitoringTimeseriesContainer: () => 'MonitoringTimeseriesContainer', })); -jest.mock('../../../np_imports/ui/chrome', () => { - return { - getBasePath: () => '', - }; -}); - import { BeatsOverview } from './overview'; describe('Overview', () => { diff --git a/x-pack/legacy/plugins/monitoring/public/components/beats/stats.js b/x-pack/plugins/monitoring/public/components/beats/stats.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/beats/stats.js rename to x-pack/plugins/monitoring/public/components/beats/stats.js index 672d8a79ca64a..89ec10bbaf1bb 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/beats/stats.js +++ b/x-pack/plugins/monitoring/public/components/beats/stats.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { formatMetric } from 'plugins/monitoring/lib/format_number'; +import { formatMetric } from '../../lib/format_number'; import { SummaryStatus } from '../summary_status'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/__tests__/get_color.js b/x-pack/plugins/monitoring/public/components/chart/__tests__/get_color.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/__tests__/get_color.js rename to x-pack/plugins/monitoring/public/components/chart/__tests__/get_color.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/__tests__/get_last_value.js b/x-pack/plugins/monitoring/public/components/chart/__tests__/get_last_value.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/__tests__/get_last_value.js rename to x-pack/plugins/monitoring/public/components/chart/__tests__/get_last_value.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/__tests__/get_title.js b/x-pack/plugins/monitoring/public/components/chart/__tests__/get_title.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/__tests__/get_title.js rename to x-pack/plugins/monitoring/public/components/chart/__tests__/get_title.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/__tests__/get_values_for_legend.js b/x-pack/plugins/monitoring/public/components/chart/__tests__/get_values_for_legend.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/__tests__/get_values_for_legend.js rename to x-pack/plugins/monitoring/public/components/chart/__tests__/get_values_for_legend.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/_chart.scss b/x-pack/plugins/monitoring/public/components/chart/_chart.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/_chart.scss rename to x-pack/plugins/monitoring/public/components/chart/_chart.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/_index.scss b/x-pack/plugins/monitoring/public/components/chart/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/_index.scss rename to x-pack/plugins/monitoring/public/components/chart/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/chart_target.js b/x-pack/plugins/monitoring/public/components/chart/chart_target.js similarity index 99% rename from x-pack/legacy/plugins/monitoring/public/components/chart/chart_target.js rename to x-pack/plugins/monitoring/public/components/chart/chart_target.js index 5c9cddf9c2902..e6a6cc4b77755 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/chart/chart_target.js +++ b/x-pack/plugins/monitoring/public/components/chart/chart_target.js @@ -6,7 +6,7 @@ import _ from 'lodash'; import React from 'react'; -import $ from 'plugins/xpack_main/jquery_flot'; +import $ from '../../lib/jquery_flot'; import { eventBus } from './event_bus'; import { getChartOptions } from './get_chart_options'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/event_bus.js b/x-pack/plugins/monitoring/public/components/chart/event_bus.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/event_bus.js rename to x-pack/plugins/monitoring/public/components/chart/event_bus.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/get_chart_options.js b/x-pack/plugins/monitoring/public/components/chart/get_chart_options.js similarity index 92% rename from x-pack/legacy/plugins/monitoring/public/components/chart/get_chart_options.js rename to x-pack/plugins/monitoring/public/components/chart/get_chart_options.js index 661d51e068201..81a3260447600 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/chart/get_chart_options.js +++ b/x-pack/plugins/monitoring/public/components/chart/get_chart_options.js @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from '../../np_imports/ui/chrome'; +import { Legacy } from '../../legacy_shims'; import { merge } from 'lodash'; import { CHART_LINE_COLOR, CHART_TEXT_COLOR } from '../../../common/constants'; export async function getChartOptions(axisOptions) { - const $injector = chrome.dangerouslyGetActiveInjector(); + const $injector = Legacy.shims.getAngularInjector(); const timezone = $injector.get('config').get('dateFormat:tz'); const opts = { legend: { diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/get_color.js b/x-pack/plugins/monitoring/public/components/chart/get_color.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/get_color.js rename to x-pack/plugins/monitoring/public/components/chart/get_color.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/get_last_value.js b/x-pack/plugins/monitoring/public/components/chart/get_last_value.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/get_last_value.js rename to x-pack/plugins/monitoring/public/components/chart/get_last_value.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/get_title.js b/x-pack/plugins/monitoring/public/components/chart/get_title.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/get_title.js rename to x-pack/plugins/monitoring/public/components/chart/get_title.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/get_units.js b/x-pack/plugins/monitoring/public/components/chart/get_units.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/get_units.js rename to x-pack/plugins/monitoring/public/components/chart/get_units.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/get_values_for_legend.js b/x-pack/plugins/monitoring/public/components/chart/get_values_for_legend.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/get_values_for_legend.js rename to x-pack/plugins/monitoring/public/components/chart/get_values_for_legend.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/horizontal_legend.js b/x-pack/plugins/monitoring/public/components/chart/horizontal_legend.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/horizontal_legend.js rename to x-pack/plugins/monitoring/public/components/chart/horizontal_legend.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/index.js b/x-pack/plugins/monitoring/public/components/chart/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/index.js rename to x-pack/plugins/monitoring/public/components/chart/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/info_tooltip.js b/x-pack/plugins/monitoring/public/components/chart/info_tooltip.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/info_tooltip.js rename to x-pack/plugins/monitoring/public/components/chart/info_tooltip.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/monitoring_timeseries.js b/x-pack/plugins/monitoring/public/components/chart/monitoring_timeseries.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/monitoring_timeseries.js rename to x-pack/plugins/monitoring/public/components/chart/monitoring_timeseries.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/monitoring_timeseries_container.js b/x-pack/plugins/monitoring/public/components/chart/monitoring_timeseries_container.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/monitoring_timeseries_container.js rename to x-pack/plugins/monitoring/public/components/chart/monitoring_timeseries_container.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/timeseries_container.js b/x-pack/plugins/monitoring/public/components/chart/timeseries_container.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/timeseries_container.js rename to x-pack/plugins/monitoring/public/components/chart/timeseries_container.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/chart/timeseries_visualization.js b/x-pack/plugins/monitoring/public/components/chart/timeseries_visualization.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/chart/timeseries_visualization.js rename to x-pack/plugins/monitoring/public/components/chart/timeseries_visualization.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/listing/alerts_indicator.js b/x-pack/plugins/monitoring/public/components/cluster/listing/alerts_indicator.js similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/listing/alerts_indicator.js rename to x-pack/plugins/monitoring/public/components/cluster/listing/alerts_indicator.js index 948f743ba0183..68d7a5a94e42f 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/listing/alerts_indicator.js +++ b/x-pack/plugins/monitoring/public/components/cluster/listing/alerts_indicator.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { mapSeverity } from 'plugins/monitoring/components/alerts/map_severity'; +import { mapSeverity } from '../../alerts/map_severity'; import { EuiHealth, EuiToolTip } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/listing/index.js b/x-pack/plugins/monitoring/public/components/cluster/listing/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/listing/index.js rename to x-pack/plugins/monitoring/public/components/cluster/listing/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/listing/listing.js b/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/listing/listing.js rename to x-pack/plugins/monitoring/public/components/cluster/listing/listing.js index 4cf74b3595730..feda891c1ce29 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/listing/listing.js +++ b/x-pack/plugins/monitoring/public/components/cluster/listing/listing.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment, Component } from 'react'; -import chrome from 'plugins/monitoring/np_imports/ui/chrome'; +import { Legacy } from '../../../legacy_shims'; import moment from 'moment'; import numeral from '@elastic/numeral'; import { capitalize, partial } from 'lodash'; @@ -19,12 +19,11 @@ import { EuiSpacer, EuiIcon, } from '@elastic/eui'; -import { toastNotifications } from 'ui/notify'; -import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; -import { AlertsIndicator } from 'plugins/monitoring/components/cluster/listing/alerts_indicator'; +import { EuiMonitoringTable } from '../../table'; +import { AlertsIndicator } from '../../cluster/listing/alerts_indicator'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; -import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../../../src/plugins/kibana_react/public'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../../../common/constants'; const IsClusterSupported = ({ isSupported, children }) => { @@ -236,13 +235,17 @@ const changeCluster = (scope, globalState, kbnUrl, clusterUuid, ccs) => { globalState.cluster_uuid = clusterUuid; globalState.ccs = ccs; globalState.save(); - kbnUrl.changePath('/overview'); + kbnUrl.redirect('/overview'); }); }; const licenseWarning = (scope, { title, text }) => { scope.$evalAsync(() => { - toastNotifications.addWarning({ title, text, 'data-test-subj': 'monitoringLicenseWarning' }); + Legacy.shims.toastNotifications.addWarning({ + title, + text, + 'data-test-subj': 'monitoringLicenseWarning', + }); }); }; @@ -285,7 +288,7 @@ const handleClickIncompatibleLicense = (scope, clusterName) => { }; const handleClickInvalidLicense = (scope, clusterName) => { - const licensingPath = `${chrome.getBasePath()}/app/kibana#/management/elasticsearch/license_management/home`; + const licensingPath = `${Legacy.shims.getBasePath()}/app/kibana#/management/elasticsearch/license_management/home`; licenseWarning(scope, { title: toMountPoint( diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/__tests__/__snapshots__/helpers.test.js.snap b/x-pack/plugins/monitoring/public/components/cluster/overview/__tests__/__snapshots__/helpers.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/__tests__/__snapshots__/helpers.test.js.snap rename to x-pack/plugins/monitoring/public/components/cluster/overview/__tests__/__snapshots__/helpers.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/__tests__/helpers.test.js b/x-pack/plugins/monitoring/public/components/cluster/overview/__tests__/helpers.test.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/__tests__/helpers.test.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/__tests__/helpers.test.js index fea8f0001540a..e09c42bc59429 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/__tests__/helpers.test.js +++ b/x-pack/plugins/monitoring/public/components/cluster/overview/__tests__/helpers.test.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { BytesUsage, BytesPercentageUsage } from '../helpers'; describe('Bytes Usage', () => { diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/alerts_panel.js b/x-pack/plugins/monitoring/public/components/cluster/overview/alerts_panel.js similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/alerts_panel.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/alerts_panel.js index d87ff98e79be0..6dcd64f875e1c 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/alerts_panel.js +++ b/x-pack/plugins/monitoring/public/components/cluster/overview/alerts_panel.js @@ -6,8 +6,8 @@ import React, { Fragment } from 'react'; import moment from 'moment-timezone'; -import { FormattedAlert } from 'plugins/monitoring/components/alerts/formatted_alert'; -import { mapSeverity } from 'plugins/monitoring/components/alerts/map_severity'; +import { FormattedAlert } from '../../alerts/formatted_alert'; +import { mapSeverity } from '../../alerts/map_severity'; import { formatTimestampToDuration } from '../../../../common/format_timestamp_to_duration'; import { CALCULATE_DURATION_SINCE, diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/apm_panel.js b/x-pack/plugins/monitoring/public/components/cluster/overview/apm_panel.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/apm_panel.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/apm_panel.js index 84dc13e9da1de..97205e0fcd732 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/apm_panel.js +++ b/x-pack/plugins/monitoring/public/components/cluster/overview/apm_panel.js @@ -7,7 +7,7 @@ import React from 'react'; import moment from 'moment'; import { get } from 'lodash'; -import { formatMetric } from 'plugins/monitoring/lib/format_number'; +import { formatMetric } from '../../../lib/format_number'; import { ClusterItemContainer, BytesUsage, DisabledIfNoDataAndInSetupModeLink } from './helpers'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/beats_panel.js b/x-pack/plugins/monitoring/public/components/cluster/overview/beats_panel.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/beats_panel.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/beats_panel.js index 7406c15f3cf1d..c20770bdda6b7 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/beats_panel.js +++ b/x-pack/plugins/monitoring/public/components/cluster/overview/beats_panel.js @@ -6,7 +6,7 @@ import { get } from 'lodash'; import React from 'react'; -import { formatMetric } from 'plugins/monitoring/lib/format_number'; +import { formatMetric } from '../../../lib/format_number'; import { EuiFlexGrid, EuiFlexItem, diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/elasticsearch_panel.js b/x-pack/plugins/monitoring/public/components/cluster/overview/elasticsearch_panel.js similarity index 99% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/elasticsearch_panel.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/elasticsearch_panel.js index 48ff8edaafe60..41dc662c94211 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/elasticsearch_panel.js +++ b/x-pack/plugins/monitoring/public/components/cluster/overview/elasticsearch_panel.js @@ -6,7 +6,7 @@ import React, { Fragment } from 'react'; import { get, capitalize } from 'lodash'; -import { formatNumber } from 'plugins/monitoring/lib/format_number'; +import { formatNumber } from '../../../lib/format_number'; import { ClusterItemContainer, HealthStatusIndicator, diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/helpers.js b/x-pack/plugins/monitoring/public/components/cluster/overview/helpers.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/helpers.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/helpers.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/index.js b/x-pack/plugins/monitoring/public/components/cluster/overview/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/index.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/kibana_panel.js b/x-pack/plugins/monitoring/public/components/cluster/overview/kibana_panel.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/kibana_panel.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/kibana_panel.js index ee17ce446dd6d..541c240b3c35a 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/kibana_panel.js +++ b/x-pack/plugins/monitoring/public/components/cluster/overview/kibana_panel.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { formatNumber } from 'plugins/monitoring/lib/format_number'; +import { formatNumber } from '../../../lib/format_number'; import { ClusterItemContainer, HealthStatusIndicator, diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/license_text.js b/x-pack/plugins/monitoring/public/components/cluster/overview/license_text.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/license_text.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/license_text.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/logstash_panel.js b/x-pack/plugins/monitoring/public/components/cluster/overview/logstash_panel.js similarity index 99% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/overview/logstash_panel.js rename to x-pack/plugins/monitoring/public/components/cluster/overview/logstash_panel.js index 9e21ef1074ed3..19a318642aab7 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/cluster/overview/logstash_panel.js +++ b/x-pack/plugins/monitoring/public/components/cluster/overview/logstash_panel.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { formatNumber } from 'plugins/monitoring/lib/format_number'; +import { formatNumber } from '../../../lib/format_number'; import { ClusterItemContainer, BytesPercentageUsage, diff --git a/x-pack/legacy/plugins/monitoring/public/components/cluster/status_icon.js b/x-pack/plugins/monitoring/public/components/cluster/status_icon.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/cluster/status_icon.js rename to x-pack/plugins/monitoring/public/components/cluster/status_icon.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/__snapshots__/ccr.test.js.snap b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr/__snapshots__/ccr.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/__snapshots__/ccr.test.js.snap rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr/__snapshots__/ccr.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/ccr.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr/ccr.js similarity index 99% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/ccr.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr/ccr.js index cddae16f34eca..5aad73d7a131e 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/ccr.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr/ccr.js @@ -17,10 +17,9 @@ import { EuiTextColor, EuiScreenReaderOnly, } from '@elastic/eui'; -import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link'; -import './ccr.css'; import { FormattedMessage } from '@kbn/i18n/react'; import { i18n } from '@kbn/i18n'; +import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link'; function toSeconds(ms) { return Math.floor(ms / 1000) + 's'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/ccr.test.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr/ccr.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/ccr.test.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr/ccr.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/ccr.css b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr/index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr/ccr.css rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr/index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/__snapshots__/ccr_shard.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.js similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.js index af0ff323b7ba8..a8aa931bad254 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.js @@ -5,7 +5,7 @@ */ import React, { Fragment, PureComponent } from 'react'; -import chrome from '../../../np_imports/ui/chrome'; +import { Legacy } from '../../../legacy_shims'; import { EuiPage, EuiPageBody, @@ -93,7 +93,7 @@ export class CcrShard extends PureComponent { renderLatestStat() { const { stat, timestamp } = this.props; - const injector = chrome.dangerouslyGetActiveInjector(); + const injector = Legacy.shims.getAngularInjector(); const timezone = injector.get('config').get('dateFormat:tz'); return ( diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.test.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.test.js similarity index 88% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.test.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.test.js index b950c2ca0a6d2..ceb1fd1186eed 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.test.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/ccr_shard.test.js @@ -8,13 +8,18 @@ import React from 'react'; import { shallow } from 'enzyme'; import { CcrShard } from './ccr_shard'; -jest.mock('../../../np_imports/ui/chrome', () => { +jest.mock('../../../legacy_shims', () => { return { - getBasePath: () => '', - dangerouslyGetActiveInjector: () => ({ get: () => ({ get: () => 'utc' }) }), + Legacy: { + shims: { getAngularInjector: () => ({ get: () => ({ get: () => 'utc' }) }) }, + }, }; }); +jest.mock('../../chart', () => ({ + MonitoringTimeseriesContainer: () => 'MonitoringTimeseriesContainer', +})); + describe('CcrShard', () => { const props = { formattedLeader: 'leader on remote', diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/ccr_shard/status.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/cluster_status/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/index/advanced.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index/advanced.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/index/advanced.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/index/advanced.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/index/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/index/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/index/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/index_detail_status/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/indices/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/indices/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/indices/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/indices/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/indices/indices.js b/x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/indices/indices.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/indices/indices.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.js b/x-pack/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.js index c2775713171ad..4d457c943c872 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/ml_job_listing/status_icon.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { StatusIcon } from 'plugins/monitoring/components/status_icon'; +import { StatusIcon } from '../../status_icon'; import { i18n } from '@kbn/i18n'; export function MachineLearningJobStatusIcon({ status }) { diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node/advanced.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node/advanced.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node/advanced.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/node/advanced.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/node/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node/node.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node/node.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node/node.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/node/node.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node/status_icon.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node/status_icon.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/node/status_icon.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/node_detail_status/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap rename to x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/__snapshots__/cells.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/cells.test.js b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/cells.test.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/cells.test.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/cells.test.js index 50abdcc718bc8..0c4b4b2b3c3f4 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/cells.test.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/__tests__/cells.test.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { MetricCell } from '../cells'; describe('Node Listing Metric Cell', () => { diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/cells.js b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/cells.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/cells.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/nodes/cells.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/nodes/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js b/x-pack/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/nodes/nodes.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/overview/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/overview/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/overview/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/overview/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/overview/overview.js b/x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/overview/overview.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/overview/overview.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js similarity index 92% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js index 133b520947b1b..1aaba96ed3da4 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/parse_props.js @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from '../../../np_imports/ui/chrome'; +import { Legacy } from '../../../legacy_shims'; import { capitalize } from 'lodash'; -import { formatMetric } from 'plugins/monitoring/lib/format_number'; +import { formatMetric } from '../../../lib/format_number'; import { formatDateTimeLocal } from '../../../../common/formatting'; const getIpAndPort = transport => { @@ -39,7 +39,7 @@ export const parseProps = props => { } = props; const { files, size } = index; - const injector = chrome.dangerouslyGetActiveInjector(); + const injector = Legacy.shims.getAngularInjector(); const timezone = injector.get('config').get('dateFormat:tz'); return { diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/progress.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/progress.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/progress.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/progress.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/recovery_index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js index 6607d236590c1..d228144778c02 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js +++ b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/shard_activity.js @@ -6,7 +6,7 @@ import React, { Fragment } from 'react'; import { EuiText, EuiTitle, EuiLink, EuiSpacer, EuiSwitch } from '@elastic/eui'; -import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; +import { EuiMonitoringTable } from '../../table'; import { RecoveryIndex } from './recovery_index'; import { TotalTime } from './total_time'; import { SourceDestination } from './source_destination'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/snapshot.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/snapshot.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/snapshot.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/snapshot.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/source_destination.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/source_destination.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/source_destination.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/source_destination.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/source_tooltip.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/source_tooltip.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/source_tooltip.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/source_tooltip.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/total_time.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/total_time.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_activity/total_time.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_activity/total_time.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/_index.scss b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/_index.scss rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/_shard_allocation.scss b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_shard_allocation.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/_shard_allocation.scss rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/_shard_allocation.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/__snapshots__/shard.test.js.snap b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/__snapshots__/shard.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/__snapshots__/shard.test.js.snap rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/__snapshots__/shard.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/assigned.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/cluster_view.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.test.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.test.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/shard.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_body.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_body.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_body.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_body.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_head.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_head.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_head.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/table_head.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/unassigned.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/unassigned.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/unassigned.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/components/unassigned.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/index.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/index.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/calculate_class.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/calculate_class.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/calculate_class.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/calculate_class.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.test.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.test.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/decorate_shards.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/generate_query_and_link.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/generate_query_and_link.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/generate_query_and_link.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/generate_query_and_link.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_primary_children.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_primary_children.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_primary_children.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_primary_children.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_unassigned.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_unassigned.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_unassigned.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/has_unassigned.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/labels.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/labels.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/labels.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/labels.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/lib/vents.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/shard_allocation.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/shard_allocation.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/shard_allocation.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/shard_allocation.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/indices_by_nodes.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/indices_by_nodes.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/indices_by_nodes.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/indices_by_nodes.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.js b/x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/shard_allocation/transformers/nodes_by_indices.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/elasticsearch/status_icon.js b/x-pack/plugins/monitoring/public/components/elasticsearch/status_icon.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/elasticsearch/status_icon.js rename to x-pack/plugins/monitoring/public/components/elasticsearch/status_icon.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/index.js b/x-pack/plugins/monitoring/public/components/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/index.js rename to x-pack/plugins/monitoring/public/components/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/kibana/cluster_status/index.js b/x-pack/plugins/monitoring/public/components/kibana/cluster_status/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/kibana/cluster_status/index.js rename to x-pack/plugins/monitoring/public/components/kibana/cluster_status/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/kibana/detail_status/index.js b/x-pack/plugins/monitoring/public/components/kibana/detail_status/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/kibana/detail_status/index.js rename to x-pack/plugins/monitoring/public/components/kibana/detail_status/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/kibana/instances/index.js b/x-pack/plugins/monitoring/public/components/kibana/instances/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/kibana/instances/index.js rename to x-pack/plugins/monitoring/public/components/kibana/instances/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/kibana/instances/instances.js b/x-pack/plugins/monitoring/public/components/kibana/instances/instances.js similarity index 99% rename from x-pack/legacy/plugins/monitoring/public/components/kibana/instances/instances.js rename to x-pack/plugins/monitoring/public/components/kibana/instances/instances.js index 3a30bbc38d426..ed562c7da995b 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/kibana/instances/instances.js +++ b/x-pack/plugins/monitoring/public/components/kibana/instances/instances.js @@ -19,7 +19,7 @@ import { capitalize, get } from 'lodash'; import { ClusterStatus } from '../cluster_status'; import { EuiMonitoringTable } from '../../table'; import { KibanaStatusIcon } from '../status_icon'; -import { StatusIcon } from 'plugins/monitoring/components/status_icon'; +import { StatusIcon } from '../../status_icon'; import { formatMetric, formatNumber } from '../../../lib/format_number'; import { getSafeForExternalLink } from '../../../lib/get_safe_for_external_link'; import { i18n } from '@kbn/i18n'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/kibana/status_icon.js b/x-pack/plugins/monitoring/public/components/kibana/status_icon.js similarity index 91% rename from x-pack/legacy/plugins/monitoring/public/components/kibana/status_icon.js rename to x-pack/plugins/monitoring/public/components/kibana/status_icon.js index 87a2ab4cc4713..3c18197170b50 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/kibana/status_icon.js +++ b/x-pack/plugins/monitoring/public/components/kibana/status_icon.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { StatusIcon } from 'plugins/monitoring/components/status_icon'; +import { StatusIcon } from '../status_icon'; import { i18n } from '@kbn/i18n'; export function KibanaStatusIcon({ status, availability = true }) { diff --git a/x-pack/plugins/monitoring/public/components/license/index.js b/x-pack/plugins/monitoring/public/components/license/index.js new file mode 100644 index 0000000000000..085cc9082cf53 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/license/index.js @@ -0,0 +1,201 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { + EuiPage, + EuiPageBody, + EuiSpacer, + EuiCodeBlock, + EuiPanel, + EuiText, + EuiLink, + EuiFlexGroup, + EuiFlexItem, + EuiScreenReaderOnly, + EuiCard, + EuiButton, + EuiIcon, + EuiTitle, + EuiTextAlign, +} from '@elastic/eui'; + +import { FormattedMessage } from '@kbn/i18n/react'; +import { Legacy } from '../../legacy_shims'; + +export const AddLicense = ({ uploadPath }) => { + return ( + + } + description={ + + } + footer={ + + + + } + /> + ); +}; + +export class LicenseStatus extends React.PureComponent { + render() { + const { isExpired, status, type, expiryDate } = this.props; + const typeTitleCase = type.charAt(0).toUpperCase() + type.substr(1).toLowerCase(); + let icon; + let title; + let message; + if (isExpired) { + icon = ; + message = ( + + {expiryDate}, + }} + /> + + ); + title = ( + + ); + } else { + icon = ; + message = expiryDate ? ( + + {expiryDate}, + }} + /> + + ) : ( + + + + ); + title = ( + + ); + } + return ( + + + {icon} + + +

{title}

+
+
+
+ + + + {message} +
+ ); + } +} + +const LicenseUpdateInfoForPrimary = ({ isPrimaryCluster, uploadLicensePath }) => { + if (!isPrimaryCluster) { + return null; + } + + // viewed license is for the cluster directly connected to Kibana + return ; +}; + +const LicenseUpdateInfoForRemote = ({ isPrimaryCluster }) => { + if (isPrimaryCluster) { + return null; + } + + // viewed license is for a remote monitored cluster not directly connected to Kibana + return ( + +

+ +

+ + + {`curl -XPUT -u 'https://:/_license' -H 'Content-Type: application/json' -d @license.json`} + +
+ ); +}; + +export function License(props) { + const { status, type, isExpired, expiryDate } = props; + const licenseManagement = `${Legacy.shims.getBasePath()}/app/kibana#/management/elasticsearch/license_management`; + return ( + + +

+ +

+
+ + + + + + + + + + + + + +

+ For more license options please visit  + License Management. +

+
+
+
+ ); +} diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap rename to x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap rename to x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/index.js b/x-pack/plugins/monitoring/public/components/logs/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logs/index.js rename to x-pack/plugins/monitoring/public/components/logs/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/logs.js b/x-pack/plugins/monitoring/public/components/logs/logs.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/logs/logs.js rename to x-pack/plugins/monitoring/public/components/logs/logs.js index 3590199048352..eaf92f72103e0 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logs/logs.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.js @@ -5,17 +5,16 @@ */ import React, { PureComponent } from 'react'; import { capitalize } from 'lodash'; -import chrome from '../../np_imports/ui/chrome'; +import { Legacy } from '../../legacy_shims'; import { EuiBasicTable, EuiTitle, EuiSpacer, EuiText, EuiCallOut, EuiLink } from '@elastic/eui'; import { INFRA_SOURCE_ID } from '../../../common/constants'; import { formatDateTimeLocal } from '../../../common/formatting'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import { Reason } from './reason'; -import { capabilities } from '../../np_imports/ui/capabilities'; const getFormattedDateTimeLocal = timestamp => { - const injector = chrome.dangerouslyGetActiveInjector(); + const injector = Legacy.shims.getAngularInjector(); const timezone = injector.get('config').get('dateFormat:tz'); return formatDateTimeLocal(timestamp, timezone); }; @@ -110,7 +109,7 @@ const clusterColumns = [ ]; function getLogsUiLink(clusterUuid, nodeId, indexUuid) { - const base = `${chrome.getBasePath()}/app/logs/link-to/${INFRA_SOURCE_ID}/logs`; + const base = `${Legacy.shims.getBasePath()}/app/logs/link-to/${INFRA_SOURCE_ID}/logs`; const params = []; if (clusterUuid) { @@ -158,7 +157,7 @@ export class Logs extends PureComponent { } renderCallout() { - const uiCapabilities = capabilities.get(); + const uiCapabilities = Legacy.shims.capabilities.get(); const show = uiCapabilities.logs && uiCapabilities.logs.show; const { logs: { enabled }, diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/logs.test.js b/x-pack/plugins/monitoring/public/components/logs/logs.test.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/logs/logs.test.js rename to x-pack/plugins/monitoring/public/components/logs/logs.test.js index 63af8b208fbec..c0497ee351e34 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logs/logs.test.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.test.js @@ -8,21 +8,16 @@ import React from 'react'; import { shallow } from 'enzyme'; import { Logs } from './logs'; -jest.mock('../../np_imports/ui/chrome', () => { - return { - getBasePath: () => '', - }; -}); - -jest.mock( - '../../np_imports/ui/capabilities', - () => ({ - capabilities: { - get: () => ({ logs: { show: true } }), +jest.mock('../../legacy_shims', () => ({ + Legacy: { + shims: { + getBasePath: () => '', + capabilities: { + get: () => ({ logs: { show: true } }), + }, }, - }), - { virtual: true } -); + }, +})); const logs = { enabled: true, diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/reason.js b/x-pack/plugins/monitoring/public/components/logs/reason.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/logs/reason.js rename to x-pack/plugins/monitoring/public/components/logs/reason.js index 91c62ae53a1ca..ad21f7f81d9bd 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logs/reason.js +++ b/x-pack/plugins/monitoring/public/components/logs/reason.js @@ -8,10 +8,11 @@ import React from 'react'; import { EuiCallOut, EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; +import { Legacy } from '../../legacy_shims'; import { Monospace } from '../metricbeat_migration/instruction_steps/components/monospace/monospace'; export const Reason = ({ reason }) => { + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; let title = i18n.translate('xpack.monitoring.logs.reason.defaultTitle', { defaultMessage: 'No log data found', }); diff --git a/x-pack/legacy/plugins/monitoring/public/components/logs/reason.test.js b/x-pack/plugins/monitoring/public/components/logs/reason.test.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/public/components/logs/reason.test.js rename to x-pack/plugins/monitoring/public/components/logs/reason.test.js index c8ed05bd73ade..bd56c733268b7 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logs/reason.test.js +++ b/x-pack/plugins/monitoring/public/components/logs/reason.test.js @@ -8,9 +8,15 @@ import React from 'react'; import { shallow } from 'enzyme'; import { Reason } from './reason'; -jest.mock('ui/documentation_links', () => ({ - ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', - DOC_LINK_VERSION: 'current', +jest.mock('../../legacy_shims', () => ({ + Legacy: { + shims: { + docLinks: { + ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', + DOC_LINK_VERSION: 'current', + }, + }, + }, })); describe('Logs', () => { diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/cluster_status/index.js b/x-pack/plugins/monitoring/public/components/logstash/cluster_status/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/cluster_status/index.js rename to x-pack/plugins/monitoring/public/components/logstash/cluster_status/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/detail_status/index.js b/x-pack/plugins/monitoring/public/components/logstash/detail_status/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/detail_status/index.js rename to x-pack/plugins/monitoring/public/components/logstash/detail_status/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/listing/__snapshots__/listing.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/listing/__snapshots__/listing.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/listing/__snapshots__/listing.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/listing/__snapshots__/listing.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/listing/index.js b/x-pack/plugins/monitoring/public/components/logstash/listing/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/listing/index.js rename to x-pack/plugins/monitoring/public/components/logstash/listing/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/listing/listing.js b/x-pack/plugins/monitoring/public/components/logstash/listing/listing.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/listing/listing.js rename to x-pack/plugins/monitoring/public/components/logstash/listing/listing.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/listing/listing.test.js b/x-pack/plugins/monitoring/public/components/logstash/listing/listing.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/listing/listing.test.js rename to x-pack/plugins/monitoring/public/components/logstash/listing/listing.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/overview/index.js b/x-pack/plugins/monitoring/public/components/logstash/overview/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/overview/index.js rename to x-pack/plugins/monitoring/public/components/logstash/overview/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/overview/overview.js b/x-pack/plugins/monitoring/public/components/logstash/overview/overview.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/overview/overview.js rename to x-pack/plugins/monitoring/public/components/logstash/overview/overview.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_listing/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_listing/index.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js index f8df93d6ee8fb..132cc7ce131cf 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_listing/pipeline_listing.js @@ -20,7 +20,7 @@ import { } from '@elastic/eui'; import { formatMetric } from '../../../lib/format_number'; import { ClusterStatus } from '../cluster_status'; -import { Sparkline } from 'plugins/monitoring/components/sparkline'; +import { Sparkline } from '../../../components/sparkline'; import { EuiMonitoringSSPTable } from '../../table'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/config.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/__tests__/pipeline_state.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/config.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/config.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/config.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/config.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/if_vertex.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/plugin_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/plugin_vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/plugin_vertex.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/plugin_vertex.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/queue_vertex.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex_factory.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/plugin_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/plugin_vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/plugin_vertex.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/plugin_vertex.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/queue_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/queue_vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/queue_vertex.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/queue_vertex.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex_factory.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/element.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/element.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/element.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/element.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/else_element.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/flatten_pipeline_section.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/if_element.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/index.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/list.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/list/plugin_element.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/if_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/if_statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/if_statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/if_statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/make_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/make_statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/make_statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/make_statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/pipeline.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/pipeline.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/pipeline.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/pipeline.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/plugin_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/plugin_statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/plugin_statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/plugin_statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/queue.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/queue.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/queue.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/queue.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/utils.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/utils.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/utils.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/__tests__/utils.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/if_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/if_statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/if_statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/if_statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/index.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/make_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/make_statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/make_statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/make_statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/pipeline.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/pipeline.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/pipeline.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/pipeline.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/plugin_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/plugin_statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/plugin_statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/plugin_statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/queue.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/queue.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/queue.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/queue.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/utils.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/utils.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/utils.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline/utils.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline_state.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline_state.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline_state.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/pipeline_state.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/collapsible_statement.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/collapsible_statement.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/collapsible_statement.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/collapsible_statement.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/detail_drawer.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/detail_drawer.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/detail_drawer.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/detail_drawer.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/metric.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/metric.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/metric.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/metric.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/pipeline_viewer.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/pipeline_viewer.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/pipeline_viewer.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/pipeline_viewer.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/plugin_statement.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/plugin_statement.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/plugin_statement.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/plugin_statement.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/queue.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/queue.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/queue.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/queue.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list_heading.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list_heading.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list_heading.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list_heading.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_section.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_section.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_section.test.js.snap rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_section.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/collapsible_statement.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/collapsible_statement.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/collapsible_statement.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/collapsible_statement.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js index 2a65110f81169..09f4d03953038 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js @@ -8,6 +8,10 @@ import React from 'react'; import { DetailDrawer } from '../detail_drawer'; import { shallow } from 'enzyme'; +jest.mock('../../../../sparkline', () => ({ + Sparkline: () => 'Sparkline', +})); + describe('DetailDrawer component', () => { let onHide; let timeseriesTooltipXValueFormatter; diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/metric.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/metric.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/metric.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/metric.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js similarity index 94% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js index 5013c38ac1921..8c2558bee4e44 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js @@ -8,6 +8,10 @@ import React from 'react'; import { PipelineViewer } from '../pipeline_viewer'; import { shallow } from 'enzyme'; +jest.mock('../../../../sparkline', () => ({ + Sparkline: () => 'Sparkline', +})); + describe('PipelineViewer component', () => { let pipeline; let component; diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/plugin_statement.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/plugin_statement.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/plugin_statement.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/plugin_statement.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/queue.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/queue.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/queue.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/queue.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list_heading.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list_heading.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list_heading.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list_heading.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_section.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_section.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_section.test.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_section.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_index.scss b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_index.scss rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_pipeline_viewer.scss b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_pipeline_viewer.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_pipeline_viewer.scss rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/_pipeline_viewer.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/detail_drawer.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/detail_drawer.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/detail_drawer.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/detail_drawer.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/index.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/metric.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/metric.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/metric.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/metric.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/pipeline_viewer.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/pipeline_viewer.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/pipeline_viewer.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/pipeline_viewer.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list_heading.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list_heading.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list_heading.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list_heading.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js rename to x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/constants.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/constants.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/constants.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/constants.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap b/x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/__snapshots__/flyout.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.js index 0a284c102dc9d..42d0eec7cbed0 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.js +++ b/x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.js @@ -25,7 +25,7 @@ import { EuiCheckbox, } from '@elastic/eui'; import { getInstructionSteps } from '../instruction_steps'; -import { Storage } from '../../../../../../../../src/plugins/kibana_utils/public'; +import { Storage } from '../../../../../../../src/plugins/kibana_utils/public'; import { STORAGE_KEY, ELASTICSEARCH_SYSTEM_ID, @@ -38,7 +38,7 @@ import { INSTRUCTION_STEP_ENABLE_METRICBEAT, INSTRUCTION_STEP_DISABLE_INTERNAL, } from '../constants'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; +import { Legacy } from '../../../legacy_shims'; import { getIdentifier, formatProductName } from '../../setup_mode/formatting'; const storage = new Storage(window.localStorage); @@ -223,6 +223,7 @@ export class Flyout extends Component { getDocumentationTitle() { const { productName } = this.props; + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; let documentationUrl = null; if (productName === KIBANA_SYSTEM_ID) { diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.test.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.test.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.test.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.test.js index 3587381f977cb..61cfb491f0bd0 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.test.js +++ b/x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/flyout.test.js @@ -16,9 +16,16 @@ import { LOGSTASH_SYSTEM_ID, } from '../../../../common/constants'; -jest.mock('ui/documentation_links', () => ({ - ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', - DOC_LINK_VERSION: 'current', +jest.mock('../../../legacy_shims', () => ({ + Legacy: { + shims: { + kfetch: jest.fn(), + docLinks: { + ELASTIC_WEBSITE_URL: 'https://www.elastic.co/', + DOC_LINK_VERSION: 'current', + }, + }, + }, })); jest.mock('../../../../common', () => ({ diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/index.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/flyout/index.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/flyout/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/disable_internal_collection_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/disable_internal_collection_instructions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/disable_internal_collection_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/disable_internal_collection_instructions.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/enable_metricbeat_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/enable_metricbeat_instructions.js similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/enable_metricbeat_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/enable_metricbeat_instructions.js index 9fa33802b0202..51a7a139aafd0 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/enable_metricbeat_instructions.js +++ b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/enable_metricbeat_instructions.js @@ -8,10 +8,11 @@ import React, { Fragment } from 'react'; import { EuiSpacer, EuiCodeBlock, EuiLink, EuiText } from '@elastic/eui'; import { Monospace } from '../components/monospace'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; +import { Legacy } from '../../../../legacy_shims'; import { getMigrationStatusStep, getSecurityStep } from '../common_instructions'; export function getApmInstructionsForEnablingMetricbeat(product, _meta, { esMonitoringUrl }) { + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; const securitySetup = getSecurityStep( `${ELASTIC_WEBSITE_URL}guide/en/beats/metricbeat/${DOC_LINK_VERSION}/metricbeat-configuration.html` ); diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/index.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/index.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/apm/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/common_beats_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/common_beats_instructions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/common_beats_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/common_beats_instructions.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/disable_internal_collection_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/disable_internal_collection_instructions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/disable_internal_collection_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/disable_internal_collection_instructions.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/enable_metricbeat_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/enable_metricbeat_instructions.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/enable_metricbeat_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/enable_metricbeat_instructions.js index 56e7c9b5af064..ddaa610b874a8 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/enable_metricbeat_instructions.js +++ b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/enable_metricbeat_instructions.js @@ -9,10 +9,11 @@ import { EuiSpacer, EuiCodeBlock, EuiLink, EuiCallOut, EuiText } from '@elastic/ import { Monospace } from '../components/monospace'; import { FormattedMessage } from '@kbn/i18n/react'; import { UNDETECTED_BEAT_TYPE, DEFAULT_BEAT_FOR_URLS } from './common_beats_instructions'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; +import { Legacy } from '../../../../legacy_shims'; import { getMigrationStatusStep, getSecurityStep } from '../common_instructions'; export function getBeatsInstructionsForEnablingMetricbeat(product, _meta, { esMonitoringUrl }) { + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; const beatType = product.beatType; const securitySetup = getSecurityStep( `${ELASTIC_WEBSITE_URL}guide/en/beats/metricbeat/${DOC_LINK_VERSION}/metricbeat-configuration.html` diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/index.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/index.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/beats/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/common_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/common_instructions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/common_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/common_instructions.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/index.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/index.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/monospace.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/monospace.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/monospace.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/components/monospace/monospace.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/disable_internal_collection_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/disable_internal_collection_instructions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/disable_internal_collection_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/disable_internal_collection_instructions.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/enable_metricbeat_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/enable_metricbeat_instructions.js similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/enable_metricbeat_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/enable_metricbeat_instructions.js index 36b3dd21ff43e..8607739e7090c 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/enable_metricbeat_instructions.js +++ b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/enable_metricbeat_instructions.js @@ -8,7 +8,7 @@ import React, { Fragment } from 'react'; import { EuiSpacer, EuiCodeBlock, EuiLink, EuiText } from '@elastic/eui'; import { Monospace } from '../components/monospace'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; +import { Legacy } from '../../../../legacy_shims'; import { getSecurityStep, getMigrationStatusStep } from '../common_instructions'; export function getElasticsearchInstructionsForEnablingMetricbeat( @@ -16,6 +16,7 @@ export function getElasticsearchInstructionsForEnablingMetricbeat( _meta, { esMonitoringUrl } ) { + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; const securitySetup = getSecurityStep( `${ELASTIC_WEBSITE_URL}guide/en/elasticsearch/reference/${DOC_LINK_VERSION}/configuring-metricbeat.html` ); diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/index.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/index.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/elasticsearch/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/get_instruction_steps.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/get_instruction_steps.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/get_instruction_steps.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/get_instruction_steps.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/index.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/index.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/disable_internal_collection_instructions.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/enable_metricbeat_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/enable_metricbeat_instructions.js similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/enable_metricbeat_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/enable_metricbeat_instructions.js index 98c75dbfe4b37..eb1aedd47c568 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/enable_metricbeat_instructions.js +++ b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/enable_metricbeat_instructions.js @@ -8,10 +8,11 @@ import React, { Fragment } from 'react'; import { EuiSpacer, EuiCodeBlock, EuiLink, EuiText } from '@elastic/eui'; import { Monospace } from '../components/monospace'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; +import { Legacy } from '../../../../legacy_shims'; import { getMigrationStatusStep, getSecurityStep } from '../common_instructions'; export function getKibanaInstructionsForEnablingMetricbeat(product, _meta, { esMonitoringUrl }) { + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; const securitySetup = getSecurityStep( `${ELASTIC_WEBSITE_URL}guide/en/kibana/${DOC_LINK_VERSION}/monitoring-metricbeat.html` ); diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/index.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/index.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/kibana/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/disable_internal_collection_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/disable_internal_collection_instructions.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/disable_internal_collection_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/disable_internal_collection_instructions.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/enable_metricbeat_instructions.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/enable_metricbeat_instructions.js similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/enable_metricbeat_instructions.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/enable_metricbeat_instructions.js index 4a36f394e4bd5..ce542fa8a05e5 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/enable_metricbeat_instructions.js +++ b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/enable_metricbeat_instructions.js @@ -8,10 +8,11 @@ import React, { Fragment } from 'react'; import { EuiSpacer, EuiCodeBlock, EuiLink, EuiText } from '@elastic/eui'; import { Monospace } from '../components/monospace'; import { FormattedMessage } from '@kbn/i18n/react'; -import { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } from 'ui/documentation_links'; +import { Legacy } from '../../../../legacy_shims'; import { getMigrationStatusStep, getSecurityStep } from '../common_instructions'; export function getLogstashInstructionsForEnablingMetricbeat(product, _meta, { esMonitoringUrl }) { + const { ELASTIC_WEBSITE_URL, DOC_LINK_VERSION } = Legacy.shims.docLinks; const securitySetup = getSecurityStep( `${ELASTIC_WEBSITE_URL}guide/en/logstash/${DOC_LINK_VERSION}/monitoring-with-metricbeat.html` ); diff --git a/x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/index.js b/x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/index.js rename to x-pack/plugins/monitoring/public/components/metricbeat_migration/instruction_steps/logstash/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/checker_errors.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/checker_errors.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/checker_errors.test.js.snap rename to x-pack/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/checker_errors.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap rename to x-pack/plugins/monitoring/public/components/no_data/__tests__/__snapshots__/no_data.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/checker_errors.test.js b/x-pack/plugins/monitoring/public/components/no_data/__tests__/checker_errors.test.js similarity index 92% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/checker_errors.test.js rename to x-pack/plugins/monitoring/public/components/no_data/__tests__/checker_errors.test.js index 8462d2a6fc87b..f3cd5ccb9703d 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/checker_errors.test.js +++ b/x-pack/plugins/monitoring/public/components/no_data/__tests__/checker_errors.test.js @@ -6,7 +6,7 @@ import React from 'react'; import { boomify, forbidden } from 'boom'; -import { renderWithIntl } from '../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { CheckerErrors } from '../checker_errors'; describe('CheckerErrors', () => { diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/no_data.test.js b/x-pack/plugins/monitoring/public/components/no_data/__tests__/no_data.test.js similarity index 84% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/no_data.test.js rename to x-pack/plugins/monitoring/public/components/no_data/__tests__/no_data.test.js index 81a412a680bc6..5b54df3a82812 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/__tests__/no_data.test.js +++ b/x-pack/plugins/monitoring/public/components/no_data/__tests__/no_data.test.js @@ -5,17 +5,11 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { NoData } from '../'; const enabler = {}; -jest.mock('../../../np_imports/ui/chrome', () => { - return { - getBasePath: () => '', - }; -}); - describe('NoData', () => { test('should show text next to the spinner while checking a setting', () => { const component = renderWithIntl( diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/_index.scss b/x-pack/plugins/monitoring/public/components/no_data/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/_index.scss rename to x-pack/plugins/monitoring/public/components/no_data/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/_no_data.scss b/x-pack/plugins/monitoring/public/components/no_data/_no_data.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/_no_data.scss rename to x-pack/plugins/monitoring/public/components/no_data/_no_data.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/changes_needed.js b/x-pack/plugins/monitoring/public/components/no_data/blurbs/changes_needed.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/changes_needed.js rename to x-pack/plugins/monitoring/public/components/no_data/blurbs/changes_needed.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/cloud_deployment.js b/x-pack/plugins/monitoring/public/components/no_data/blurbs/cloud_deployment.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/cloud_deployment.js rename to x-pack/plugins/monitoring/public/components/no_data/blurbs/cloud_deployment.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/index.js b/x-pack/plugins/monitoring/public/components/no_data/blurbs/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/index.js rename to x-pack/plugins/monitoring/public/components/no_data/blurbs/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/looking_for.js b/x-pack/plugins/monitoring/public/components/no_data/blurbs/looking_for.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/looking_for.js rename to x-pack/plugins/monitoring/public/components/no_data/blurbs/looking_for.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/what_is.js b/x-pack/plugins/monitoring/public/components/no_data/blurbs/what_is.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/blurbs/what_is.js rename to x-pack/plugins/monitoring/public/components/no_data/blurbs/what_is.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/checker_errors.js b/x-pack/plugins/monitoring/public/components/no_data/checker_errors.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/checker_errors.js rename to x-pack/plugins/monitoring/public/components/no_data/checker_errors.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/checking_settings.js b/x-pack/plugins/monitoring/public/components/no_data/checking_settings.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/checking_settings.js rename to x-pack/plugins/monitoring/public/components/no_data/checking_settings.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap rename to x-pack/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/__snapshots__/collection_enabled.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/collection_enabled.test.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/collection_enabled.test.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/collection_enabled.test.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/collection_enabled.test.js index d2be217ca8498..13a49b1c7b200 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/collection_enabled.test.js +++ b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_enabled/__tests__/collection_enabled.test.js @@ -6,7 +6,7 @@ import React from 'react'; import sinon from 'sinon'; -import { mountWithIntl } from '../../../../../../../../../test_utils/enzyme_helpers'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ExplainCollectionEnabled } from '../collection_enabled'; import { findTestSubject } from '@elastic/eui/lib/test'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/collection_enabled/collection_enabled.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap rename to x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/__snapshots__/collection_interval.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/collection_interval.test.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/collection_interval.test.js similarity index 96% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/collection_interval.test.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/collection_interval.test.js index 0a50ad44c8b4f..88185283b6faa 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/collection_interval.test.js +++ b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/__tests__/collection_interval.test.js @@ -6,7 +6,7 @@ import React from 'react'; import sinon from 'sinon'; -import { mountWithIntl } from '../../../../../../../../../test_utils/enzyme_helpers'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { ExplainCollectionInterval } from '../collection_interval'; import { findTestSubject } from '@elastic/eui/lib/test'; diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/collection_interval.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/collection_interval.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/collection_interval/collection_interval.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/collection_interval/collection_interval.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap rename to x-pack/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/__snapshots__/exporters.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js index c9147037f0022..88f1eedfc3bcc 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js +++ b/x-pack/plugins/monitoring/public/components/no_data/explanations/exporters/__tests__/exporters.test.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { ExplainExporters, ExplainExportersCloud } from '../exporters'; // Mocking to prevent errors with React portal. diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/exporters/exporters.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/index.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/index.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap rename to x-pack/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/__snapshots__/plugin_enabled.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js similarity index 92% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js index 56536a8e4270b..ece58ad6aeed2 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js +++ b/x-pack/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/__tests__/plugin_enabled.test.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { ExplainPluginEnabled } from '../plugin_enabled'; // Mocking to prevent errors with React portal. diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js b/x-pack/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js rename to x-pack/plugins/monitoring/public/components/no_data/explanations/plugin_enabled/plugin_enabled.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/index.js b/x-pack/plugins/monitoring/public/components/no_data/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/index.js rename to x-pack/plugins/monitoring/public/components/no_data/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/no_data.js b/x-pack/plugins/monitoring/public/components/no_data/no_data.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/no_data.js rename to x-pack/plugins/monitoring/public/components/no_data/no_data.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap rename to x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/reason_found.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/we_tried.test.js.snap b/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/we_tried.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/we_tried.test.js.snap rename to x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/__snapshots__/we_tried.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js b/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js similarity index 96% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js rename to x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js index e9b2ff11538ab..7f15cacb1ebb9 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js +++ b/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/reason_found.test.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { ReasonFound } from '../'; // Mocking to prevent errors with React portal. diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/we_tried.test.js b/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/we_tried.test.js similarity index 85% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/we_tried.test.js rename to x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/we_tried.test.js index e382a1c9ea8db..95970453d4b7c 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/__tests__/we_tried.test.js +++ b/x-pack/plugins/monitoring/public/components/no_data/reasons/__tests__/we_tried.test.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { WeTried } from '../'; describe('WeTried', () => { diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/index.js b/x-pack/plugins/monitoring/public/components/no_data/reasons/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/index.js rename to x-pack/plugins/monitoring/public/components/no_data/reasons/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/reason_found.js b/x-pack/plugins/monitoring/public/components/no_data/reasons/reason_found.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/reason_found.js rename to x-pack/plugins/monitoring/public/components/no_data/reasons/reason_found.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/we_tried.js b/x-pack/plugins/monitoring/public/components/no_data/reasons/we_tried.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/no_data/reasons/we_tried.js rename to x-pack/plugins/monitoring/public/components/no_data/reasons/we_tried.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap b/x-pack/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap rename to x-pack/plugins/monitoring/public/components/page_loading/__tests__/__snapshots__/page_loading.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/page_loading.test.js b/x-pack/plugins/monitoring/public/components/page_loading/__tests__/page_loading.test.js similarity index 85% rename from x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/page_loading.test.js rename to x-pack/plugins/monitoring/public/components/page_loading/__tests__/page_loading.test.js index b1ad00ffcc3c6..41f3ef4be969e 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/page_loading/__tests__/page_loading.test.js +++ b/x-pack/plugins/monitoring/public/components/page_loading/__tests__/page_loading.test.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { PageLoading } from '../'; describe('PageLoading', () => { diff --git a/x-pack/legacy/plugins/monitoring/public/components/page_loading/index.js b/x-pack/plugins/monitoring/public/components/page_loading/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/page_loading/index.js rename to x-pack/plugins/monitoring/public/components/page_loading/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap b/x-pack/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap rename to x-pack/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/renderers/index.js b/x-pack/plugins/monitoring/public/components/renderers/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/renderers/index.js rename to x-pack/plugins/monitoring/public/components/renderers/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/renderers/lib/find_new_uuid.js b/x-pack/plugins/monitoring/public/components/renderers/lib/find_new_uuid.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/renderers/lib/find_new_uuid.js rename to x-pack/plugins/monitoring/public/components/renderers/lib/find_new_uuid.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/renderers/setup_mode.js b/x-pack/plugins/monitoring/public/components/renderers/setup_mode.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/renderers/setup_mode.js rename to x-pack/plugins/monitoring/public/components/renderers/setup_mode.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/renderers/setup_mode.test.js b/x-pack/plugins/monitoring/public/components/renderers/setup_mode.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/renderers/setup_mode.test.js rename to x-pack/plugins/monitoring/public/components/renderers/setup_mode.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/badge.test.js.snap b/x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/badge.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/badge.test.js.snap rename to x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/badge.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/enter_button.test.tsx.snap b/x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/enter_button.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/enter_button.test.tsx.snap rename to x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/enter_button.test.tsx.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/formatting.test.js.snap b/x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/formatting.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/formatting.test.js.snap rename to x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/formatting.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/listing_callout.test.js.snap b/x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/listing_callout.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/listing_callout.test.js.snap rename to x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/listing_callout.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/tooltip.test.js.snap b/x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/tooltip.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/__snapshots__/tooltip.test.js.snap rename to x-pack/plugins/monitoring/public/components/setup_mode/__snapshots__/tooltip.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/_enter_button.scss b/x-pack/plugins/monitoring/public/components/setup_mode/_enter_button.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/_enter_button.scss rename to x-pack/plugins/monitoring/public/components/setup_mode/_enter_button.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/_index.scss b/x-pack/plugins/monitoring/public/components/setup_mode/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/_index.scss rename to x-pack/plugins/monitoring/public/components/setup_mode/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/badge.js b/x-pack/plugins/monitoring/public/components/setup_mode/badge.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/badge.js rename to x-pack/plugins/monitoring/public/components/setup_mode/badge.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/badge.test.js b/x-pack/plugins/monitoring/public/components/setup_mode/badge.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/badge.test.js rename to x-pack/plugins/monitoring/public/components/setup_mode/badge.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/enter_button.test.tsx b/x-pack/plugins/monitoring/public/components/setup_mode/enter_button.test.tsx similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/enter_button.test.tsx rename to x-pack/plugins/monitoring/public/components/setup_mode/enter_button.test.tsx diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/enter_button.tsx b/x-pack/plugins/monitoring/public/components/setup_mode/enter_button.tsx similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/enter_button.tsx rename to x-pack/plugins/monitoring/public/components/setup_mode/enter_button.tsx diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/formatting.js b/x-pack/plugins/monitoring/public/components/setup_mode/formatting.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/formatting.js rename to x-pack/plugins/monitoring/public/components/setup_mode/formatting.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/formatting.test.js b/x-pack/plugins/monitoring/public/components/setup_mode/formatting.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/formatting.test.js rename to x-pack/plugins/monitoring/public/components/setup_mode/formatting.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/listing_callout.js b/x-pack/plugins/monitoring/public/components/setup_mode/listing_callout.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/listing_callout.js rename to x-pack/plugins/monitoring/public/components/setup_mode/listing_callout.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/listing_callout.test.js b/x-pack/plugins/monitoring/public/components/setup_mode/listing_callout.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/listing_callout.test.js rename to x-pack/plugins/monitoring/public/components/setup_mode/listing_callout.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/tooltip.js b/x-pack/plugins/monitoring/public/components/setup_mode/tooltip.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/tooltip.js rename to x-pack/plugins/monitoring/public/components/setup_mode/tooltip.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/setup_mode/tooltip.test.js b/x-pack/plugins/monitoring/public/components/setup_mode/tooltip.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/setup_mode/tooltip.test.js rename to x-pack/plugins/monitoring/public/components/setup_mode/tooltip.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/sparkline/__mocks__/plugins/xpack_main/jquery_flot.js b/x-pack/plugins/monitoring/public/components/sparkline/__mocks__/plugins/xpack_main/jquery_flot.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/sparkline/__mocks__/plugins/xpack_main/jquery_flot.js rename to x-pack/plugins/monitoring/public/components/sparkline/__mocks__/plugins/xpack_main/jquery_flot.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/sparkline/__test__/__snapshots__/index.test.js.snap b/x-pack/plugins/monitoring/public/components/sparkline/__test__/__snapshots__/index.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/sparkline/__test__/__snapshots__/index.test.js.snap rename to x-pack/plugins/monitoring/public/components/sparkline/__test__/__snapshots__/index.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/sparkline/__test__/index.test.js b/x-pack/plugins/monitoring/public/components/sparkline/__test__/index.test.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/sparkline/__test__/index.test.js rename to x-pack/plugins/monitoring/public/components/sparkline/__test__/index.test.js index 22f4787593fec..ab2cf10b4615d 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/sparkline/__test__/index.test.js +++ b/x-pack/plugins/monitoring/public/components/sparkline/__test__/index.test.js @@ -9,6 +9,10 @@ import renderer from 'react-test-renderer'; import { shallow } from 'enzyme'; import { Sparkline } from '../'; +jest.mock('../sparkline_flot_chart', () => ({ + SparklineFlotChart: () => 'SparklineFlotChart', +})); + describe('Sparkline component', () => { let component; let renderedComponent; diff --git a/x-pack/legacy/plugins/monitoring/public/components/sparkline/_index.scss b/x-pack/plugins/monitoring/public/components/sparkline/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/sparkline/_index.scss rename to x-pack/plugins/monitoring/public/components/sparkline/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/sparkline/_sparkline.scss b/x-pack/plugins/monitoring/public/components/sparkline/_sparkline.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/sparkline/_sparkline.scss rename to x-pack/plugins/monitoring/public/components/sparkline/_sparkline.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/sparkline/index.js b/x-pack/plugins/monitoring/public/components/sparkline/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/sparkline/index.js rename to x-pack/plugins/monitoring/public/components/sparkline/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/sparkline/sparkline_flot_chart.js b/x-pack/plugins/monitoring/public/components/sparkline/sparkline_flot_chart.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/components/sparkline/sparkline_flot_chart.js rename to x-pack/plugins/monitoring/public/components/sparkline/sparkline_flot_chart.js index bb17f464a155a..82d5f53f9fbd7 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/sparkline/sparkline_flot_chart.js +++ b/x-pack/plugins/monitoring/public/components/sparkline/sparkline_flot_chart.js @@ -5,7 +5,7 @@ */ import { last, isFunction, debounce } from 'lodash'; -import $ from 'plugins/xpack_main/jquery_flot'; +import $ from '../../lib/jquery_flot'; import { DEBOUNCE_FAST_MS } from '../../../common/constants'; /** diff --git a/x-pack/legacy/plugins/monitoring/public/components/status_icon/_index.scss b/x-pack/plugins/monitoring/public/components/status_icon/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/status_icon/_index.scss rename to x-pack/plugins/monitoring/public/components/status_icon/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/status_icon/_status_icon.scss b/x-pack/plugins/monitoring/public/components/status_icon/_status_icon.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/status_icon/_status_icon.scss rename to x-pack/plugins/monitoring/public/components/status_icon/_status_icon.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/status_icon/index.js b/x-pack/plugins/monitoring/public/components/status_icon/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/status_icon/index.js rename to x-pack/plugins/monitoring/public/components/status_icon/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap b/x-pack/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap rename to x-pack/plugins/monitoring/public/components/summary_status/__snapshots__/summary_status.test.js.snap diff --git a/x-pack/legacy/plugins/monitoring/public/components/summary_status/_index.scss b/x-pack/plugins/monitoring/public/components/summary_status/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/summary_status/_index.scss rename to x-pack/plugins/monitoring/public/components/summary_status/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/summary_status/_summary_status.scss b/x-pack/plugins/monitoring/public/components/summary_status/_summary_status.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/summary_status/_summary_status.scss rename to x-pack/plugins/monitoring/public/components/summary_status/_summary_status.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/summary_status/index.js b/x-pack/plugins/monitoring/public/components/summary_status/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/summary_status/index.js rename to x-pack/plugins/monitoring/public/components/summary_status/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/summary_status/summary_status.js b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/summary_status/summary_status.js rename to x-pack/plugins/monitoring/public/components/summary_status/summary_status.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/summary_status/summary_status.test.js b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.test.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/components/summary_status/summary_status.test.js rename to x-pack/plugins/monitoring/public/components/summary_status/summary_status.test.js index fe709af266349..5f4dced47ee6f 100644 --- a/x-pack/legacy/plugins/monitoring/public/components/summary_status/summary_status.test.js +++ b/x-pack/plugins/monitoring/public/components/summary_status/summary_status.test.js @@ -5,7 +5,7 @@ */ import React from 'react'; -import { renderWithIntl } from '../../../../../../test_utils/enzyme_helpers'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; import { SummaryStatus } from './summary_status'; jest.mock(`@elastic/eui/lib/components/form/form_row/make_id`, () => () => `generated-id`); diff --git a/x-pack/legacy/plugins/monitoring/public/components/table/_index.scss b/x-pack/plugins/monitoring/public/components/table/_index.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/table/_index.scss rename to x-pack/plugins/monitoring/public/components/table/_index.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/table/_table.scss b/x-pack/plugins/monitoring/public/components/table/_table.scss similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/table/_table.scss rename to x-pack/plugins/monitoring/public/components/table/_table.scss diff --git a/x-pack/legacy/plugins/monitoring/public/components/table/eui_table.js b/x-pack/plugins/monitoring/public/components/table/eui_table.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/table/eui_table.js rename to x-pack/plugins/monitoring/public/components/table/eui_table.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/table/eui_table_ssp.js b/x-pack/plugins/monitoring/public/components/table/eui_table_ssp.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/table/eui_table_ssp.js rename to x-pack/plugins/monitoring/public/components/table/eui_table_ssp.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/table/index.js b/x-pack/plugins/monitoring/public/components/table/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/table/index.js rename to x-pack/plugins/monitoring/public/components/table/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/components/table/storage.js b/x-pack/plugins/monitoring/public/components/table/storage.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/components/table/storage.js rename to x-pack/plugins/monitoring/public/components/table/storage.js diff --git a/x-pack/legacy/plugins/monitoring/public/directives/beats/overview/index.js b/x-pack/plugins/monitoring/public/directives/beats/beat/index.js similarity index 59% rename from x-pack/legacy/plugins/monitoring/public/directives/beats/overview/index.js rename to x-pack/plugins/monitoring/public/directives/beats/beat/index.js index fb78b6a2e0300..103cac98ba564 100644 --- a/x-pack/legacy/plugins/monitoring/public/directives/beats/overview/index.js +++ b/x-pack/plugins/monitoring/public/directives/beats/beat/index.js @@ -6,12 +6,10 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -import { BeatsOverview } from 'plugins/monitoring/components/beats/overview'; -import { I18nContext } from 'ui/i18n'; +import { Beat } from '../../../components/beats/beat'; -const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('monitoringBeatsOverview', () => { +//monitoringBeatsBeat +export function monitoringBeatsBeatProvider() { return { restrict: 'E', scope: { @@ -24,12 +22,15 @@ uiModule.directive('monitoringBeatsOverview', () => { scope.$watch('data', (data = {}) => { render( - - - , + , $el[0] ); }); }, }; -}); +} diff --git a/x-pack/legacy/plugins/monitoring/public/directives/beats/beat/index.js b/x-pack/plugins/monitoring/public/directives/beats/overview/index.js similarity index 55% rename from x-pack/legacy/plugins/monitoring/public/directives/beats/beat/index.js rename to x-pack/plugins/monitoring/public/directives/beats/overview/index.js index c86315fc03482..4faf69e13d02c 100644 --- a/x-pack/legacy/plugins/monitoring/public/directives/beats/beat/index.js +++ b/x-pack/plugins/monitoring/public/directives/beats/overview/index.js @@ -6,12 +6,9 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -import { Beat } from 'plugins/monitoring/components/beats/beat'; -import { I18nContext } from 'ui/i18n'; +import { BeatsOverview } from '../../../components/beats/overview'; -const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('monitoringBeatsBeat', () => { +export function monitoringBeatsOverviewProvider() { return { restrict: 'E', scope: { @@ -24,17 +21,10 @@ uiModule.directive('monitoringBeatsBeat', () => { scope.$watch('data', (data = {}) => { render( - - - , + , $el[0] ); }); }, }; -}); +} diff --git a/x-pack/legacy/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js b/x-pack/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js similarity index 63% rename from x-pack/legacy/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js rename to x-pack/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js index 8f35bd599ac49..706d1ac4c0e33 100644 --- a/x-pack/legacy/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js +++ b/x-pack/plugins/monitoring/public/directives/elasticsearch/ml_job_listing/index.js @@ -8,10 +8,8 @@ import { capitalize } from 'lodash'; import numeral from '@elastic/numeral'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import { I18nContext } from 'ui/i18n'; -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -import { EuiMonitoringTable } from 'plugins/monitoring/components/table'; -import { MachineLearningJobStatusIcon } from 'plugins/monitoring/components/elasticsearch/ml_job_listing/status_icon'; +import { EuiMonitoringTable } from '../../../components/table'; +import { MachineLearningJobStatusIcon } from '../../../components/elasticsearch/ml_job_listing/status_icon'; import { LARGE_ABBREVIATED, LARGE_BYTES } from '../../../../common/formatting'; import { EuiLink, EuiPage, EuiPageContent, EuiPageBody, EuiPanel, EuiSpacer } from '@elastic/eui'; import { ClusterStatus } from '../../../components/elasticsearch/cluster_status'; @@ -93,8 +91,8 @@ const getColumns = (kbnUrl, scope) => [ }, ]; -const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('monitoringMlListing', kbnUrl => { +//monitoringMlListing +export function monitoringMlListingProvider(kbnUrl) { return { restrict: 'E', scope: { @@ -117,51 +115,49 @@ uiModule.directive('monitoringMlListing', kbnUrl => { scope.$watch('jobs', (jobs = []) => { const mlTable = ( - - - - - - - - - - - - - + + + + + + + + + + + ); render(mlTable, $el[0]); }); }, }; -}); +} diff --git a/x-pack/legacy/plugins/monitoring/public/directives/main/__tests__/monitoring_main_controller.js b/x-pack/plugins/monitoring/public/directives/main/__tests__/monitoring_main_controller.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/directives/main/__tests__/monitoring_main_controller.js rename to x-pack/plugins/monitoring/public/directives/main/__tests__/monitoring_main_controller.js diff --git a/x-pack/legacy/plugins/monitoring/public/directives/main/index.html b/x-pack/plugins/monitoring/public/directives/main/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/directives/main/index.html rename to x-pack/plugins/monitoring/public/directives/main/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/directives/main/index.js b/x-pack/plugins/monitoring/public/directives/main/index.js similarity index 93% rename from x-pack/legacy/plugins/monitoring/public/directives/main/index.js rename to x-pack/plugins/monitoring/public/directives/main/index.js index 4e09225cb85e8..8c28ab6103868 100644 --- a/x-pack/legacy/plugins/monitoring/public/directives/main/index.js +++ b/x-pack/plugins/monitoring/public/directives/main/index.js @@ -8,9 +8,8 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { EuiSelect, EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { Legacy } from '../../legacy_shims'; import { shortenPipelineHash } from '../../../common/formatting'; import { getSetupModeState, initSetupModeState } from '../../lib/setup_mode'; import { Subscription } from 'rxjs'; @@ -77,6 +76,7 @@ export class MonitoringMainController { } addTimerangeObservers = () => { + const timefilter = Legacy.shims.timefilter; this.subscriptions = new Subscription(); const refreshIntervalUpdated = () => { @@ -101,6 +101,7 @@ export class MonitoringMainController { // kick things off from the directive link function setup(options) { + const timefilter = Legacy.shims.timefilter; this._licenseService = options.licenseService; this._breadcrumbsService = options.breadcrumbsService; this._kbnUrlService = options.kbnUrlService; @@ -197,8 +198,7 @@ export class MonitoringMainController { } } -const uiModule = uiModules.get('monitoring/directives', []); -uiModule.directive('monitoringMain', (breadcrumbs, license, kbnUrl, $injector) => { +export function monitoringMainProvider(breadcrumbs, license, kbnUrl, $injector) { const $executor = $injector.get('$executor'); return { @@ -209,7 +209,15 @@ uiModule.directive('monitoringMain', (breadcrumbs, license, kbnUrl, $injector) = controllerAs: 'monitoringMain', bindToController: true, link(scope, _element, attributes, controller) { - controller.addTimerangeObservers(); + scope.$applyAsync(() => { + controller.addTimerangeObservers(); + const setupObj = getSetupObj(); + controller.setup(setupObj); + Object.keys(setupObj.attributes).forEach(key => { + attributes.$observe(key, () => controller.setup(getSetupObj())); + }); + }); + initSetupModeState(scope, $injector, () => { controller.setup(getSetupObj()); }); @@ -244,11 +252,6 @@ uiModule.directive('monitoringMain', (breadcrumbs, license, kbnUrl, $injector) = }; } - const setupObj = getSetupObj(); - controller.setup(setupObj); - Object.keys(setupObj.attributes).forEach(key => { - attributes.$observe(key, () => controller.setup(getSetupObj())); - }); scope.$on('$destroy', () => { controller.pipelineDropdownElement && unmountComponentAtNode(controller.pipelineDropdownElement); @@ -260,4 +263,4 @@ uiModule.directive('monitoringMain', (breadcrumbs, license, kbnUrl, $injector) = }); }, }; -}); +} diff --git a/x-pack/legacy/plugins/monitoring/public/icons/health-gray.svg b/x-pack/plugins/monitoring/public/icons/health-gray.svg similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/icons/health-gray.svg rename to x-pack/plugins/monitoring/public/icons/health-gray.svg diff --git a/x-pack/legacy/plugins/monitoring/public/icons/health-green.svg b/x-pack/plugins/monitoring/public/icons/health-green.svg similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/icons/health-green.svg rename to x-pack/plugins/monitoring/public/icons/health-green.svg diff --git a/x-pack/legacy/plugins/monitoring/public/icons/health-red.svg b/x-pack/plugins/monitoring/public/icons/health-red.svg similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/icons/health-red.svg rename to x-pack/plugins/monitoring/public/icons/health-red.svg diff --git a/x-pack/legacy/plugins/monitoring/public/icons/health-yellow.svg b/x-pack/plugins/monitoring/public/icons/health-yellow.svg similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/icons/health-yellow.svg rename to x-pack/plugins/monitoring/public/icons/health-yellow.svg diff --git a/x-pack/legacy/plugins/monitoring/public/index.scss b/x-pack/plugins/monitoring/public/index.scss similarity index 83% rename from x-pack/legacy/plugins/monitoring/public/index.scss rename to x-pack/plugins/monitoring/public/index.scss index 41bca7774a8b8..4dda80ee7454b 100644 --- a/x-pack/legacy/plugins/monitoring/public/index.scss +++ b/x-pack/plugins/monitoring/public/index.scss @@ -21,3 +21,10 @@ @import 'components/logstash/pipeline_viewer/views/index'; @import 'components/elasticsearch/shard_allocation/index'; @import 'components/setup_mode/index'; +@import 'components/elasticsearch/ccr/index'; + +.monitoringApplicationWrapper { + display: flex; + flex-direction: column; + flex-grow: 1; +} diff --git a/x-pack/legacy/plugins/monitoring/public/np_ready/index.ts b/x-pack/plugins/monitoring/public/index.ts similarity index 84% rename from x-pack/legacy/plugins/monitoring/public/np_ready/index.ts rename to x-pack/plugins/monitoring/public/index.ts index 80848c497c370..71c98e8e8b131 100644 --- a/x-pack/legacy/plugins/monitoring/public/np_ready/index.ts +++ b/x-pack/plugins/monitoring/public/index.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { PluginInitializerContext } from 'src/core/public'; +import { PluginInitializerContext } from '../../../../src/core/public'; import { MonitoringPlugin } from './plugin'; export function plugin(ctx: PluginInitializerContext) { diff --git a/x-pack/legacy/plugins/monitoring/public/jest.helpers.ts b/x-pack/plugins/monitoring/public/jest.helpers.ts similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/jest.helpers.ts rename to x-pack/plugins/monitoring/public/jest.helpers.ts index 46ba603d30138..96fb70e480f53 100644 --- a/x-pack/legacy/plugins/monitoring/public/jest.helpers.ts +++ b/x-pack/plugins/monitoring/public/jest.helpers.ts @@ -25,12 +25,3 @@ export function mockUseEffects(count = 1) { spy.mockImplementationOnce(f => f()); } } - -// export function mockUseEffectForDeps(deps, count = 1) { -// const spy = jest.spyOn(React, 'useEffect'); -// for (let i = 0; i < count; i++) { -// spy.mockImplementationOnce((f, depList) => { - -// }); -// } -// } diff --git a/x-pack/plugins/monitoring/public/legacy_shims.ts b/x-pack/plugins/monitoring/public/legacy_shims.ts new file mode 100644 index 0000000000000..47aa1048c5130 --- /dev/null +++ b/x-pack/plugins/monitoring/public/legacy_shims.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 { CoreStart } from 'kibana/public'; +import angular from 'angular'; +import { HttpRequestInit } from '../../../../src/core/public'; +import { MonitoringPluginDependencies } from './types'; + +export interface KFetchQuery { + [key: string]: string | number | boolean | undefined; +} + +export interface KFetchOptions extends HttpRequestInit { + pathname: string; + query?: KFetchQuery; + asSystemRequest?: boolean; +} + +export interface KFetchKibanaOptions { + prependBasePath?: boolean; +} + +export interface IShims { + toastNotifications: CoreStart['notifications']['toasts']; + capabilities: { get: () => CoreStart['application']['capabilities'] }; + getAngularInjector: () => angular.auto.IInjectorService; + getBasePath: () => string; + getInjected: (name: string, defaultValue?: unknown) => unknown; + breadcrumbs: { set: () => void }; + I18nContext: CoreStart['i18n']['Context']; + docLinks: CoreStart['docLinks']; + docTitle: CoreStart['chrome']['docTitle']; + timefilter: MonitoringPluginDependencies['data']['query']['timefilter']['timefilter']; + kfetch: ( + { pathname, ...options }: KFetchOptions, + kfetchOptions?: KFetchKibanaOptions | undefined + ) => Promise; + isCloud: boolean; +} + +export class Legacy { + private static _shims: IShims; + + public static init( + { core, data, isCloud }: MonitoringPluginDependencies, + ngInjector: angular.auto.IInjectorService + ) { + this._shims = { + toastNotifications: core.notifications.toasts, + capabilities: { get: () => core.application.capabilities }, + getAngularInjector: (): angular.auto.IInjectorService => ngInjector, + getBasePath: (): string => core.http.basePath.get(), + getInjected: (name: string, defaultValue?: unknown): string | unknown => + core.injectedMetadata.getInjectedVar(name, defaultValue), + breadcrumbs: { + set: (...args: any[0]) => core.chrome.setBreadcrumbs.apply(this, args), + }, + I18nContext: core.i18n.Context, + docLinks: core.docLinks, + docTitle: core.chrome.docTitle, + timefilter: data.query.timefilter.timefilter, + kfetch: async ( + { pathname, ...options }: KFetchOptions, + kfetchOptions?: KFetchKibanaOptions + ) => + await core.http.fetch(pathname, { + prependBasePath: kfetchOptions?.prependBasePath, + ...options, + }), + isCloud, + }; + } + + public static get shims(): Readonly { + if (!Legacy._shims) { + throw new Error('Legacy needs to be initiated with Legacy.init(...) before use'); + } + return Legacy._shims; + } +} diff --git a/x-pack/legacy/plugins/monitoring/public/lib/__tests__/format_number.js b/x-pack/plugins/monitoring/public/lib/__tests__/format_number.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/lib/__tests__/format_number.js rename to x-pack/plugins/monitoring/public/lib/__tests__/format_number.js diff --git a/x-pack/legacy/plugins/monitoring/public/lib/ajax_error_handler.tsx b/x-pack/plugins/monitoring/public/lib/ajax_error_handler.tsx similarity index 88% rename from x-pack/legacy/plugins/monitoring/public/lib/ajax_error_handler.tsx rename to x-pack/plugins/monitoring/public/lib/ajax_error_handler.tsx index c09014b9a9627..d729457f60df1 100644 --- a/x-pack/legacy/plugins/monitoring/public/lib/ajax_error_handler.tsx +++ b/x-pack/plugins/monitoring/public/lib/ajax_error_handler.tsx @@ -6,12 +6,11 @@ import React from 'react'; import { contains } from 'lodash'; -import { toastNotifications } from 'ui/notify'; -// @ts-ignore -import { formatMsg } from '../../../../../../src/plugins/kibana_legacy/public'; // eslint-disable-line import/order import { EuiButton, EuiSpacer, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public'; +import { Legacy } from '../legacy_shims'; +import { formatMsg } from '../../../../../src/plugins/kibana_legacy/public'; +import { toMountPoint } from '../../../../../src/plugins/kibana_react/public'; export function formatMonitoringError(err: any) { // TODO: We should stop using Boom for errors and instead write a custom handler to return richer error objects @@ -43,7 +42,7 @@ export function ajaxErrorHandlersProvider($injector: any) { kbnUrl.redirect('access-denied'); } else if (err.status === 404 && !contains(window.location.hash, 'no-data')) { // pass through if this is a 404 and we're already on the no-data page - toastNotifications.addDanger({ + Legacy.shims.toastNotifications.addDanger({ title: toMountPoint( string) + labelBoxBorderColor: color + noColumns: number + position: "ne" or "nw" or "se" or "sw" + margin: number of pixels or [x margin, y margin] + backgroundColor: null or color + backgroundOpacity: number between 0 and 1 + container: null or jQuery object/DOM element/jQuery expression + sorted: null/false, true, "ascending", "descending", "reverse", or a comparator +} +``` + +The legend is generated as a table with the data series labels and +small label boxes with the color of the series. If you want to format +the labels in some way, e.g. make them to links, you can pass in a +function for "labelFormatter". Here's an example that makes them +clickable: + +```js +labelFormatter: function(label, series) { + // series is the series object for the label + return '
' + label + ''; +} +``` + +To prevent a series from showing up in the legend, simply have the function +return null. + +"noColumns" is the number of columns to divide the legend table into. +"position" specifies the overall placement of the legend within the +plot (top-right, top-left, etc.) and margin the distance to the plot +edge (this can be either a number or an array of two numbers like [x, +y]). "backgroundColor" and "backgroundOpacity" specifies the +background. The default is a partly transparent auto-detected +background. + +If you want the legend to appear somewhere else in the DOM, you can +specify "container" as a jQuery object/expression to put the legend +table into. The "position" and "margin" etc. options will then be +ignored. Note that Flot will overwrite the contents of the container. + +Legend entries appear in the same order as their series by default. If "sorted" +is "reverse" then they appear in the opposite order from their series. To sort +them alphabetically, you can specify true, "ascending" or "descending", where +true and "ascending" are equivalent. + +You can also provide your own comparator function that accepts two +objects with "label" and "color" properties, and returns zero if they +are equal, a positive value if the first is greater than the second, +and a negative value if the first is less than the second. + +```js +sorted: function(a, b) { + // sort alphabetically in ascending order + return a.label == b.label ? 0 : ( + a.label > b.label ? 1 : -1 + ) +} +``` + + +## Customizing the axes ## + +```js +xaxis, yaxis: { + show: null or true/false + position: "bottom" or "top" or "left" or "right" + mode: null or "time" ("time" requires jquery.flot.time.js plugin) + timezone: null, "browser" or timezone (only makes sense for mode: "time") + + color: null or color spec + tickColor: null or color spec + font: null or font spec object + + min: null or number + max: null or number + autoscaleMargin: null or number + + transform: null or fn: number -> number + inverseTransform: null or fn: number -> number + + ticks: null or number or ticks array or (fn: axis -> ticks array) + tickSize: number or array + minTickSize: number or array + tickFormatter: (fn: number, object -> string) or string + tickDecimals: null or number + + labelWidth: null or number + labelHeight: null or number + reserveSpace: null or true + + tickLength: null or number + + alignTicksWithAxis: null or number +} +``` + +All axes have the same kind of options. The following describes how to +configure one axis, see below for what to do if you've got more than +one x axis or y axis. + +If you don't set the "show" option (i.e. it is null), visibility is +auto-detected, i.e. the axis will show up if there's data associated +with it. You can override this by setting the "show" option to true or +false. + +The "position" option specifies where the axis is placed, bottom or +top for x axes, left or right for y axes. The "mode" option determines +how the data is interpreted, the default of null means as decimal +numbers. Use "time" for time series data; see the time series data +section. The time plugin (jquery.flot.time.js) is required for time +series support. + +The "color" option determines the color of the line and ticks for the axis, and +defaults to the grid color with transparency. For more fine-grained control you +can also set the color of the ticks separately with "tickColor". + +You can customize the font and color used to draw the axis tick labels with CSS +or directly via the "font" option. When "font" is null - the default - each +tick label is given the 'flot-tick-label' class. For compatibility with Flot +0.7 and earlier the labels are also given the 'tickLabel' class, but this is +deprecated and scheduled to be removed with the release of version 1.0.0. + +To enable more granular control over styles, labels are divided between a set +of text containers, with each holding the labels for one axis. These containers +are given the classes 'flot-[x|y]-axis', and 'flot-[x|y]#-axis', where '#' is +the number of the axis when there are multiple axes. For example, the x-axis +labels for a simple plot with only a single x-axis might look like this: + +```html +
+
January 2013
+ ... +
+``` + +For direct control over label styles you can also provide "font" as an object +with this format: + +```js +{ + size: 11, + lineHeight: 13, + style: "italic", + weight: "bold", + family: "sans-serif", + variant: "small-caps", + color: "#545454" +} +``` + +The size and lineHeight must be expressed in pixels; CSS units such as 'em' +or 'smaller' are not allowed. + +The options "min"/"max" are the precise minimum/maximum value on the +scale. If you don't specify either of them, a value will automatically +be chosen based on the minimum/maximum data values. Note that Flot +always examines all the data values you feed to it, even if a +restriction on another axis may make some of them invisible (this +makes interactive use more stable). + +The "autoscaleMargin" is a bit esoteric: it's the fraction of margin +that the scaling algorithm will add to avoid that the outermost points +ends up on the grid border. Note that this margin is only applied when +a min or max value is not explicitly set. If a margin is specified, +the plot will furthermore extend the axis end-point to the nearest +whole tick. The default value is "null" for the x axes and 0.02 for y +axes which seems appropriate for most cases. + +"transform" and "inverseTransform" are callbacks you can put in to +change the way the data is drawn. You can design a function to +compress or expand certain parts of the axis non-linearly, e.g. +suppress weekends or compress far away points with a logarithm or some +other means. When Flot draws the plot, each value is first put through +the transform function. Here's an example, the x axis can be turned +into a natural logarithm axis with the following code: + +```js +xaxis: { + transform: function (v) { return Math.log(v); }, + inverseTransform: function (v) { return Math.exp(v); } +} +``` + +Similarly, for reversing the y axis so the values appear in inverse +order: + +```js +yaxis: { + transform: function (v) { return -v; }, + inverseTransform: function (v) { return -v; } +} +``` + +Note that for finding extrema, Flot assumes that the transform +function does not reorder values (it should be monotone). + +The inverseTransform is simply the inverse of the transform function +(so v == inverseTransform(transform(v)) for all relevant v). It is +required for converting from canvas coordinates to data coordinates, +e.g. for a mouse interaction where a certain pixel is clicked. If you +don't use any interactive features of Flot, you may not need it. + + +The rest of the options deal with the ticks. + +If you don't specify any ticks, a tick generator algorithm will make +some for you. The algorithm has two passes. It first estimates how +many ticks would be reasonable and uses this number to compute a nice +round tick interval size. Then it generates the ticks. + +You can specify how many ticks the algorithm aims for by setting +"ticks" to a number. The algorithm always tries to generate reasonably +round tick values so even if you ask for three ticks, you might get +five if that fits better with the rounding. If you don't want any +ticks at all, set "ticks" to 0 or an empty array. + +Another option is to skip the rounding part and directly set the tick +interval size with "tickSize". If you set it to 2, you'll get ticks at +2, 4, 6, etc. Alternatively, you can specify that you just don't want +ticks at a size less than a specific tick size with "minTickSize". +Note that for time series, the format is an array like [2, "month"], +see the next section. + +If you want to completely override the tick algorithm, you can specify +an array for "ticks", either like this: + +```js +ticks: [0, 1.2, 2.4] +``` + +Or like this where the labels are also customized: + +```js +ticks: [[0, "zero"], [1.2, "one mark"], [2.4, "two marks"]] +``` + +You can mix the two if you like. + +For extra flexibility you can specify a function as the "ticks" +parameter. The function will be called with an object with the axis +min and max and should return a ticks array. Here's a simplistic tick +generator that spits out intervals of pi, suitable for use on the x +axis for trigonometric functions: + +```js +function piTickGenerator(axis) { + var res = [], i = Math.floor(axis.min / Math.PI); + do { + var v = i * Math.PI; + res.push([v, i + "\u03c0"]); + ++i; + } while (v < axis.max); + return res; +} +``` + +You can control how the ticks look like with "tickDecimals", the +number of decimals to display (default is auto-detected). + +Alternatively, for ultimate control over how ticks are formatted you can +provide a function to "tickFormatter". The function is passed two +parameters, the tick value and an axis object with information, and +should return a string. The default formatter looks like this: + +```js +function formatter(val, axis) { + return val.toFixed(axis.tickDecimals); +} +``` + +The axis object has "min" and "max" with the range of the axis, +"tickDecimals" with the number of decimals to round the value to and +"tickSize" with the size of the interval between ticks as calculated +by the automatic axis scaling algorithm (or specified by you). Here's +an example of a custom formatter: + +```js +function suffixFormatter(val, axis) { + if (val > 1000000) + return (val / 1000000).toFixed(axis.tickDecimals) + " MB"; + else if (val > 1000) + return (val / 1000).toFixed(axis.tickDecimals) + " kB"; + else + return val.toFixed(axis.tickDecimals) + " B"; +} +``` + +"labelWidth" and "labelHeight" specifies a fixed size of the tick +labels in pixels. They're useful in case you need to align several +plots. "reserveSpace" means that even if an axis isn't shown, Flot +should reserve space for it - it is useful in combination with +labelWidth and labelHeight for aligning multi-axis charts. + +"tickLength" is the length of the tick lines in pixels. By default, the +innermost axes will have ticks that extend all across the plot, while +any extra axes use small ticks. A value of null means use the default, +while a number means small ticks of that length - set it to 0 to hide +the lines completely. + +If you set "alignTicksWithAxis" to the number of another axis, e.g. +alignTicksWithAxis: 1, Flot will ensure that the autogenerated ticks +of this axis are aligned with the ticks of the other axis. This may +improve the looks, e.g. if you have one y axis to the left and one to +the right, because the grid lines will then match the ticks in both +ends. The trade-off is that the forced ticks won't necessarily be at +natural places. + + +## Multiple axes ## + +If you need more than one x axis or y axis, you need to specify for +each data series which axis they are to use, as described under the +format of the data series, e.g. { data: [...], yaxis: 2 } specifies +that a series should be plotted against the second y axis. + +To actually configure that axis, you can't use the xaxis/yaxis options +directly - instead there are two arrays in the options: + +```js +xaxes: [] +yaxes: [] +``` + +Here's an example of configuring a single x axis and two y axes (we +can leave options of the first y axis empty as the defaults are fine): + +```js +{ + xaxes: [ { position: "top" } ], + yaxes: [ { }, { position: "right", min: 20 } ] +} +``` + +The arrays get their default values from the xaxis/yaxis settings, so +say you want to have all y axes start at zero, you can simply specify +yaxis: { min: 0 } instead of adding a min parameter to all the axes. + +Generally, the various interfaces in Flot dealing with data points +either accept an xaxis/yaxis parameter to specify which axis number to +use (starting from 1), or lets you specify the coordinate directly as +x2/x3/... or x2axis/x3axis/... instead of "x" or "xaxis". + + +## Time series data ## + +Please note that it is now required to include the time plugin, +jquery.flot.time.js, for time series support. + +Time series are a bit more difficult than scalar data because +calendars don't follow a simple base 10 system. For many cases, Flot +abstracts most of this away, but it can still be a bit difficult to +get the data into Flot. So we'll first discuss the data format. + +The time series support in Flot is based on JavaScript timestamps, +i.e. everywhere a time value is expected or handed over, a JavaScript +timestamp number is used. This is a number, not a Date object. A +JavaScript timestamp is the number of milliseconds since January 1, +1970 00:00:00 UTC. This is almost the same as Unix timestamps, except it's +in milliseconds, so remember to multiply by 1000! + +You can see a timestamp like this + +```js +alert((new Date()).getTime()) +``` + +There are different schools of thought when it comes to display of +timestamps. Many will want the timestamps to be displayed according to +a certain time zone, usually the time zone in which the data has been +produced. Some want the localized experience, where the timestamps are +displayed according to the local time of the visitor. Flot supports +both. Optionally you can include a third-party library to get +additional timezone support. + +Default behavior is that Flot always displays timestamps according to +UTC. The reason being that the core JavaScript Date object does not +support other fixed time zones. Often your data is at another time +zone, so it may take a little bit of tweaking to work around this +limitation. + +The easiest way to think about it is to pretend that the data +production time zone is UTC, even if it isn't. So if you have a +datapoint at 2002-02-20 08:00, you can generate a timestamp for eight +o'clock UTC even if it really happened eight o'clock UTC+0200. + +In PHP you can get an appropriate timestamp with: + +```php +strtotime("2002-02-20 UTC") * 1000 +``` + +In Python you can get it with something like: + +```python +calendar.timegm(datetime_object.timetuple()) * 1000 +``` +In Ruby you can get it using the `#to_i` method on the +[`Time`](http://apidock.com/ruby/Time/to_i) object. If you're using the +`active_support` gem (default for Ruby on Rails applications) `#to_i` is also +available on the `DateTime` and `ActiveSupport::TimeWithZone` objects. You +simply need to multiply the result by 1000: + +```ruby +Time.now.to_i * 1000 # => 1383582043000 +# ActiveSupport examples: +DateTime.now.to_i * 1000 # => 1383582043000 +ActiveSupport::TimeZone.new('Asia/Shanghai').now.to_i * 1000 +# => 1383582043000 +``` + +In .NET you can get it with something like: + +```aspx +public static int GetJavaScriptTimestamp(System.DateTime input) +{ + System.TimeSpan span = new System.TimeSpan(System.DateTime.Parse("1/1/1970").Ticks); + System.DateTime time = input.Subtract(span); + return (long)(time.Ticks / 10000); +} +``` + +JavaScript also has some support for parsing date strings, so it is +possible to generate the timestamps manually client-side. + +If you've already got the real UTC timestamp, it's too late to use the +pretend trick described above. But you can fix up the timestamps by +adding the time zone offset, e.g. for UTC+0200 you would add 2 hours +to the UTC timestamp you got. Then it'll look right on the plot. Most +programming environments have some means of getting the timezone +offset for a specific date (note that you need to get the offset for +each individual timestamp to account for daylight savings). + +The alternative with core JavaScript is to interpret the timestamps +according to the time zone that the visitor is in, which means that +the ticks will shift with the time zone and daylight savings of each +visitor. This behavior is enabled by setting the axis option +"timezone" to the value "browser". + +If you need more time zone functionality than this, there is still +another option. If you include the "timezone-js" library + in the page and set axis.timezone +to a value recognized by said library, Flot will use timezone-js to +interpret the timestamps according to that time zone. + +Once you've gotten the timestamps into the data and specified "time" +as the axis mode, Flot will automatically generate relevant ticks and +format them. As always, you can tweak the ticks via the "ticks" option +- just remember that the values should be timestamps (numbers), not +Date objects. + +Tick generation and formatting can also be controlled separately +through the following axis options: + +```js +minTickSize: array +timeformat: null or format string +monthNames: null or array of size 12 of strings +dayNames: null or array of size 7 of strings +twelveHourClock: boolean +``` + +Here "timeformat" is a format string to use. You might use it like +this: + +```js +xaxis: { + mode: "time", + timeformat: "%Y/%m/%d" +} +``` + +This will result in tick labels like "2000/12/24". A subset of the +standard strftime specifiers are supported (plus the nonstandard %q): + +```js +%a: weekday name (customizable) +%b: month name (customizable) +%d: day of month, zero-padded (01-31) +%e: day of month, space-padded ( 1-31) +%H: hours, 24-hour time, zero-padded (00-23) +%I: hours, 12-hour time, zero-padded (01-12) +%m: month, zero-padded (01-12) +%M: minutes, zero-padded (00-59) +%q: quarter (1-4) +%S: seconds, zero-padded (00-59) +%y: year (two digits) +%Y: year (four digits) +%p: am/pm +%P: AM/PM (uppercase version of %p) +%w: weekday as number (0-6, 0 being Sunday) +``` + +Flot 0.8 switched from %h to the standard %H hours specifier. The %h specifier +is still available, for backwards-compatibility, but is deprecated and +scheduled to be removed permanently with the release of version 1.0. + +You can customize the month names with the "monthNames" option. For +instance, for Danish you might specify: + +```js +monthNames: ["jan", "feb", "mar", "apr", "maj", "jun", "jul", "aug", "sep", "okt", "nov", "dec"] +``` + +Similarly you can customize the weekday names with the "dayNames" +option. An example in French: + +```js +dayNames: ["dim", "lun", "mar", "mer", "jeu", "ven", "sam"] +``` + +If you set "twelveHourClock" to true, the autogenerated timestamps +will use 12 hour AM/PM timestamps instead of 24 hour. This only +applies if you have not set "timeformat". Use the "%I" and "%p" or +"%P" options if you want to build your own format string with 12-hour +times. + +If the Date object has a strftime property (and it is a function), it +will be used instead of the built-in formatter. Thus you can include +a strftime library such as http://hacks.bluesmoon.info/strftime/ for +more powerful date/time formatting. + +If everything else fails, you can control the formatting by specifying +a custom tick formatter function as usual. Here's a simple example +which will format December 24 as 24/12: + +```js +tickFormatter: function (val, axis) { + var d = new Date(val); + return d.getUTCDate() + "/" + (d.getUTCMonth() + 1); +} +``` + +Note that for the time mode "tickSize" and "minTickSize" are a bit +special in that they are arrays on the form "[value, unit]" where unit +is one of "second", "minute", "hour", "day", "month" and "year". So +you can specify + +```js +minTickSize: [1, "month"] +``` + +to get a tick interval size of at least 1 month and correspondingly, +if axis.tickSize is [2, "day"] in the tick formatter, the ticks have +been produced with two days in-between. + + +## Customizing the data series ## + +```js +series: { + lines, points, bars: { + show: boolean + lineWidth: number + fill: boolean or number + fillColor: null or color/gradient + } + + lines, bars: { + zero: boolean + } + + points: { + radius: number + symbol: "circle" or function + } + + bars: { + barWidth: number + align: "left", "right" or "center" + horizontal: boolean + } + + lines: { + steps: boolean + } + + shadowSize: number + highlightColor: color or number +} + +colors: [ color1, color2, ... ] +``` + +The options inside "series: {}" are copied to each of the series. So +you can specify that all series should have bars by putting it in the +global options, or override it for individual series by specifying +bars in a particular the series object in the array of data. + +The most important options are "lines", "points" and "bars" that +specify whether and how lines, points and bars should be shown for +each data series. In case you don't specify anything at all, Flot will +default to showing lines (you can turn this off with +lines: { show: false }). You can specify the various types +independently of each other, and Flot will happily draw each of them +in turn (this is probably only useful for lines and points), e.g. + +```js +var options = { + series: { + lines: { show: true, fill: true, fillColor: "rgba(255, 255, 255, 0.8)" }, + points: { show: true, fill: false } + } +}; +``` + +"lineWidth" is the thickness of the line or outline in pixels. You can +set it to 0 to prevent a line or outline from being drawn; this will +also hide the shadow. + +"fill" is whether the shape should be filled. For lines, this produces +area graphs. You can use "fillColor" to specify the color of the fill. +If "fillColor" evaluates to false (default for everything except +points which are filled with white), the fill color is auto-set to the +color of the data series. You can adjust the opacity of the fill by +setting fill to a number between 0 (fully transparent) and 1 (fully +opaque). + +For bars, fillColor can be a gradient, see the gradient documentation +below. "barWidth" is the width of the bars in units of the x axis (or +the y axis if "horizontal" is true), contrary to most other measures +that are specified in pixels. For instance, for time series the unit +is milliseconds so 24 * 60 * 60 * 1000 produces bars with the width of +a day. "align" specifies whether a bar should be left-aligned +(default), right-aligned or centered on top of the value it represents. +When "horizontal" is on, the bars are drawn horizontally, i.e. from the +y axis instead of the x axis; note that the bar end points are still +defined in the same way so you'll probably want to swap the +coordinates if you've been plotting vertical bars first. + +Area and bar charts normally start from zero, regardless of the data's range. +This is because they convey information through size, and starting from a +different value would distort their meaning. In cases where the fill is purely +for decorative purposes, however, "zero" allows you to override this behavior. +It defaults to true for filled lines and bars; setting it to false tells the +series to use the same automatic scaling as an un-filled line. + +For lines, "steps" specifies whether two adjacent data points are +connected with a straight (possibly diagonal) line or with first a +horizontal and then a vertical line. Note that this transforms the +data by adding extra points. + +For points, you can specify the radius and the symbol. The only +built-in symbol type is circles, for other types you can use a plugin +or define them yourself by specifying a callback: + +```js +function cross(ctx, x, y, radius, shadow) { + var size = radius * Math.sqrt(Math.PI) / 2; + ctx.moveTo(x - size, y - size); + ctx.lineTo(x + size, y + size); + ctx.moveTo(x - size, y + size); + ctx.lineTo(x + size, y - size); +} +``` + +The parameters are the drawing context, x and y coordinates of the +center of the point, a radius which corresponds to what the circle +would have used and whether the call is to draw a shadow (due to +limited canvas support, shadows are currently faked through extra +draws). It's good practice to ensure that the area covered by the +symbol is the same as for the circle with the given radius, this +ensures that all symbols have approximately the same visual weight. + +"shadowSize" is the default size of shadows in pixels. Set it to 0 to +remove shadows. + +"highlightColor" is the default color of the translucent overlay used +to highlight the series when the mouse hovers over it. + +The "colors" array specifies a default color theme to get colors for +the data series from. You can specify as many colors as you like, like +this: + +```js +colors: ["#d18b2c", "#dba255", "#919733"] +``` + +If there are more data series than colors, Flot will try to generate +extra colors by lightening and darkening colors in the theme. + + +## Customizing the grid ## + +```js +grid: { + show: boolean + aboveData: boolean + color: color + backgroundColor: color/gradient or null + margin: number or margin object + labelMargin: number + axisMargin: number + markings: array of markings or (fn: axes -> array of markings) + borderWidth: number or object with "top", "right", "bottom" and "left" properties with different widths + borderColor: color or null or object with "top", "right", "bottom" and "left" properties with different colors + minBorderMargin: number or null + clickable: boolean + hoverable: boolean + autoHighlight: boolean + mouseActiveRadius: number +} + +interaction: { + redrawOverlayInterval: number or -1 +} +``` + +The grid is the thing with the axes and a number of ticks. Many of the +things in the grid are configured under the individual axes, but not +all. "color" is the color of the grid itself whereas "backgroundColor" +specifies the background color inside the grid area, here null means +that the background is transparent. You can also set a gradient, see +the gradient documentation below. + +You can turn off the whole grid including tick labels by setting +"show" to false. "aboveData" determines whether the grid is drawn +above the data or below (below is default). + +"margin" is the space in pixels between the canvas edge and the grid, +which can be either a number or an object with individual margins for +each side, in the form: + +```js +margin: { + top: top margin in pixels + left: left margin in pixels + bottom: bottom margin in pixels + right: right margin in pixels +} +``` + +"labelMargin" is the space in pixels between tick labels and axis +line, and "axisMargin" is the space in pixels between axes when there +are two next to each other. + +"borderWidth" is the width of the border around the plot. Set it to 0 +to disable the border. Set it to an object with "top", "right", +"bottom" and "left" properties to use different widths. You can +also set "borderColor" if you want the border to have a different color +than the grid lines. Set it to an object with "top", "right", "bottom" +and "left" properties to use different colors. "minBorderMargin" controls +the default minimum margin around the border - it's used to make sure +that points aren't accidentally clipped by the canvas edge so by default +the value is computed from the point radius. + +"markings" is used to draw simple lines and rectangular areas in the +background of the plot. You can either specify an array of ranges on +the form { xaxis: { from, to }, yaxis: { from, to } } (with multiple +axes, you can specify coordinates for other axes instead, e.g. as +x2axis/x3axis/...) or with a function that returns such an array given +the axes for the plot in an object as the first parameter. + +You can set the color of markings by specifying "color" in the ranges +object. Here's an example array: + +```js +markings: [ { xaxis: { from: 0, to: 2 }, yaxis: { from: 10, to: 10 }, color: "#bb0000" }, ... ] +``` + +If you leave out one of the values, that value is assumed to go to the +border of the plot. So for example if you only specify { xaxis: { +from: 0, to: 2 } } it means an area that extends from the top to the +bottom of the plot in the x range 0-2. + +A line is drawn if from and to are the same, e.g. + +```js +markings: [ { yaxis: { from: 1, to: 1 } }, ... ] +``` + +would draw a line parallel to the x axis at y = 1. You can control the +line width with "lineWidth" in the range object. + +An example function that makes vertical stripes might look like this: + +```js +markings: function (axes) { + var markings = []; + for (var x = Math.floor(axes.xaxis.min); x < axes.xaxis.max; x += 2) + markings.push({ xaxis: { from: x, to: x + 1 } }); + return markings; +} +``` + +If you set "clickable" to true, the plot will listen for click events +on the plot area and fire a "plotclick" event on the placeholder with +a position and a nearby data item object as parameters. The coordinates +are available both in the unit of the axes (not in pixels) and in +global screen coordinates. + +Likewise, if you set "hoverable" to true, the plot will listen for +mouse move events on the plot area and fire a "plothover" event with +the same parameters as the "plotclick" event. If "autoHighlight" is +true (the default), nearby data items are highlighted automatically. +If needed, you can disable highlighting and control it yourself with +the highlight/unhighlight plot methods described elsewhere. + +You can use "plotclick" and "plothover" events like this: + +```js +$.plot($("#placeholder"), [ d ], { grid: { clickable: true } }); + +$("#placeholder").bind("plotclick", function (event, pos, item) { + alert("You clicked at " + pos.x + ", " + pos.y); + // axis coordinates for other axes, if present, are in pos.x2, pos.x3, ... + // if you need global screen coordinates, they are pos.pageX, pos.pageY + + if (item) { + highlight(item.series, item.datapoint); + alert("You clicked a point!"); + } +}); +``` + +The item object in this example is either null or a nearby object on the form: + +```js +item: { + datapoint: the point, e.g. [0, 2] + dataIndex: the index of the point in the data array + series: the series object + seriesIndex: the index of the series + pageX, pageY: the global screen coordinates of the point +} +``` + +For instance, if you have specified the data like this + +```js +$.plot($("#placeholder"), [ { label: "Foo", data: [[0, 10], [7, 3]] } ], ...); +``` + +and the mouse is near the point (7, 3), "datapoint" is [7, 3], +"dataIndex" will be 1, "series" is a normalized series object with +among other things the "Foo" label in series.label and the color in +series.color, and "seriesIndex" is 0. Note that plugins and options +that transform the data can shift the indexes from what you specified +in the original data array. + +If you use the above events to update some other information and want +to clear out that info in case the mouse goes away, you'll probably +also need to listen to "mouseout" events on the placeholder div. + +"mouseActiveRadius" specifies how far the mouse can be from an item +and still activate it. If there are two or more points within this +radius, Flot chooses the closest item. For bars, the top-most bar +(from the latest specified data series) is chosen. + +If you want to disable interactivity for a specific data series, you +can set "hoverable" and "clickable" to false in the options for that +series, like this: + +```js +{ data: [...], label: "Foo", clickable: false } +``` + +"redrawOverlayInterval" specifies the maximum time to delay a redraw +of interactive things (this works as a rate limiting device). The +default is capped to 60 frames per second. You can set it to -1 to +disable the rate limiting. + + +## Specifying gradients ## + +A gradient is specified like this: + +```js +{ colors: [ color1, color2, ... ] } +``` + +For instance, you might specify a background on the grid going from +black to gray like this: + +```js +grid: { + backgroundColor: { colors: ["#000", "#999"] } +} +``` + +For the series you can specify the gradient as an object that +specifies the scaling of the brightness and the opacity of the series +color, e.g. + +```js +{ colors: [{ opacity: 0.8 }, { brightness: 0.6, opacity: 0.8 } ] } +``` + +where the first color simply has its alpha scaled, whereas the second +is also darkened. For instance, for bars the following makes the bars +gradually disappear, without outline: + +```js +bars: { + show: true, + lineWidth: 0, + fill: true, + fillColor: { colors: [ { opacity: 0.8 }, { opacity: 0.1 } ] } +} +``` + +Flot currently only supports vertical gradients drawn from top to +bottom because that's what works with IE. + + +## Plot Methods ## + +The Plot object returned from the plot function has some methods you +can call: + + - highlight(series, datapoint) + + Highlight a specific datapoint in the data series. You can either + specify the actual objects, e.g. if you got them from a + "plotclick" event, or you can specify the indices, e.g. + highlight(1, 3) to highlight the fourth point in the second series + (remember, zero-based indexing). + + - unhighlight(series, datapoint) or unhighlight() + + Remove the highlighting of the point, same parameters as + highlight. + + If you call unhighlight with no parameters, e.g. as + plot.unhighlight(), all current highlights are removed. + + - setData(data) + + You can use this to reset the data used. Note that axis scaling, + ticks, legend etc. will not be recomputed (use setupGrid() to do + that). You'll probably want to call draw() afterwards. + + You can use this function to speed up redrawing a small plot if + you know that the axes won't change. Put in the new data with + setData(newdata), call draw(), and you're good to go. Note that + for large datasets, almost all the time is consumed in draw() + plotting the data so in this case don't bother. + + - setupGrid() + + Recalculate and set axis scaling, ticks, legend etc. + + Note that because of the drawing model of the canvas, this + function will immediately redraw (actually reinsert in the DOM) + the labels and the legend, but not the actual tick lines because + they're drawn on the canvas. You need to call draw() to get the + canvas redrawn. + + - draw() + + Redraws the plot canvas. + + - triggerRedrawOverlay() + + Schedules an update of an overlay canvas used for drawing + interactive things like a selection and point highlights. This + is mostly useful for writing plugins. The redraw doesn't happen + immediately, instead a timer is set to catch multiple successive + redraws (e.g. from a mousemove). You can get to the overlay by + setting up a drawOverlay hook. + + - width()/height() + + Gets the width and height of the plotting area inside the grid. + This is smaller than the canvas or placeholder dimensions as some + extra space is needed (e.g. for labels). + + - offset() + + Returns the offset of the plotting area inside the grid relative + to the document, useful for instance for calculating mouse + positions (event.pageX/Y minus this offset is the pixel position + inside the plot). + + - pointOffset({ x: xpos, y: ypos }) + + Returns the calculated offset of the data point at (x, y) in data + space within the placeholder div. If you are working with multiple + axes, you can specify the x and y axis references, e.g. + + ```js + o = pointOffset({ x: xpos, y: ypos, xaxis: 2, yaxis: 3 }) + // o.left and o.top now contains the offset within the div + ```` + + - resize() + + Tells Flot to resize the drawing canvas to the size of the + placeholder. You need to run setupGrid() and draw() afterwards as + canvas resizing is a destructive operation. This is used + internally by the resize plugin. + + - shutdown() + + Cleans up any event handlers Flot has currently registered. This + is used internally. + +There are also some members that let you peek inside the internal +workings of Flot which is useful in some cases. Note that if you change +something in the objects returned, you're changing the objects used by +Flot to keep track of its state, so be careful. + + - getData() + + Returns an array of the data series currently used in normalized + form with missing settings filled in according to the global + options. So for instance to find out what color Flot has assigned + to the data series, you could do this: + + ```js + var series = plot.getData(); + for (var i = 0; i < series.length; ++i) + alert(series[i].color); + ``` + + A notable other interesting field besides color is datapoints + which has a field "points" with the normalized data points in a + flat array (the field "pointsize" is the increment in the flat + array to get to the next point so for a dataset consisting only of + (x,y) pairs it would be 2). + + - getAxes() + + Gets an object with the axes. The axes are returned as the + attributes of the object, so for instance getAxes().xaxis is the + x axis. + + Various things are stuffed inside an axis object, e.g. you could + use getAxes().xaxis.ticks to find out what the ticks are for the + xaxis. Two other useful attributes are p2c and c2p, functions for + transforming from data point space to the canvas plot space and + back. Both returns values that are offset with the plot offset. + Check the Flot source code for the complete set of attributes (or + output an axis with console.log() and inspect it). + + With multiple axes, the extra axes are returned as x2axis, x3axis, + etc., e.g. getAxes().y2axis is the second y axis. You can check + y2axis.used to see whether the axis is associated with any data + points and y2axis.show to see if it is currently shown. + + - getPlaceholder() + + Returns placeholder that the plot was put into. This can be useful + for plugins for adding DOM elements or firing events. + + - getCanvas() + + Returns the canvas used for drawing in case you need to hack on it + yourself. You'll probably need to get the plot offset too. + + - getPlotOffset() + + Gets the offset that the grid has within the canvas as an object + with distances from the canvas edges as "left", "right", "top", + "bottom". I.e., if you draw a circle on the canvas with the center + placed at (left, top), its center will be at the top-most, left + corner of the grid. + + - getOptions() + + Gets the options for the plot, normalized, with default values + filled in. You get a reference to actual values used by Flot, so + if you modify the values in here, Flot will use the new values. + If you change something, you probably have to call draw() or + setupGrid() or triggerRedrawOverlay() to see the change. + + +## Hooks ## + +In addition to the public methods, the Plot object also has some hooks +that can be used to modify the plotting process. You can install a +callback function at various points in the process, the function then +gets access to the internal data structures in Flot. + +Here's an overview of the phases Flot goes through: + + 1. Plugin initialization, parsing options + + 2. Constructing the canvases used for drawing + + 3. Set data: parsing data specification, calculating colors, + copying raw data points into internal format, + normalizing them, finding max/min for axis auto-scaling + + 4. Grid setup: calculating axis spacing, ticks, inserting tick + labels, the legend + + 5. Draw: drawing the grid, drawing each of the series in turn + + 6. Setting up event handling for interactive features + + 7. Responding to events, if any + + 8. Shutdown: this mostly happens in case a plot is overwritten + +Each hook is simply a function which is put in the appropriate array. +You can add them through the "hooks" option, and they are also available +after the plot is constructed as the "hooks" attribute on the returned +plot object, e.g. + +```js + // define a simple draw hook + function hellohook(plot, canvascontext) { alert("hello!"); }; + + // pass it in, in an array since we might want to specify several + var plot = $.plot(placeholder, data, { hooks: { draw: [hellohook] } }); + + // we can now find it again in plot.hooks.draw[0] unless a plugin + // has added other hooks +``` + +The available hooks are described below. All hook callbacks get the +plot object as first parameter. You can find some examples of defined +hooks in the plugins bundled with Flot. + + - processOptions [phase 1] + + ```function(plot, options)``` + + Called after Flot has parsed and merged options. Useful in the + instance where customizations beyond simple merging of default + values is needed. A plugin might use it to detect that it has been + enabled and then turn on or off other options. + + + - processRawData [phase 3] + + ```function(plot, series, data, datapoints)``` + + Called before Flot copies and normalizes the raw data for the given + series. If the function fills in datapoints.points with normalized + points and sets datapoints.pointsize to the size of the points, + Flot will skip the copying/normalization step for this series. + + In any case, you might be interested in setting datapoints.format, + an array of objects for specifying how a point is normalized and + how it interferes with axis scaling. It accepts the following options: + + ```js + { + x, y: boolean, + number: boolean, + required: boolean, + defaultValue: value, + autoscale: boolean + } + ``` + + "x" and "y" specify whether the value is plotted against the x or y axis, + and is currently used only to calculate axis min-max ranges. The default + format array, for example, looks like this: + + ```js + [ + { x: true, number: true, required: true }, + { y: true, number: true, required: true } + ] + ``` + + This indicates that a point, i.e. [0, 25], consists of two values, with the + first being plotted on the x axis and the second on the y axis. + + If "number" is true, then the value must be numeric, and is set to null if + it cannot be converted to a number. + + "defaultValue" provides a fallback in case the original value is null. This + is for instance handy for bars, where one can omit the third coordinate + (the bottom of the bar), which then defaults to zero. + + If "required" is true, then the value must exist (be non-null) for the + point as a whole to be valid. If no value is provided, then the entire + point is cleared out with nulls, turning it into a gap in the series. + + "autoscale" determines whether the value is considered when calculating an + automatic min-max range for the axes that the value is plotted against. + + - processDatapoints [phase 3] + + ```function(plot, series, datapoints)``` + + Called after normalization of the given series but before finding + min/max of the data points. This hook is useful for implementing data + transformations. "datapoints" contains the normalized data points in + a flat array as datapoints.points with the size of a single point + given in datapoints.pointsize. Here's a simple transform that + multiplies all y coordinates by 2: + + ```js + function multiply(plot, series, datapoints) { + var points = datapoints.points, ps = datapoints.pointsize; + for (var i = 0; i < points.length; i += ps) + points[i + 1] *= 2; + } + ``` + + Note that you must leave datapoints in a good condition as Flot + doesn't check it or do any normalization on it afterwards. + + - processOffset [phase 4] + + ```function(plot, offset)``` + + Called after Flot has initialized the plot's offset, but before it + draws any axes or plot elements. This hook is useful for customizing + the margins between the grid and the edge of the canvas. "offset" is + an object with attributes "top", "bottom", "left" and "right", + corresponding to the margins on the four sides of the plot. + + - drawBackground [phase 5] + + ```function(plot, canvascontext)``` + + Called before all other drawing operations. Used to draw backgrounds + or other custom elements before the plot or axes have been drawn. + + - drawSeries [phase 5] + + ```function(plot, canvascontext, series)``` + + Hook for custom drawing of a single series. Called just before the + standard drawing routine has been called in the loop that draws + each series. + + - draw [phase 5] + + ```function(plot, canvascontext)``` + + Hook for drawing on the canvas. Called after the grid is drawn + (unless it's disabled or grid.aboveData is set) and the series have + been plotted (in case any points, lines or bars have been turned + on). For examples of how to draw things, look at the source code. + + - bindEvents [phase 6] + + ```function(plot, eventHolder)``` + + Called after Flot has setup its event handlers. Should set any + necessary event handlers on eventHolder, a jQuery object with the + canvas, e.g. + + ```js + function (plot, eventHolder) { + eventHolder.mousedown(function (e) { + alert("You pressed the mouse at " + e.pageX + " " + e.pageY); + }); + } + ``` + + Interesting events include click, mousemove, mouseup/down. You can + use all jQuery events. Usually, the event handlers will update the + state by drawing something (add a drawOverlay hook and call + triggerRedrawOverlay) or firing an externally visible event for + user code. See the crosshair plugin for an example. + + Currently, eventHolder actually contains both the static canvas + used for the plot itself and the overlay canvas used for + interactive features because some versions of IE get the stacking + order wrong. The hook only gets one event, though (either for the + overlay or for the static canvas). + + Note that custom plot events generated by Flot are not generated on + eventHolder, but on the div placeholder supplied as the first + argument to the plot call. You can get that with + plot.getPlaceholder() - that's probably also the one you should use + if you need to fire a custom event. + + - drawOverlay [phase 7] + + ```function (plot, canvascontext)``` + + The drawOverlay hook is used for interactive things that need a + canvas to draw on. The model currently used by Flot works the way + that an extra overlay canvas is positioned on top of the static + canvas. This overlay is cleared and then completely redrawn + whenever something interesting happens. This hook is called when + the overlay canvas is to be redrawn. + + "canvascontext" is the 2D context of the overlay canvas. You can + use this to draw things. You'll most likely need some of the + metrics computed by Flot, e.g. plot.width()/plot.height(). See the + crosshair plugin for an example. + + - shutdown [phase 8] + + ```function (plot, eventHolder)``` + + Run when plot.shutdown() is called, which usually only happens in + case a plot is overwritten by a new plot. If you're writing a + plugin that adds extra DOM elements or event handlers, you should + add a callback to clean up after you. Take a look at the section in + the [PLUGINS](PLUGINS.md) document for more info. + + +## Plugins ## + +Plugins extend the functionality of Flot. To use a plugin, simply +include its JavaScript file after Flot in the HTML page. + +If you're worried about download size/latency, you can concatenate all +the plugins you use, and Flot itself for that matter, into one big file +(make sure you get the order right), then optionally run it through a +JavaScript minifier such as YUI Compressor. + +Here's a brief explanation of how the plugin plumbings work: + +Each plugin registers itself in the global array $.plot.plugins. When +you make a new plot object with $.plot, Flot goes through this array +calling the "init" function of each plugin and merging default options +from the "option" attribute of the plugin. The init function gets a +reference to the plot object created and uses this to register hooks +and add new public methods if needed. + +See the [PLUGINS](PLUGINS.md) document for details on how to write a plugin. As the +above description hints, it's actually pretty easy. + + +## Version number ## + +The version number of Flot is available in ```$.plot.version```. diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/index.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/index.js new file mode 100644 index 0000000000000..613939256cfc9 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/index.js @@ -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. + */ + +/* @notice + * + * This product includes code that is based on flot-charts, which was available + * under a "MIT" license. + * + * The MIT License (MIT) + * + * Copyright (c) 2007-2014 IOLA and Ole Laursen + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +import $ from 'jquery'; +if (window) window.jQuery = $; +require('./jquery.flot'); +require('./jquery.flot.time'); +require('./jquery.flot.canvas'); +require('./jquery.flot.symbol'); +require('./jquery.flot.crosshair'); +require('./jquery.flot.selection'); +require('./jquery.flot.pie'); +require('./jquery.flot.stack'); +require('./jquery.flot.threshold'); +require('./jquery.flot.fillbetween'); +require('./jquery.flot.log'); +module.exports = $; diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.colorhelpers.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.colorhelpers.js new file mode 100644 index 0000000000000..b2f6dc4e433a3 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.colorhelpers.js @@ -0,0 +1,180 @@ +/* Plugin for jQuery for working with colors. + * + * Version 1.1. + * + * Inspiration from jQuery color animation plugin by John Resig. + * + * Released under the MIT license by Ole Laursen, October 2009. + * + * Examples: + * + * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString() + * var c = $.color.extract($("#mydiv"), 'background-color'); + * console.log(c.r, c.g, c.b, c.a); + * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)" + * + * Note that .scale() and .add() return the same modified object + * instead of making a new one. + * + * V. 1.1: Fix error handling so e.g. parsing an empty string does + * produce a color rather than just crashing. + */ + +(function($) { + $.color = {}; + + // construct color object with some convenient chainable helpers + $.color.make = function (r, g, b, a) { + var o = {}; + o.r = r || 0; + o.g = g || 0; + o.b = b || 0; + o.a = a != null ? a : 1; + + o.add = function (c, d) { + for (var i = 0; i < c.length; ++i) + o[c.charAt(i)] += d; + return o.normalize(); + }; + + o.scale = function (c, f) { + for (var i = 0; i < c.length; ++i) + o[c.charAt(i)] *= f; + return o.normalize(); + }; + + o.toString = function () { + if (o.a >= 1.0) { + return "rgb("+[o.r, o.g, o.b].join(",")+")"; + } else { + return "rgba("+[o.r, o.g, o.b, o.a].join(",")+")"; + } + }; + + o.normalize = function () { + function clamp(min, value, max) { + return value < min ? min: (value > max ? max: value); + } + + o.r = clamp(0, parseInt(o.r), 255); + o.g = clamp(0, parseInt(o.g), 255); + o.b = clamp(0, parseInt(o.b), 255); + o.a = clamp(0, o.a, 1); + return o; + }; + + o.clone = function () { + return $.color.make(o.r, o.b, o.g, o.a); + }; + + return o.normalize(); + } + + // extract CSS color property from element, going up in the DOM + // if it's "transparent" + $.color.extract = function (elem, css) { + var c; + + do { + c = elem.css(css).toLowerCase(); + // keep going until we find an element that has color, or + // we hit the body or root (have no parent) + if (c != '' && c != 'transparent') + break; + elem = elem.parent(); + } while (elem.length && !$.nodeName(elem.get(0), "body")); + + // catch Safari's way of signalling transparent + if (c == "rgba(0, 0, 0, 0)") + c = "transparent"; + + return $.color.parse(c); + } + + // parse CSS color string (like "rgb(10, 32, 43)" or "#fff"), + // returns color object, if parsing failed, you get black (0, 0, + // 0) out + $.color.parse = function (str) { + var res, m = $.color.make; + + // Look for rgb(num,num,num) + if (res = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str)) + return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10)); + + // Look for rgba(num,num,num,num) + if (res = /rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)) + return m(parseInt(res[1], 10), parseInt(res[2], 10), parseInt(res[3], 10), parseFloat(res[4])); + + // Look for rgb(num%,num%,num%) + if (res = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str)) + return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55); + + // Look for rgba(num%,num%,num%,num) + if (res = /rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str)) + return m(parseFloat(res[1])*2.55, parseFloat(res[2])*2.55, parseFloat(res[3])*2.55, parseFloat(res[4])); + + // Look for #a0b1c2 + if (res = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str)) + return m(parseInt(res[1], 16), parseInt(res[2], 16), parseInt(res[3], 16)); + + // Look for #fff + if (res = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str)) + return m(parseInt(res[1]+res[1], 16), parseInt(res[2]+res[2], 16), parseInt(res[3]+res[3], 16)); + + // Otherwise, we're most likely dealing with a named color + var name = $.trim(str).toLowerCase(); + if (name == "transparent") + return m(255, 255, 255, 0); + else { + // default to black + res = lookupColors[name] || [0, 0, 0]; + return m(res[0], res[1], res[2]); + } + } + + var lookupColors = { + aqua:[0,255,255], + azure:[240,255,255], + beige:[245,245,220], + black:[0,0,0], + blue:[0,0,255], + brown:[165,42,42], + cyan:[0,255,255], + darkblue:[0,0,139], + darkcyan:[0,139,139], + darkgrey:[169,169,169], + darkgreen:[0,100,0], + darkkhaki:[189,183,107], + darkmagenta:[139,0,139], + darkolivegreen:[85,107,47], + darkorange:[255,140,0], + darkorchid:[153,50,204], + darkred:[139,0,0], + darksalmon:[233,150,122], + darkviolet:[148,0,211], + fuchsia:[255,0,255], + gold:[255,215,0], + green:[0,128,0], + indigo:[75,0,130], + khaki:[240,230,140], + lightblue:[173,216,230], + lightcyan:[224,255,255], + lightgreen:[144,238,144], + lightgrey:[211,211,211], + lightpink:[255,182,193], + lightyellow:[255,255,224], + lime:[0,255,0], + magenta:[255,0,255], + maroon:[128,0,0], + navy:[0,0,128], + olive:[128,128,0], + orange:[255,165,0], + pink:[255,192,203], + purple:[128,0,128], + violet:[128,0,128], + red:[255,0,0], + silver:[192,192,192], + white:[255,255,255], + yellow:[255,255,0] + }; +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.canvas.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.canvas.js new file mode 100644 index 0000000000000..29328d5812127 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.canvas.js @@ -0,0 +1,345 @@ +/* Flot plugin for drawing all elements of a plot on the canvas. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Flot normally produces certain elements, like axis labels and the legend, using +HTML elements. This permits greater interactivity and customization, and often +looks better, due to cross-browser canvas text inconsistencies and limitations. + +It can also be desirable to render the plot entirely in canvas, particularly +if the goal is to save it as an image, or if Flot is being used in a context +where the HTML DOM does not exist, as is the case within Node.js. This plugin +switches out Flot's standard drawing operations for canvas-only replacements. + +Currently the plugin supports only axis labels, but it will eventually allow +every element of the plot to be rendered directly to canvas. + +The plugin supports these options: + +{ + canvas: boolean +} + +The "canvas" option controls whether full canvas drawing is enabled, making it +possible to toggle on and off. This is useful when a plot uses HTML text in the +browser, but needs to redraw with canvas text when exporting as an image. + +*/ + +(function($) { + + var options = { + canvas: true + }; + + var render, getTextInfo, addText; + + // Cache the prototype hasOwnProperty for faster access + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + function init(plot, classes) { + + var Canvas = classes.Canvas; + + // We only want to replace the functions once; the second time around + // we would just get our new function back. This whole replacing of + // prototype functions is a disaster, and needs to be changed ASAP. + + if (render == null) { + getTextInfo = Canvas.prototype.getTextInfo, + addText = Canvas.prototype.addText, + render = Canvas.prototype.render; + } + + // Finishes rendering the canvas, including overlaid text + + Canvas.prototype.render = function() { + + if (!plot.getOptions().canvas) { + return render.call(this); + } + + var context = this.context, + cache = this._textCache; + + // For each text layer, render elements marked as active + + context.save(); + context.textBaseline = "middle"; + + for (var layerKey in cache) { + if (hasOwnProperty.call(cache, layerKey)) { + var layerCache = cache[layerKey]; + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey], + updateStyles = true; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + + var info = styleCache[key], + positions = info.positions, + lines = info.lines; + + // Since every element at this level of the cache have the + // same font and fill styles, we can just change them once + // using the values from the first element. + + if (updateStyles) { + context.fillStyle = info.font.color; + context.font = info.font.definition; + updateStyles = false; + } + + for (var i = 0, position; position = positions[i]; i++) { + if (position.active) { + for (var j = 0, line; line = position.lines[j]; j++) { + context.fillText(lines[j].text, line[0], line[1]); + } + } else { + positions.splice(i--, 1); + } + } + + if (positions.length == 0) { + delete styleCache[key]; + } + } + } + } + } + } + } + + context.restore(); + }; + + // Creates (if necessary) and returns a text info object. + // + // When the canvas option is set, the object looks like this: + // + // { + // width: Width of the text's bounding box. + // height: Height of the text's bounding box. + // positions: Array of positions at which this text is drawn. + // lines: [{ + // height: Height of this line. + // widths: Width of this line. + // text: Text on this line. + // }], + // font: { + // definition: Canvas font property string. + // color: Color of the text. + // }, + // } + // + // The positions array contains objects that look like this: + // + // { + // active: Flag indicating whether the text should be visible. + // lines: Array of [x, y] coordinates at which to draw the line. + // x: X coordinate at which to draw the text. + // y: Y coordinate at which to draw the text. + // } + + Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { + + if (!plot.getOptions().canvas) { + return getTextInfo.call(this, layer, text, font, angle, width); + } + + var textStyle, layerCache, styleCache, info; + + // Cast the value to a string, in case we were given a number + + text = "" + text; + + // If the font is a font-spec object, generate a CSS definition + + if (typeof font === "object") { + textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px " + font.family; + } else { + textStyle = font; + } + + // Retrieve (or create) the cache for the text's layer and styles + + layerCache = this._textCache[layer]; + + if (layerCache == null) { + layerCache = this._textCache[layer] = {}; + } + + styleCache = layerCache[textStyle]; + + if (styleCache == null) { + styleCache = layerCache[textStyle] = {}; + } + + info = styleCache[text]; + + if (info == null) { + + var context = this.context; + + // If the font was provided as CSS, create a div with those + // classes and examine it to generate a canvas font spec. + + if (typeof font !== "object") { + + var element = $("
 
") + .css("position", "absolute") + .addClass(typeof font === "string" ? font : null) + .appendTo(this.getTextLayer(layer)); + + font = { + lineHeight: element.height(), + style: element.css("font-style"), + variant: element.css("font-variant"), + weight: element.css("font-weight"), + family: element.css("font-family"), + color: element.css("color") + }; + + // Setting line-height to 1, without units, sets it equal + // to the font-size, even if the font-size is abstract, + // like 'smaller'. This enables us to read the real size + // via the element's height, working around browsers that + // return the literal 'smaller' value. + + font.size = element.css("line-height", 1).height(); + + element.remove(); + } + + textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px " + font.family; + + // Create a new info object, initializing the dimensions to + // zero so we can count them up line-by-line. + + info = styleCache[text] = { + width: 0, + height: 0, + positions: [], + lines: [], + font: { + definition: textStyle, + color: font.color + } + }; + + context.save(); + context.font = textStyle; + + // Canvas can't handle multi-line strings; break on various + // newlines, including HTML brs, to build a list of lines. + // Note that we could split directly on regexps, but IE < 9 is + // broken; revisit when we drop IE 7/8 support. + + var lines = (text + "").replace(/
|\r\n|\r/g, "\n").split("\n"); + + for (var i = 0; i < lines.length; ++i) { + + var lineText = lines[i], + measured = context.measureText(lineText); + + info.width = Math.max(measured.width, info.width); + info.height += font.lineHeight; + + info.lines.push({ + text: lineText, + width: measured.width, + height: font.lineHeight + }); + } + + context.restore(); + } + + return info; + }; + + // Adds a text string to the canvas text overlay. + + Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) { + + if (!plot.getOptions().canvas) { + return addText.call(this, layer, x, y, text, font, angle, width, halign, valign); + } + + var info = this.getTextInfo(layer, text, font, angle, width), + positions = info.positions, + lines = info.lines; + + // Text is drawn with baseline 'middle', which we need to account + // for by adding half a line's height to the y position. + + y += info.height / lines.length / 2; + + // Tweak the initial y-position to match vertical alignment + + if (valign == "middle") { + y = Math.round(y - info.height / 2); + } else if (valign == "bottom") { + y = Math.round(y - info.height); + } else { + y = Math.round(y); + } + + // FIXME: LEGACY BROWSER FIX + // AFFECTS: Opera < 12.00 + + // Offset the y coordinate, since Opera is off pretty + // consistently compared to the other browsers. + + if (!!(window.opera && window.opera.version().split(".")[0] < 12)) { + y -= 2; + } + + // Determine whether this text already exists at this position. + // If so, mark it for inclusion in the next render pass. + + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = true; + return; + } + } + + // If the text doesn't exist at this position, create a new entry + + position = { + active: true, + lines: [], + x: x, + y: y + }; + + positions.push(position); + + // Fill in the x & y positions of each line, adjusting them + // individually for horizontal alignment. + + for (var i = 0, line; line = lines[i]; i++) { + if (halign == "center") { + position.lines.push([Math.round(x - line.width / 2), y]); + } else if (halign == "right") { + position.lines.push([Math.round(x - line.width), y]); + } else { + position.lines.push([Math.round(x), y]); + } + y += line.height; + } + }; + } + + $.plot.plugins.push({ + init: init, + options: options, + name: "canvas", + version: "1.0" + }); + +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.categories.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.categories.js new file mode 100644 index 0000000000000..2f9b257971499 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.categories.js @@ -0,0 +1,190 @@ +/* Flot plugin for plotting textual data or categories. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Consider a dataset like [["February", 34], ["March", 20], ...]. This plugin +allows you to plot such a dataset directly. + +To enable it, you must specify mode: "categories" on the axis with the textual +labels, e.g. + + $.plot("#placeholder", data, { xaxis: { mode: "categories" } }); + +By default, the labels are ordered as they are met in the data series. If you +need a different ordering, you can specify "categories" on the axis options +and list the categories there: + + xaxis: { + mode: "categories", + categories: ["February", "March", "April"] + } + +If you need to customize the distances between the categories, you can specify +"categories" as an object mapping labels to values + + xaxis: { + mode: "categories", + categories: { "February": 1, "March": 3, "April": 4 } + } + +If you don't specify all categories, the remaining categories will be numbered +from the max value plus 1 (with a spacing of 1 between each). + +Internally, the plugin works by transforming the input data through an auto- +generated mapping where the first category becomes 0, the second 1, etc. +Hence, a point like ["February", 34] becomes [0, 34] internally in Flot (this +is visible in hover and click events that return numbers rather than the +category labels). The plugin also overrides the tick generator to spit out the +categories as ticks instead of the values. + +If you need to map a value back to its label, the mapping is always accessible +as "categories" on the axis object, e.g. plot.getAxes().xaxis.categories. + +*/ + +(function ($) { + var options = { + xaxis: { + categories: null + }, + yaxis: { + categories: null + } + }; + + function processRawData(plot, series, data, datapoints) { + // if categories are enabled, we need to disable + // auto-transformation to numbers so the strings are intact + // for later processing + + var xCategories = series.xaxis.options.mode == "categories", + yCategories = series.yaxis.options.mode == "categories"; + + if (!(xCategories || yCategories)) + return; + + var format = datapoints.format; + + if (!format) { + // FIXME: auto-detection should really not be defined here + var s = series; + format = []; + format.push({ x: true, number: true, required: true }); + format.push({ y: true, number: true, required: true }); + + if (s.bars.show || (s.lines.show && s.lines.fill)) { + var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero)); + format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale }); + if (s.bars.horizontal) { + delete format[format.length - 1].y; + format[format.length - 1].x = true; + } + } + + datapoints.format = format; + } + + for (var m = 0; m < format.length; ++m) { + if (format[m].x && xCategories) + format[m].number = false; + + if (format[m].y && yCategories) + format[m].number = false; + } + } + + function getNextIndex(categories) { + var index = -1; + + for (var v in categories) + if (categories[v] > index) + index = categories[v]; + + return index + 1; + } + + function categoriesTickGenerator(axis) { + var res = []; + for (var label in axis.categories) { + var v = axis.categories[label]; + if (v >= axis.min && v <= axis.max) + res.push([v, label]); + } + + res.sort(function (a, b) { return a[0] - b[0]; }); + + return res; + } + + function setupCategoriesForAxis(series, axis, datapoints) { + if (series[axis].options.mode != "categories") + return; + + if (!series[axis].categories) { + // parse options + var c = {}, o = series[axis].options.categories || {}; + if ($.isArray(o)) { + for (var i = 0; i < o.length; ++i) + c[o[i]] = i; + } + else { + for (var v in o) + c[v] = o[v]; + } + + series[axis].categories = c; + } + + // fix ticks + if (!series[axis].options.ticks) + series[axis].options.ticks = categoriesTickGenerator; + + transformPointsOnAxis(datapoints, axis, series[axis].categories); + } + + function transformPointsOnAxis(datapoints, axis, categories) { + // go through the points, transforming them + var points = datapoints.points, + ps = datapoints.pointsize, + format = datapoints.format, + formatColumn = axis.charAt(0), + index = getNextIndex(categories); + + for (var i = 0; i < points.length; i += ps) { + if (points[i] == null) + continue; + + for (var m = 0; m < ps; ++m) { + var val = points[i + m]; + + if (val == null || !format[m][formatColumn]) + continue; + + if (!(val in categories)) { + categories[val] = index; + ++index; + } + + points[i + m] = categories[val]; + } + } + } + + function processDatapoints(plot, series, datapoints) { + setupCategoriesForAxis(series, "xaxis", datapoints); + setupCategoriesForAxis(series, "yaxis", datapoints); + } + + function init(plot) { + plot.hooks.processRawData.push(processRawData); + plot.hooks.processDatapoints.push(processDatapoints); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'categories', + version: '1.0' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.crosshair.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.crosshair.js new file mode 100644 index 0000000000000..5111695e3d12c --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.crosshair.js @@ -0,0 +1,176 @@ +/* Flot plugin for showing crosshairs when the mouse hovers over the plot. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + + crosshair: { + mode: null or "x" or "y" or "xy" + color: color + lineWidth: number + } + +Set the mode to one of "x", "y" or "xy". The "x" mode enables a vertical +crosshair that lets you trace the values on the x axis, "y" enables a +horizontal crosshair and "xy" enables them both. "color" is the color of the +crosshair (default is "rgba(170, 0, 0, 0.80)"), "lineWidth" is the width of +the drawn lines (default is 1). + +The plugin also adds four public methods: + + - setCrosshair( pos ) + + Set the position of the crosshair. Note that this is cleared if the user + moves the mouse. "pos" is in coordinates of the plot and should be on the + form { x: xpos, y: ypos } (you can use x2/x3/... if you're using multiple + axes), which is coincidentally the same format as what you get from a + "plothover" event. If "pos" is null, the crosshair is cleared. + + - clearCrosshair() + + Clear the crosshair. + + - lockCrosshair(pos) + + Cause the crosshair to lock to the current location, no longer updating if + the user moves the mouse. Optionally supply a position (passed on to + setCrosshair()) to move it to. + + Example usage: + + var myFlot = $.plot( $("#graph"), ..., { crosshair: { mode: "x" } } }; + $("#graph").bind( "plothover", function ( evt, position, item ) { + if ( item ) { + // Lock the crosshair to the data point being hovered + myFlot.lockCrosshair({ + x: item.datapoint[ 0 ], + y: item.datapoint[ 1 ] + }); + } else { + // Return normal crosshair operation + myFlot.unlockCrosshair(); + } + }); + + - unlockCrosshair() + + Free the crosshair to move again after locking it. +*/ + +(function ($) { + var options = { + crosshair: { + mode: null, // one of null, "x", "y" or "xy", + color: "rgba(170, 0, 0, 0.80)", + lineWidth: 1 + } + }; + + function init(plot) { + // position of crosshair in pixels + var crosshair = { x: -1, y: -1, locked: false }; + + plot.setCrosshair = function setCrosshair(pos) { + if (!pos) + crosshair.x = -1; + else { + var o = plot.p2c(pos); + crosshair.x = Math.max(0, Math.min(o.left, plot.width())); + crosshair.y = Math.max(0, Math.min(o.top, plot.height())); + } + + plot.triggerRedrawOverlay(); + }; + + plot.clearCrosshair = plot.setCrosshair; // passes null for pos + + plot.lockCrosshair = function lockCrosshair(pos) { + if (pos) + plot.setCrosshair(pos); + crosshair.locked = true; + }; + + plot.unlockCrosshair = function unlockCrosshair() { + crosshair.locked = false; + }; + + function onMouseOut(e) { + if (crosshair.locked) + return; + + if (crosshair.x != -1) { + crosshair.x = -1; + plot.triggerRedrawOverlay(); + } + } + + function onMouseMove(e) { + if (crosshair.locked) + return; + + if (plot.getSelection && plot.getSelection()) { + crosshair.x = -1; // hide the crosshair while selecting + return; + } + + var offset = plot.offset(); + crosshair.x = Math.max(0, Math.min(e.pageX - offset.left, plot.width())); + crosshair.y = Math.max(0, Math.min(e.pageY - offset.top, plot.height())); + plot.triggerRedrawOverlay(); + } + + plot.hooks.bindEvents.push(function (plot, eventHolder) { + if (!plot.getOptions().crosshair.mode) + return; + + eventHolder.mouseout(onMouseOut); + eventHolder.mousemove(onMouseMove); + }); + + plot.hooks.drawOverlay.push(function (plot, ctx) { + var c = plot.getOptions().crosshair; + if (!c.mode) + return; + + var plotOffset = plot.getPlotOffset(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + if (crosshair.x != -1) { + var adj = plot.getOptions().crosshair.lineWidth % 2 ? 0.5 : 0; + + ctx.strokeStyle = c.color; + ctx.lineWidth = c.lineWidth; + ctx.lineJoin = "round"; + + ctx.beginPath(); + if (c.mode.indexOf("x") != -1) { + var drawX = Math.floor(crosshair.x) + adj; + ctx.moveTo(drawX, 0); + ctx.lineTo(drawX, plot.height()); + } + if (c.mode.indexOf("y") != -1) { + var drawY = Math.floor(crosshair.y) + adj; + ctx.moveTo(0, drawY); + ctx.lineTo(plot.width(), drawY); + } + ctx.stroke(); + } + ctx.restore(); + }); + + plot.hooks.shutdown.push(function (plot, eventHolder) { + eventHolder.unbind("mouseout", onMouseOut); + eventHolder.unbind("mousemove", onMouseMove); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'crosshair', + version: '1.0' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.errorbars.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.errorbars.js new file mode 100644 index 0000000000000..655036e0db846 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.errorbars.js @@ -0,0 +1,353 @@ +/* Flot plugin for plotting error bars. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Error bars are used to show standard deviation and other statistical +properties in a plot. + +* Created by Rui Pereira - rui (dot) pereira (at) gmail (dot) com + +This plugin allows you to plot error-bars over points. Set "errorbars" inside +the points series to the axis name over which there will be error values in +your data array (*even* if you do not intend to plot them later, by setting +"show: null" on xerr/yerr). + +The plugin supports these options: + + series: { + points: { + errorbars: "x" or "y" or "xy", + xerr: { + show: null/false or true, + asymmetric: null/false or true, + upperCap: null or "-" or function, + lowerCap: null or "-" or function, + color: null or color, + radius: null or number + }, + yerr: { same options as xerr } + } + } + +Each data point array is expected to be of the type: + + "x" [ x, y, xerr ] + "y" [ x, y, yerr ] + "xy" [ x, y, xerr, yerr ] + +Where xerr becomes xerr_lower,xerr_upper for the asymmetric error case, and +equivalently for yerr. E.g., a datapoint for the "xy" case with symmetric +error-bars on X and asymmetric on Y would be: + + [ x, y, xerr, yerr_lower, yerr_upper ] + +By default no end caps are drawn. Setting upperCap and/or lowerCap to "-" will +draw a small cap perpendicular to the error bar. They can also be set to a +user-defined drawing function, with (ctx, x, y, radius) as parameters, as e.g.: + + function drawSemiCircle( ctx, x, y, radius ) { + ctx.beginPath(); + ctx.arc( x, y, radius, 0, Math.PI, false ); + ctx.moveTo( x - radius, y ); + ctx.lineTo( x + radius, y ); + ctx.stroke(); + } + +Color and radius both default to the same ones of the points series if not +set. The independent radius parameter on xerr/yerr is useful for the case when +we may want to add error-bars to a line, without showing the interconnecting +points (with radius: 0), and still showing end caps on the error-bars. +shadowSize and lineWidth are derived as well from the points series. + +*/ + +(function ($) { + var options = { + series: { + points: { + errorbars: null, //should be 'x', 'y' or 'xy' + xerr: { err: 'x', show: null, asymmetric: null, upperCap: null, lowerCap: null, color: null, radius: null}, + yerr: { err: 'y', show: null, asymmetric: null, upperCap: null, lowerCap: null, color: null, radius: null} + } + } + }; + + function processRawData(plot, series, data, datapoints){ + if (!series.points.errorbars) + return; + + // x,y values + var format = [ + { x: true, number: true, required: true }, + { y: true, number: true, required: true } + ]; + + var errors = series.points.errorbars; + // error bars - first X then Y + if (errors == 'x' || errors == 'xy') { + // lower / upper error + if (series.points.xerr.asymmetric) { + format.push({ x: true, number: true, required: true }); + format.push({ x: true, number: true, required: true }); + } else + format.push({ x: true, number: true, required: true }); + } + if (errors == 'y' || errors == 'xy') { + // lower / upper error + if (series.points.yerr.asymmetric) { + format.push({ y: true, number: true, required: true }); + format.push({ y: true, number: true, required: true }); + } else + format.push({ y: true, number: true, required: true }); + } + datapoints.format = format; + } + + function parseErrors(series, i){ + + var points = series.datapoints.points; + + // read errors from points array + var exl = null, + exu = null, + eyl = null, + eyu = null; + var xerr = series.points.xerr, + yerr = series.points.yerr; + + var eb = series.points.errorbars; + // error bars - first X + if (eb == 'x' || eb == 'xy') { + if (xerr.asymmetric) { + exl = points[i + 2]; + exu = points[i + 3]; + if (eb == 'xy') + if (yerr.asymmetric){ + eyl = points[i + 4]; + eyu = points[i + 5]; + } else eyl = points[i + 4]; + } else { + exl = points[i + 2]; + if (eb == 'xy') + if (yerr.asymmetric) { + eyl = points[i + 3]; + eyu = points[i + 4]; + } else eyl = points[i + 3]; + } + // only Y + } else if (eb == 'y') + if (yerr.asymmetric) { + eyl = points[i + 2]; + eyu = points[i + 3]; + } else eyl = points[i + 2]; + + // symmetric errors? + if (exu == null) exu = exl; + if (eyu == null) eyu = eyl; + + var errRanges = [exl, exu, eyl, eyu]; + // nullify if not showing + if (!xerr.show){ + errRanges[0] = null; + errRanges[1] = null; + } + if (!yerr.show){ + errRanges[2] = null; + errRanges[3] = null; + } + return errRanges; + } + + function drawSeriesErrors(plot, ctx, s){ + + var points = s.datapoints.points, + ps = s.datapoints.pointsize, + ax = [s.xaxis, s.yaxis], + radius = s.points.radius, + err = [s.points.xerr, s.points.yerr]; + + //sanity check, in case some inverted axis hack is applied to flot + var invertX = false; + if (ax[0].p2c(ax[0].max) < ax[0].p2c(ax[0].min)) { + invertX = true; + var tmp = err[0].lowerCap; + err[0].lowerCap = err[0].upperCap; + err[0].upperCap = tmp; + } + + var invertY = false; + if (ax[1].p2c(ax[1].min) < ax[1].p2c(ax[1].max)) { + invertY = true; + var tmp = err[1].lowerCap; + err[1].lowerCap = err[1].upperCap; + err[1].upperCap = tmp; + } + + for (var i = 0; i < s.datapoints.points.length; i += ps) { + + //parse + var errRanges = parseErrors(s, i); + + //cycle xerr & yerr + for (var e = 0; e < err.length; e++){ + + var minmax = [ax[e].min, ax[e].max]; + + //draw this error? + if (errRanges[e * err.length]){ + + //data coordinates + var x = points[i], + y = points[i + 1]; + + //errorbar ranges + var upper = [x, y][e] + errRanges[e * err.length + 1], + lower = [x, y][e] - errRanges[e * err.length]; + + //points outside of the canvas + if (err[e].err == 'x') + if (y > ax[1].max || y < ax[1].min || upper < ax[0].min || lower > ax[0].max) + continue; + if (err[e].err == 'y') + if (x > ax[0].max || x < ax[0].min || upper < ax[1].min || lower > ax[1].max) + continue; + + // prevent errorbars getting out of the canvas + var drawUpper = true, + drawLower = true; + + if (upper > minmax[1]) { + drawUpper = false; + upper = minmax[1]; + } + if (lower < minmax[0]) { + drawLower = false; + lower = minmax[0]; + } + + //sanity check, in case some inverted axis hack is applied to flot + if ((err[e].err == 'x' && invertX) || (err[e].err == 'y' && invertY)) { + //swap coordinates + var tmp = lower; + lower = upper; + upper = tmp; + tmp = drawLower; + drawLower = drawUpper; + drawUpper = tmp; + tmp = minmax[0]; + minmax[0] = minmax[1]; + minmax[1] = tmp; + } + + // convert to pixels + x = ax[0].p2c(x), + y = ax[1].p2c(y), + upper = ax[e].p2c(upper); + lower = ax[e].p2c(lower); + minmax[0] = ax[e].p2c(minmax[0]); + minmax[1] = ax[e].p2c(minmax[1]); + + //same style as points by default + var lw = err[e].lineWidth ? err[e].lineWidth : s.points.lineWidth, + sw = s.points.shadowSize != null ? s.points.shadowSize : s.shadowSize; + + //shadow as for points + if (lw > 0 && sw > 0) { + var w = sw / 2; + ctx.lineWidth = w; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, w + w/2, minmax); + + ctx.strokeStyle = "rgba(0,0,0,0.2)"; + drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, w/2, minmax); + } + + ctx.strokeStyle = err[e].color? err[e].color: s.color; + ctx.lineWidth = lw; + //draw it + drawError(ctx, err[e], x, y, upper, lower, drawUpper, drawLower, radius, 0, minmax); + } + } + } + } + + function drawError(ctx,err,x,y,upper,lower,drawUpper,drawLower,radius,offset,minmax){ + + //shadow offset + y += offset; + upper += offset; + lower += offset; + + // error bar - avoid plotting over circles + if (err.err == 'x'){ + if (upper > x + radius) drawPath(ctx, [[upper,y],[Math.max(x + radius,minmax[0]),y]]); + else drawUpper = false; + if (lower < x - radius) drawPath(ctx, [[Math.min(x - radius,minmax[1]),y],[lower,y]] ); + else drawLower = false; + } + else { + if (upper < y - radius) drawPath(ctx, [[x,upper],[x,Math.min(y - radius,minmax[0])]] ); + else drawUpper = false; + if (lower > y + radius) drawPath(ctx, [[x,Math.max(y + radius,minmax[1])],[x,lower]] ); + else drawLower = false; + } + + //internal radius value in errorbar, allows to plot radius 0 points and still keep proper sized caps + //this is a way to get errorbars on lines without visible connecting dots + radius = err.radius != null? err.radius: radius; + + // upper cap + if (drawUpper) { + if (err.upperCap == '-'){ + if (err.err=='x') drawPath(ctx, [[upper,y - radius],[upper,y + radius]] ); + else drawPath(ctx, [[x - radius,upper],[x + radius,upper]] ); + } else if ($.isFunction(err.upperCap)){ + if (err.err=='x') err.upperCap(ctx, upper, y, radius); + else err.upperCap(ctx, x, upper, radius); + } + } + // lower cap + if (drawLower) { + if (err.lowerCap == '-'){ + if (err.err=='x') drawPath(ctx, [[lower,y - radius],[lower,y + radius]] ); + else drawPath(ctx, [[x - radius,lower],[x + radius,lower]] ); + } else if ($.isFunction(err.lowerCap)){ + if (err.err=='x') err.lowerCap(ctx, lower, y, radius); + else err.lowerCap(ctx, x, lower, radius); + } + } + } + + function drawPath(ctx, pts){ + ctx.beginPath(); + ctx.moveTo(pts[0][0], pts[0][1]); + for (var p=1; p < pts.length; p++) + ctx.lineTo(pts[p][0], pts[p][1]); + ctx.stroke(); + } + + function draw(plot, ctx){ + var plotOffset = plot.getPlotOffset(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + $.each(plot.getData(), function (i, s) { + if (s.points.errorbars && (s.points.xerr.show || s.points.yerr.show)) + drawSeriesErrors(plot, ctx, s); + }); + ctx.restore(); + } + + function init(plot) { + plot.hooks.processRawData.push(processRawData); + plot.hooks.draw.push(draw); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'errorbars', + version: '1.0' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.fillbetween.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.fillbetween.js new file mode 100644 index 0000000000000..18b15d26db8c9 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.fillbetween.js @@ -0,0 +1,226 @@ +/* Flot plugin for computing bottoms for filled line and bar charts. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The case: you've got two series that you want to fill the area between. In Flot +terms, you need to use one as the fill bottom of the other. You can specify the +bottom of each data point as the third coordinate manually, or you can use this +plugin to compute it for you. + +In order to name the other series, you need to give it an id, like this: + + var dataset = [ + { data: [ ... ], id: "foo" } , // use default bottom + { data: [ ... ], fillBetween: "foo" }, // use first dataset as bottom + ]; + + $.plot($("#placeholder"), dataset, { lines: { show: true, fill: true }}); + +As a convenience, if the id given is a number that doesn't appear as an id in +the series, it is interpreted as the index in the array instead (so fillBetween: +0 can also mean the first series). + +Internally, the plugin modifies the datapoints in each series. For line series, +extra data points might be inserted through interpolation. Note that at points +where the bottom line is not defined (due to a null point or start/end of line), +the current line will show a gap too. The algorithm comes from the +jquery.flot.stack.js plugin, possibly some code could be shared. + +*/ + +(function ( $ ) { + + var options = { + series: { + fillBetween: null // or number + } + }; + + function init( plot ) { + + function findBottomSeries( s, allseries ) { + + var i; + + for ( i = 0; i < allseries.length; ++i ) { + if ( allseries[ i ].id === s.fillBetween ) { + return allseries[ i ]; + } + } + + if ( typeof s.fillBetween === "number" ) { + if ( s.fillBetween < 0 || s.fillBetween >= allseries.length ) { + return null; + } + return allseries[ s.fillBetween ]; + } + + return null; + } + + function computeFillBottoms( plot, s, datapoints ) { + + if ( s.fillBetween == null ) { + return; + } + + var other = findBottomSeries( s, plot.getData() ); + + if ( !other ) { + return; + } + + var ps = datapoints.pointsize, + points = datapoints.points, + otherps = other.datapoints.pointsize, + otherpoints = other.datapoints.points, + newpoints = [], + px, py, intery, qx, qy, bottom, + withlines = s.lines.show, + withbottom = ps > 2 && datapoints.format[2].y, + withsteps = withlines && s.lines.steps, + fromgap = true, + i = 0, + j = 0, + l, m; + + while ( true ) { + + if ( i >= points.length ) { + break; + } + + l = newpoints.length; + + if ( points[ i ] == null ) { + + // copy gaps + + for ( m = 0; m < ps; ++m ) { + newpoints.push( points[ i + m ] ); + } + + i += ps; + + } else if ( j >= otherpoints.length ) { + + // for lines, we can't use the rest of the points + + if ( !withlines ) { + for ( m = 0; m < ps; ++m ) { + newpoints.push( points[ i + m ] ); + } + } + + i += ps; + + } else if ( otherpoints[ j ] == null ) { + + // oops, got a gap + + for ( m = 0; m < ps; ++m ) { + newpoints.push( null ); + } + + fromgap = true; + j += otherps; + + } else { + + // cases where we actually got two points + + px = points[ i ]; + py = points[ i + 1 ]; + qx = otherpoints[ j ]; + qy = otherpoints[ j + 1 ]; + bottom = 0; + + if ( px === qx ) { + + for ( m = 0; m < ps; ++m ) { + newpoints.push( points[ i + m ] ); + } + + //newpoints[ l + 1 ] += qy; + bottom = qy; + + i += ps; + j += otherps; + + } else if ( px > qx ) { + + // we got past point below, might need to + // insert interpolated extra point + + if ( withlines && i > 0 && points[ i - ps ] != null ) { + intery = py + ( points[ i - ps + 1 ] - py ) * ( qx - px ) / ( points[ i - ps ] - px ); + newpoints.push( qx ); + newpoints.push( intery ); + for ( m = 2; m < ps; ++m ) { + newpoints.push( points[ i + m ] ); + } + bottom = qy; + } + + j += otherps; + + } else { // px < qx + + // if we come from a gap, we just skip this point + + if ( fromgap && withlines ) { + i += ps; + continue; + } + + for ( m = 0; m < ps; ++m ) { + newpoints.push( points[ i + m ] ); + } + + // we might be able to interpolate a point below, + // this can give us a better y + + if ( withlines && j > 0 && otherpoints[ j - otherps ] != null ) { + bottom = qy + ( otherpoints[ j - otherps + 1 ] - qy ) * ( px - qx ) / ( otherpoints[ j - otherps ] - qx ); + } + + //newpoints[l + 1] += bottom; + + i += ps; + } + + fromgap = false; + + if ( l !== newpoints.length && withbottom ) { + newpoints[ l + 2 ] = bottom; + } + } + + // maintain the line steps invariant + + if ( withsteps && l !== newpoints.length && l > 0 && + newpoints[ l ] !== null && + newpoints[ l ] !== newpoints[ l - ps ] && + newpoints[ l + 1 ] !== newpoints[ l - ps + 1 ] ) { + for (m = 0; m < ps; ++m) { + newpoints[ l + ps + m ] = newpoints[ l + m ]; + } + newpoints[ l + 1 ] = newpoints[ l - ps + 1 ]; + } + } + + datapoints.points = newpoints; + } + + plot.hooks.processDatapoints.push( computeFillBottoms ); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: "fillbetween", + version: "1.0" + }); + +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.image.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.image.js new file mode 100644 index 0000000000000..178f0e69069ef --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.image.js @@ -0,0 +1,241 @@ +/* Flot plugin for plotting images. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The data syntax is [ [ image, x1, y1, x2, y2 ], ... ] where (x1, y1) and +(x2, y2) are where you intend the two opposite corners of the image to end up +in the plot. Image must be a fully loaded JavaScript image (you can make one +with new Image()). If the image is not complete, it's skipped when plotting. + +There are two helpers included for retrieving images. The easiest work the way +that you put in URLs instead of images in the data, like this: + + [ "myimage.png", 0, 0, 10, 10 ] + +Then call $.plot.image.loadData( data, options, callback ) where data and +options are the same as you pass in to $.plot. This loads the images, replaces +the URLs in the data with the corresponding images and calls "callback" when +all images are loaded (or failed loading). In the callback, you can then call +$.plot with the data set. See the included example. + +A more low-level helper, $.plot.image.load(urls, callback) is also included. +Given a list of URLs, it calls callback with an object mapping from URL to +Image object when all images are loaded or have failed loading. + +The plugin supports these options: + + series: { + images: { + show: boolean + anchor: "corner" or "center" + alpha: [ 0, 1 ] + } + } + +They can be specified for a specific series: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + images: { ... } + ]) + +Note that because the data format is different from usual data points, you +can't use images with anything else in a specific data series. + +Setting "anchor" to "center" causes the pixels in the image to be anchored at +the corner pixel centers inside of at the pixel corners, effectively letting +half a pixel stick out to each side in the plot. + +A possible future direction could be support for tiling for large images (like +Google Maps). + +*/ + +(function ($) { + var options = { + series: { + images: { + show: false, + alpha: 1, + anchor: "corner" // or "center" + } + } + }; + + $.plot.image = {}; + + $.plot.image.loadDataImages = function (series, options, callback) { + var urls = [], points = []; + + var defaultShow = options.series.images.show; + + $.each(series, function (i, s) { + if (!(defaultShow || s.images.show)) + return; + + if (s.data) + s = s.data; + + $.each(s, function (i, p) { + if (typeof p[0] == "string") { + urls.push(p[0]); + points.push(p); + } + }); + }); + + $.plot.image.load(urls, function (loadedImages) { + $.each(points, function (i, p) { + var url = p[0]; + if (loadedImages[url]) + p[0] = loadedImages[url]; + }); + + callback(); + }); + } + + $.plot.image.load = function (urls, callback) { + var missing = urls.length, loaded = {}; + if (missing == 0) + callback({}); + + $.each(urls, function (i, url) { + var handler = function () { + --missing; + + loaded[url] = this; + + if (missing == 0) + callback(loaded); + }; + + $('').load(handler).error(handler).attr('src', url); + }); + }; + + function drawSeries(plot, ctx, series) { + var plotOffset = plot.getPlotOffset(); + + if (!series.images || !series.images.show) + return; + + var points = series.datapoints.points, + ps = series.datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + var img = points[i], + x1 = points[i + 1], y1 = points[i + 2], + x2 = points[i + 3], y2 = points[i + 4], + xaxis = series.xaxis, yaxis = series.yaxis, + tmp; + + // actually we should check img.complete, but it + // appears to be a somewhat unreliable indicator in + // IE6 (false even after load event) + if (!img || img.width <= 0 || img.height <= 0) + continue; + + if (x1 > x2) { + tmp = x2; + x2 = x1; + x1 = tmp; + } + if (y1 > y2) { + tmp = y2; + y2 = y1; + y1 = tmp; + } + + // if the anchor is at the center of the pixel, expand the + // image by 1/2 pixel in each direction + if (series.images.anchor == "center") { + tmp = 0.5 * (x2-x1) / (img.width - 1); + x1 -= tmp; + x2 += tmp; + tmp = 0.5 * (y2-y1) / (img.height - 1); + y1 -= tmp; + y2 += tmp; + } + + // clip + if (x1 == x2 || y1 == y2 || + x1 >= xaxis.max || x2 <= xaxis.min || + y1 >= yaxis.max || y2 <= yaxis.min) + continue; + + var sx1 = 0, sy1 = 0, sx2 = img.width, sy2 = img.height; + if (x1 < xaxis.min) { + sx1 += (sx2 - sx1) * (xaxis.min - x1) / (x2 - x1); + x1 = xaxis.min; + } + + if (x2 > xaxis.max) { + sx2 += (sx2 - sx1) * (xaxis.max - x2) / (x2 - x1); + x2 = xaxis.max; + } + + if (y1 < yaxis.min) { + sy2 += (sy1 - sy2) * (yaxis.min - y1) / (y2 - y1); + y1 = yaxis.min; + } + + if (y2 > yaxis.max) { + sy1 += (sy1 - sy2) * (yaxis.max - y2) / (y2 - y1); + y2 = yaxis.max; + } + + x1 = xaxis.p2c(x1); + x2 = xaxis.p2c(x2); + y1 = yaxis.p2c(y1); + y2 = yaxis.p2c(y2); + + // the transformation may have swapped us + if (x1 > x2) { + tmp = x2; + x2 = x1; + x1 = tmp; + } + if (y1 > y2) { + tmp = y2; + y2 = y1; + y1 = tmp; + } + + tmp = ctx.globalAlpha; + ctx.globalAlpha *= series.images.alpha; + ctx.drawImage(img, + sx1, sy1, sx2 - sx1, sy2 - sy1, + x1 + plotOffset.left, y1 + plotOffset.top, + x2 - x1, y2 - y1); + ctx.globalAlpha = tmp; + } + } + + function processRawData(plot, series, data, datapoints) { + if (!series.images.show) + return; + + // format is Image, x1, y1, x2, y2 (opposite corners) + datapoints.format = [ + { required: true }, + { x: true, number: true, required: true }, + { y: true, number: true, required: true }, + { x: true, number: true, required: true }, + { y: true, number: true, required: true } + ]; + } + + function init(plot) { + plot.hooks.processRawData.push(processRawData); + plot.hooks.drawSeries.push(drawSeries); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'image', + version: '1.1' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.js new file mode 100644 index 0000000000000..43db1cc3d93db --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.js @@ -0,0 +1,3168 @@ +/* JavaScript plotting library for jQuery, version 0.8.3. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +*/ + +// first an inline dependency, jquery.colorhelpers.js, we inline it here +// for convenience + +/* Plugin for jQuery for working with colors. + * + * Version 1.1. + * + * Inspiration from jQuery color animation plugin by John Resig. + * + * Released under the MIT license by Ole Laursen, October 2009. + * + * Examples: + * + * $.color.parse("#fff").scale('rgb', 0.25).add('a', -0.5).toString() + * var c = $.color.extract($("#mydiv"), 'background-color'); + * console.log(c.r, c.g, c.b, c.a); + * $.color.make(100, 50, 25, 0.4).toString() // returns "rgba(100,50,25,0.4)" + * + * Note that .scale() and .add() return the same modified object + * instead of making a new one. + * + * V. 1.1: Fix error handling so e.g. parsing an empty string does + * produce a color rather than just crashing. + */ +(function($){$.color={};$.color.make=function(r,g,b,a){var o={};o.r=r||0;o.g=g||0;o.b=b||0;o.a=a!=null?a:1;o.add=function(c,d){for(var i=0;i=1){return"rgb("+[o.r,o.g,o.b].join(",")+")"}else{return"rgba("+[o.r,o.g,o.b,o.a].join(",")+")"}};o.normalize=function(){function clamp(min,value,max){return valuemax?max:value}o.r=clamp(0,parseInt(o.r),255);o.g=clamp(0,parseInt(o.g),255);o.b=clamp(0,parseInt(o.b),255);o.a=clamp(0,o.a,1);return o};o.clone=function(){return $.color.make(o.r,o.b,o.g,o.a)};return o.normalize()};$.color.extract=function(elem,css){var c;do{c=elem.css(css).toLowerCase();if(c!=""&&c!="transparent")break;elem=elem.parent()}while(elem.length&&!$.nodeName(elem.get(0),"body"));if(c=="rgba(0, 0, 0, 0)")c="transparent";return $.color.parse(c)};$.color.parse=function(str){var res,m=$.color.make;if(res=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10));if(res=/rgba\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseInt(res[1],10),parseInt(res[2],10),parseInt(res[3],10),parseFloat(res[4]));if(res=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55);if(res=/rgba\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\s*\)/.exec(str))return m(parseFloat(res[1])*2.55,parseFloat(res[2])*2.55,parseFloat(res[3])*2.55,parseFloat(res[4]));if(res=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(str))return m(parseInt(res[1],16),parseInt(res[2],16),parseInt(res[3],16));if(res=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(str))return m(parseInt(res[1]+res[1],16),parseInt(res[2]+res[2],16),parseInt(res[3]+res[3],16));var name=$.trim(str).toLowerCase();if(name=="transparent")return m(255,255,255,0);else{res=lookupColors[name]||[0,0,0];return m(res[0],res[1],res[2])}};var lookupColors={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0]}})(jQuery); + +// the actual Flot code +(function($) { + + // Cache the prototype hasOwnProperty for faster access + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + // A shim to provide 'detach' to jQuery versions prior to 1.4. Using a DOM + // operation produces the same effect as detach, i.e. removing the element + // without touching its jQuery data. + + // Do not merge this into Flot 0.9, since it requires jQuery 1.4.4+. + + if (!$.fn.detach) { + $.fn.detach = function() { + return this.each(function() { + if (this.parentNode) { + this.parentNode.removeChild( this ); + } + }); + }; + } + + /////////////////////////////////////////////////////////////////////////// + // The Canvas object is a wrapper around an HTML5 tag. + // + // @constructor + // @param {string} cls List of classes to apply to the canvas. + // @param {element} container Element onto which to append the canvas. + // + // Requiring a container is a little iffy, but unfortunately canvas + // operations don't work unless the canvas is attached to the DOM. + + function Canvas(cls, container) { + + var element = container.children("." + cls)[0]; + + if (element == null) { + + element = document.createElement("canvas"); + element.className = cls; + + $(element).css({ direction: "ltr", position: "absolute", left: 0, top: 0 }) + .appendTo(container); + + // If HTML5 Canvas isn't available, fall back to [Ex|Flash]canvas + + if (!element.getContext) { + if (window.G_vmlCanvasManager) { + element = window.G_vmlCanvasManager.initElement(element); + } else { + throw new Error("Canvas is not available. If you're using IE with a fall-back such as Excanvas, then there's either a mistake in your conditional include, or the page has no DOCTYPE and is rendering in Quirks Mode."); + } + } + } + + this.element = element; + + var context = this.context = element.getContext("2d"); + + // Determine the screen's ratio of physical to device-independent + // pixels. This is the ratio between the canvas width that the browser + // advertises and the number of pixels actually present in that space. + + // The iPhone 4, for example, has a device-independent width of 320px, + // but its screen is actually 640px wide. It therefore has a pixel + // ratio of 2, while most normal devices have a ratio of 1. + + var devicePixelRatio = window.devicePixelRatio || 1, + backingStoreRatio = + context.webkitBackingStorePixelRatio || + context.mozBackingStorePixelRatio || + context.msBackingStorePixelRatio || + context.oBackingStorePixelRatio || + context.backingStorePixelRatio || 1; + + this.pixelRatio = devicePixelRatio / backingStoreRatio; + + // Size the canvas to match the internal dimensions of its container + + this.resize(container.width(), container.height()); + + // Collection of HTML div layers for text overlaid onto the canvas + + this.textContainer = null; + this.text = {}; + + // Cache of text fragments and metrics, so we can avoid expensively + // re-calculating them when the plot is re-rendered in a loop. + + this._textCache = {}; + } + + // Resizes the canvas to the given dimensions. + // + // @param {number} width New width of the canvas, in pixels. + // @param {number} width New height of the canvas, in pixels. + + Canvas.prototype.resize = function(width, height) { + + if (width <= 0 || height <= 0) { + throw new Error("Invalid dimensions for plot, width = " + width + ", height = " + height); + } + + var element = this.element, + context = this.context, + pixelRatio = this.pixelRatio; + + // Resize the canvas, increasing its density based on the display's + // pixel ratio; basically giving it more pixels without increasing the + // size of its element, to take advantage of the fact that retina + // displays have that many more pixels in the same advertised space. + + // Resizing should reset the state (excanvas seems to be buggy though) + + if (this.width != width) { + element.width = width * pixelRatio; + element.style.width = width + "px"; + this.width = width; + } + + if (this.height != height) { + element.height = height * pixelRatio; + element.style.height = height + "px"; + this.height = height; + } + + // Save the context, so we can reset in case we get replotted. The + // restore ensure that we're really back at the initial state, and + // should be safe even if we haven't saved the initial state yet. + + context.restore(); + context.save(); + + // Scale the coordinate space to match the display density; so even though we + // may have twice as many pixels, we still want lines and other drawing to + // appear at the same size; the extra pixels will just make them crisper. + + context.scale(pixelRatio, pixelRatio); + }; + + // Clears the entire canvas area, not including any overlaid HTML text + + Canvas.prototype.clear = function() { + this.context.clearRect(0, 0, this.width, this.height); + }; + + // Finishes rendering the canvas, including managing the text overlay. + + Canvas.prototype.render = function() { + + var cache = this._textCache; + + // For each text layer, add elements marked as active that haven't + // already been rendered, and remove those that are no longer active. + + for (var layerKey in cache) { + if (hasOwnProperty.call(cache, layerKey)) { + + var layer = this.getTextLayer(layerKey), + layerCache = cache[layerKey]; + + layer.hide(); + + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + + var positions = styleCache[key].positions; + + for (var i = 0, position; position = positions[i]; i++) { + if (position.active) { + if (!position.rendered) { + layer.append(position.element); + position.rendered = true; + } + } else { + positions.splice(i--, 1); + if (position.rendered) { + position.element.detach(); + } + } + } + + if (positions.length == 0) { + delete styleCache[key]; + } + } + } + } + } + + layer.show(); + } + } + }; + + // Creates (if necessary) and returns the text overlay container. + // + // @param {string} classes String of space-separated CSS classes used to + // uniquely identify the text layer. + // @return {object} The jQuery-wrapped text-layer div. + + Canvas.prototype.getTextLayer = function(classes) { + + var layer = this.text[classes]; + + // Create the text layer if it doesn't exist + + if (layer == null) { + + // Create the text layer container, if it doesn't exist + + if (this.textContainer == null) { + this.textContainer = $("
") + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0, + 'font-size': "smaller", + color: "#545454" + }) + .insertAfter(this.element); + } + + layer = this.text[classes] = $("
") + .addClass(classes) + .css({ + position: "absolute", + top: 0, + left: 0, + bottom: 0, + right: 0 + }) + .appendTo(this.textContainer); + } + + return layer; + }; + + // Creates (if necessary) and returns a text info object. + // + // The object looks like this: + // + // { + // width: Width of the text's wrapper div. + // height: Height of the text's wrapper div. + // element: The jQuery-wrapped HTML div containing the text. + // positions: Array of positions at which this text is drawn. + // } + // + // The positions array contains objects that look like this: + // + // { + // active: Flag indicating whether the text should be visible. + // rendered: Flag indicating whether the text is currently visible. + // element: The jQuery-wrapped HTML div containing the text. + // x: X coordinate at which to draw the text. + // y: Y coordinate at which to draw the text. + // } + // + // Each position after the first receives a clone of the original element. + // + // The idea is that that the width, height, and general 'identity' of the + // text is constant no matter where it is placed; the placements are a + // secondary property. + // + // Canvas maintains a cache of recently-used text info objects; getTextInfo + // either returns the cached element or creates a new entry. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {string} text Text string to retrieve info for. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @return {object} a text info object. + + Canvas.prototype.getTextInfo = function(layer, text, font, angle, width) { + + var textStyle, layerCache, styleCache, info; + + // Cast the value to a string, in case we were given a number or such + + text = "" + text; + + // If the font is a font-spec object, generate a CSS font definition + + if (typeof font === "object") { + textStyle = font.style + " " + font.variant + " " + font.weight + " " + font.size + "px/" + font.lineHeight + "px " + font.family; + } else { + textStyle = font; + } + + // Retrieve (or create) the cache for the text's layer and styles + + layerCache = this._textCache[layer]; + + if (layerCache == null) { + layerCache = this._textCache[layer] = {}; + } + + styleCache = layerCache[textStyle]; + + if (styleCache == null) { + styleCache = layerCache[textStyle] = {}; + } + + info = styleCache[text]; + + // If we can't find a matching element in our cache, create a new one + + if (info == null) { + + var element = $("
").html(text) + .css({ + position: "absolute", + 'max-width': width, + top: -9999 + }) + .appendTo(this.getTextLayer(layer)); + + if (typeof font === "object") { + element.css({ + font: textStyle, + color: font.color + }); + } else if (typeof font === "string") { + element.addClass(font); + } + + info = styleCache[text] = { + width: element.outerWidth(true), + height: element.outerHeight(true), + element: element, + positions: [] + }; + + element.detach(); + } + + return info; + }; + + // Adds a text string to the canvas text overlay. + // + // The text isn't drawn immediately; it is marked as rendering, which will + // result in its addition to the canvas on the next render pass. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number} x X coordinate at which to draw the text. + // @param {number} y Y coordinate at which to draw the text. + // @param {string} text Text string to draw. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which to rotate the text, in degrees. + // Angle is currently unused, it will be implemented in the future. + // @param {number=} width Maximum width of the text before it wraps. + // @param {string=} halign Horizontal alignment of the text; either "left", + // "center" or "right". + // @param {string=} valign Vertical alignment of the text; either "top", + // "middle" or "bottom". + + Canvas.prototype.addText = function(layer, x, y, text, font, angle, width, halign, valign) { + + var info = this.getTextInfo(layer, text, font, angle, width), + positions = info.positions; + + // Tweak the div's position to match the text's alignment + + if (halign == "center") { + x -= info.width / 2; + } else if (halign == "right") { + x -= info.width; + } + + if (valign == "middle") { + y -= info.height / 2; + } else if (valign == "bottom") { + y -= info.height; + } + + // Determine whether this text already exists at this position. + // If so, mark it for inclusion in the next render pass. + + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = true; + return; + } + } + + // If the text doesn't exist at this position, create a new entry + + // For the very first position we'll re-use the original element, + // while for subsequent ones we'll clone it. + + position = { + active: true, + rendered: false, + element: positions.length ? info.element.clone() : info.element, + x: x, + y: y + }; + + positions.push(position); + + // Move the element to its final position within the container + + position.element.css({ + top: Math.round(y), + left: Math.round(x), + 'text-align': halign // In case the text wraps + }); + }; + + // Removes one or more text strings from the canvas text overlay. + // + // If no parameters are given, all text within the layer is removed. + // + // Note that the text is not immediately removed; it is simply marked as + // inactive, which will result in its removal on the next render pass. + // This avoids the performance penalty for 'clear and redraw' behavior, + // where we potentially get rid of all text on a layer, but will likely + // add back most or all of it later, as when redrawing axes, for example. + // + // @param {string} layer A string of space-separated CSS classes uniquely + // identifying the layer containing this text. + // @param {number=} x X coordinate of the text. + // @param {number=} y Y coordinate of the text. + // @param {string=} text Text string to remove. + // @param {(string|object)=} font Either a string of space-separated CSS + // classes or a font-spec object, defining the text's font and style. + // @param {number=} angle Angle at which the text is rotated, in degrees. + // Angle is currently unused, it will be implemented in the future. + + Canvas.prototype.removeText = function(layer, x, y, text, font, angle) { + if (text == null) { + var layerCache = this._textCache[layer]; + if (layerCache != null) { + for (var styleKey in layerCache) { + if (hasOwnProperty.call(layerCache, styleKey)) { + var styleCache = layerCache[styleKey]; + for (var key in styleCache) { + if (hasOwnProperty.call(styleCache, key)) { + var positions = styleCache[key].positions; + for (var i = 0, position; position = positions[i]; i++) { + position.active = false; + } + } + } + } + } + } + } else { + var positions = this.getTextInfo(layer, text, font, angle).positions; + for (var i = 0, position; position = positions[i]; i++) { + if (position.x == x && position.y == y) { + position.active = false; + } + } + } + }; + + /////////////////////////////////////////////////////////////////////////// + // The top-level container for the entire plot. + + function Plot(placeholder, data_, options_, plugins) { + // data is on the form: + // [ series1, series2 ... ] + // where series is either just the data as [ [x1, y1], [x2, y2], ... ] + // or { data: [ [x1, y1], [x2, y2], ... ], label: "some label", ... } + + var series = [], + options = { + // the color theme used for graphs + colors: ["#edc240", "#afd8f8", "#cb4b4b", "#4da74d", "#9440ed"], + legend: { + show: true, + noColumns: 1, // number of columns in legend table + labelFormatter: null, // fn: string -> string + labelBoxBorderColor: "#ccc", // border color for the little label boxes + container: null, // container (as jQuery object) to put legend in, null means default on top of graph + position: "ne", // position of default legend container within plot + margin: 5, // distance from grid edge to default legend container within plot + backgroundColor: null, // null means auto-detect + backgroundOpacity: 0.85, // set to 0 to avoid background + sorted: null // default to no legend sorting + }, + xaxis: { + show: null, // null = auto-detect, true = always, false = never + position: "bottom", // or "top" + mode: null, // null or "time" + font: null, // null (derived from CSS in placeholder) or object like { size: 11, lineHeight: 13, style: "italic", weight: "bold", family: "sans-serif", variant: "small-caps" } + color: null, // base color, labels, ticks + tickColor: null, // possibly different color of ticks, e.g. "rgba(0,0,0,0.15)" + transform: null, // null or f: number -> number to transform axis + inverseTransform: null, // if transform is set, this should be the inverse function + min: null, // min. value to show, null means set automatically + max: null, // max. value to show, null means set automatically + autoscaleMargin: null, // margin in % to add if auto-setting min/max + ticks: null, // either [1, 3] or [[1, "a"], 3] or (fn: axis info -> ticks) or app. number of ticks for auto-ticks + tickFormatter: null, // fn: number -> string + labelWidth: null, // size of tick labels in pixels + labelHeight: null, + reserveSpace: null, // whether to reserve space even if axis isn't shown + tickLength: null, // size in pixels of ticks, or "full" for whole line + alignTicksWithAxis: null, // axis number or null for no sync + tickDecimals: null, // no. of decimals, null means auto + tickSize: null, // number or [number, "unit"] + minTickSize: null // number or [number, "unit"] + }, + yaxis: { + autoscaleMargin: 0.02, + position: "left" // or "right" + }, + xaxes: [], + yaxes: [], + series: { + points: { + show: false, + radius: 3, + lineWidth: 2, // in pixels + fill: true, + fillColor: "#ffffff", + symbol: "circle" // or callback + }, + lines: { + // we don't put in show: false so we can see + // whether lines were actively disabled + lineWidth: 2, // in pixels + fill: false, + fillColor: null, + steps: false + // Omit 'zero', so we can later default its value to + // match that of the 'fill' option. + }, + bars: { + show: false, + lineWidth: 2, // in pixels + barWidth: 1, // in units of the x axis + fill: true, + fillColor: null, + align: "left", // "left", "right", or "center" + horizontal: false, + zero: true + }, + shadowSize: 3, + highlightColor: null + }, + grid: { + show: true, + aboveData: false, + color: "#545454", // primary color used for outline and labels + backgroundColor: null, // null for transparent, else color + borderColor: null, // set if different from the grid color + tickColor: null, // color for the ticks, e.g. "rgba(0,0,0,0.15)" + margin: 0, // distance from the canvas edge to the grid + labelMargin: 5, // in pixels + axisMargin: 8, // in pixels + borderWidth: 2, // in pixels + minBorderMargin: null, // in pixels, null means taken from points radius + markings: null, // array of ranges or fn: axes -> array of ranges + markingsColor: "#f4f4f4", + markingsLineWidth: 2, + // interactive stuff + clickable: false, + hoverable: false, + autoHighlight: true, // highlight in case mouse is near + mouseActiveRadius: 10 // how far the mouse can be away to activate an item + }, + interaction: { + redrawOverlayInterval: 1000/60 // time between updates, -1 means in same flow + }, + hooks: {} + }, + surface = null, // the canvas for the plot itself + overlay = null, // canvas for interactive stuff on top of plot + eventHolder = null, // jQuery object that events should be bound to + ctx = null, octx = null, + xaxes = [], yaxes = [], + plotOffset = { left: 0, right: 0, top: 0, bottom: 0}, + plotWidth = 0, plotHeight = 0, + hooks = { + processOptions: [], + processRawData: [], + processDatapoints: [], + processOffset: [], + drawBackground: [], + drawSeries: [], + draw: [], + bindEvents: [], + drawOverlay: [], + shutdown: [] + }, + plot = this; + + // public functions + plot.setData = setData; + plot.setupGrid = setupGrid; + plot.draw = draw; + plot.getPlaceholder = function() { return placeholder; }; + plot.getCanvas = function() { return surface.element; }; + plot.getPlotOffset = function() { return plotOffset; }; + plot.width = function () { return plotWidth; }; + plot.height = function () { return plotHeight; }; + plot.offset = function () { + var o = eventHolder.offset(); + o.left += plotOffset.left; + o.top += plotOffset.top; + return o; + }; + plot.getData = function () { return series; }; + plot.getAxes = function () { + var res = {}, i; + $.each(xaxes.concat(yaxes), function (_, axis) { + if (axis) + res[axis.direction + (axis.n != 1 ? axis.n : "") + "axis"] = axis; + }); + return res; + }; + plot.getXAxes = function () { return xaxes; }; + plot.getYAxes = function () { return yaxes; }; + plot.c2p = canvasToAxisCoords; + plot.p2c = axisToCanvasCoords; + plot.getOptions = function () { return options; }; + plot.highlight = highlight; + plot.unhighlight = unhighlight; + plot.triggerRedrawOverlay = triggerRedrawOverlay; + plot.pointOffset = function(point) { + return { + left: parseInt(xaxes[axisNumber(point, "x") - 1].p2c(+point.x) + plotOffset.left, 10), + top: parseInt(yaxes[axisNumber(point, "y") - 1].p2c(+point.y) + plotOffset.top, 10) + }; + }; + plot.shutdown = shutdown; + plot.destroy = function () { + shutdown(); + placeholder.removeData("plot").empty(); + + series = []; + options = null; + surface = null; + overlay = null; + eventHolder = null; + ctx = null; + octx = null; + xaxes = []; + yaxes = []; + hooks = null; + highlights = []; + plot = null; + }; + plot.resize = function () { + var width = placeholder.width(), + height = placeholder.height(); + surface.resize(width, height); + overlay.resize(width, height); + }; + + // public attributes + plot.hooks = hooks; + + // initialize + initPlugins(plot); + parseOptions(options_); + setupCanvases(); + setData(data_); + setupGrid(); + draw(); + bindEvents(); + + + function executeHooks(hook, args) { + args = [plot].concat(args); + for (var i = 0; i < hook.length; ++i) + hook[i].apply(this, args); + } + + function initPlugins() { + + // References to key classes, allowing plugins to modify them + + var classes = { + Canvas: Canvas + }; + + for (var i = 0; i < plugins.length; ++i) { + var p = plugins[i]; + p.init(plot, classes); + if (p.options) + $.extend(true, options, p.options); + } + } + + function parseOptions(opts) { + + $.extend(true, options, opts); + + // $.extend merges arrays, rather than replacing them. When less + // colors are provided than the size of the default palette, we + // end up with those colors plus the remaining defaults, which is + // not expected behavior; avoid it by replacing them here. + + if (opts && opts.colors) { + options.colors = opts.colors; + } + + if (options.xaxis.color == null) + options.xaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + if (options.yaxis.color == null) + options.yaxis.color = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + + if (options.xaxis.tickColor == null) // grid.tickColor for back-compatibility + options.xaxis.tickColor = options.grid.tickColor || options.xaxis.color; + if (options.yaxis.tickColor == null) // grid.tickColor for back-compatibility + options.yaxis.tickColor = options.grid.tickColor || options.yaxis.color; + + if (options.grid.borderColor == null) + options.grid.borderColor = options.grid.color; + if (options.grid.tickColor == null) + options.grid.tickColor = $.color.parse(options.grid.color).scale('a', 0.22).toString(); + + // Fill in defaults for axis options, including any unspecified + // font-spec fields, if a font-spec was provided. + + // If no x/y axis options were provided, create one of each anyway, + // since the rest of the code assumes that they exist. + + var i, axisOptions, axisCount, + fontSize = placeholder.css("font-size"), + fontSizeDefault = fontSize ? +fontSize.replace("px", "") : 13, + fontDefaults = { + style: placeholder.css("font-style"), + size: Math.round(0.8 * fontSizeDefault), + variant: placeholder.css("font-variant"), + weight: placeholder.css("font-weight"), + family: placeholder.css("font-family") + }; + + axisCount = options.xaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + + axisOptions = options.xaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.xaxis, axisOptions); + options.xaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + axisCount = options.yaxes.length || 1; + for (i = 0; i < axisCount; ++i) { + + axisOptions = options.yaxes[i]; + if (axisOptions && !axisOptions.tickColor) { + axisOptions.tickColor = axisOptions.color; + } + + axisOptions = $.extend(true, {}, options.yaxis, axisOptions); + options.yaxes[i] = axisOptions; + + if (axisOptions.font) { + axisOptions.font = $.extend({}, fontDefaults, axisOptions.font); + if (!axisOptions.font.color) { + axisOptions.font.color = axisOptions.color; + } + if (!axisOptions.font.lineHeight) { + axisOptions.font.lineHeight = Math.round(axisOptions.font.size * 1.15); + } + } + } + + // backwards compatibility, to be removed in future + if (options.xaxis.noTicks && options.xaxis.ticks == null) + options.xaxis.ticks = options.xaxis.noTicks; + if (options.yaxis.noTicks && options.yaxis.ticks == null) + options.yaxis.ticks = options.yaxis.noTicks; + if (options.x2axis) { + options.xaxes[1] = $.extend(true, {}, options.xaxis, options.x2axis); + options.xaxes[1].position = "top"; + // Override the inherit to allow the axis to auto-scale + if (options.x2axis.min == null) { + options.xaxes[1].min = null; + } + if (options.x2axis.max == null) { + options.xaxes[1].max = null; + } + } + if (options.y2axis) { + options.yaxes[1] = $.extend(true, {}, options.yaxis, options.y2axis); + options.yaxes[1].position = "right"; + // Override the inherit to allow the axis to auto-scale + if (options.y2axis.min == null) { + options.yaxes[1].min = null; + } + if (options.y2axis.max == null) { + options.yaxes[1].max = null; + } + } + if (options.grid.coloredAreas) + options.grid.markings = options.grid.coloredAreas; + if (options.grid.coloredAreasColor) + options.grid.markingsColor = options.grid.coloredAreasColor; + if (options.lines) + $.extend(true, options.series.lines, options.lines); + if (options.points) + $.extend(true, options.series.points, options.points); + if (options.bars) + $.extend(true, options.series.bars, options.bars); + if (options.shadowSize != null) + options.series.shadowSize = options.shadowSize; + if (options.highlightColor != null) + options.series.highlightColor = options.highlightColor; + + // save options on axes for future reference + for (i = 0; i < options.xaxes.length; ++i) + getOrCreateAxis(xaxes, i + 1).options = options.xaxes[i]; + for (i = 0; i < options.yaxes.length; ++i) + getOrCreateAxis(yaxes, i + 1).options = options.yaxes[i]; + + // add hooks from options + for (var n in hooks) + if (options.hooks[n] && options.hooks[n].length) + hooks[n] = hooks[n].concat(options.hooks[n]); + + executeHooks(hooks.processOptions, [options]); + } + + function setData(d) { + series = parseData(d); + fillInSeriesOptions(); + processData(); + } + + function parseData(d) { + var res = []; + for (var i = 0; i < d.length; ++i) { + var s = $.extend(true, {}, options.series); + + if (d[i].data != null) { + s.data = d[i].data; // move the data instead of deep-copy + delete d[i].data; + + $.extend(true, s, d[i]); + + d[i].data = s.data; + } + else + s.data = d[i]; + res.push(s); + } + + return res; + } + + function axisNumber(obj, coord) { + var a = obj[coord + "axis"]; + if (typeof a == "object") // if we got a real axis, extract number + a = a.n; + if (typeof a != "number") + a = 1; // default to first axis + return a; + } + + function allAxes() { + // return flat array without annoying null entries + return $.grep(xaxes.concat(yaxes), function (a) { return a; }); + } + + function canvasToAxisCoords(pos) { + // return an object with x/y corresponding to all used axes + var res = {}, i, axis; + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) + res["x" + axis.n] = axis.c2p(pos.left); + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) + res["y" + axis.n] = axis.c2p(pos.top); + } + + if (res.x1 !== undefined) + res.x = res.x1; + if (res.y1 !== undefined) + res.y = res.y1; + + return res; + } + + function axisToCanvasCoords(pos) { + // get canvas coords from the first pair of x/y found in pos + var res = {}, i, axis, key; + + for (i = 0; i < xaxes.length; ++i) { + axis = xaxes[i]; + if (axis && axis.used) { + key = "x" + axis.n; + if (pos[key] == null && axis.n == 1) + key = "x"; + + if (pos[key] != null) { + res.left = axis.p2c(pos[key]); + break; + } + } + } + + for (i = 0; i < yaxes.length; ++i) { + axis = yaxes[i]; + if (axis && axis.used) { + key = "y" + axis.n; + if (pos[key] == null && axis.n == 1) + key = "y"; + + if (pos[key] != null) { + res.top = axis.p2c(pos[key]); + break; + } + } + } + + return res; + } + + function getOrCreateAxis(axes, number) { + if (!axes[number - 1]) + axes[number - 1] = { + n: number, // save the number for future reference + direction: axes == xaxes ? "x" : "y", + options: $.extend(true, {}, axes == xaxes ? options.xaxis : options.yaxis) + }; + + return axes[number - 1]; + } + + function fillInSeriesOptions() { + + var neededColors = series.length, maxIndex = -1, i; + + // Subtract the number of series that already have fixed colors or + // color indexes from the number that we still need to generate. + + for (i = 0; i < series.length; ++i) { + var sc = series[i].color; + if (sc != null) { + neededColors--; + if (typeof sc == "number" && sc > maxIndex) { + maxIndex = sc; + } + } + } + + // If any of the series have fixed color indexes, then we need to + // generate at least as many colors as the highest index. + + if (neededColors <= maxIndex) { + neededColors = maxIndex + 1; + } + + // Generate all the colors, using first the option colors and then + // variations on those colors once they're exhausted. + + var c, colors = [], colorPool = options.colors, + colorPoolSize = colorPool.length, variation = 0; + + for (i = 0; i < neededColors; i++) { + + c = $.color.parse(colorPool[i % colorPoolSize] || "#666"); + + // Each time we exhaust the colors in the pool we adjust + // a scaling factor used to produce more variations on + // those colors. The factor alternates negative/positive + // to produce lighter/darker colors. + + // Reset the variation after every few cycles, or else + // it will end up producing only white or black colors. + + if (i % colorPoolSize == 0 && i) { + if (variation >= 0) { + if (variation < 0.5) { + variation = -variation - 0.2; + } else variation = 0; + } else variation = -variation; + } + + colors[i] = c.scale('rgb', 1 + variation); + } + + // Finalize the series options, filling in their colors + + var colori = 0, s; + for (i = 0; i < series.length; ++i) { + s = series[i]; + + // assign colors + if (s.color == null) { + s.color = colors[colori].toString(); + ++colori; + } + else if (typeof s.color == "number") + s.color = colors[s.color].toString(); + + // turn on lines automatically in case nothing is set + if (s.lines.show == null) { + var v, show = true; + for (v in s) + if (s[v] && s[v].show) { + show = false; + break; + } + if (show) + s.lines.show = true; + } + + // If nothing was provided for lines.zero, default it to match + // lines.fill, since areas by default should extend to zero. + + if (s.lines.zero == null) { + s.lines.zero = !!s.lines.fill; + } + + // setup axes + s.xaxis = getOrCreateAxis(xaxes, axisNumber(s, "x")); + s.yaxis = getOrCreateAxis(yaxes, axisNumber(s, "y")); + } + } + + function processData() { + var topSentry = Number.POSITIVE_INFINITY, + bottomSentry = Number.NEGATIVE_INFINITY, + fakeInfinity = Number.MAX_VALUE, + i, j, k, m, length, + s, points, ps, x, y, axis, val, f, p, + data, format; + + function updateAxis(axis, min, max) { + if (min < axis.datamin && min != -fakeInfinity) + axis.datamin = min; + if (max > axis.datamax && max != fakeInfinity) + axis.datamax = max; + } + + $.each(allAxes(), function (_, axis) { + // init axis + axis.datamin = topSentry; + axis.datamax = bottomSentry; + axis.used = false; + }); + + for (i = 0; i < series.length; ++i) { + s = series[i]; + s.datapoints = { points: [] }; + + executeHooks(hooks.processRawData, [ s, s.data, s.datapoints ]); + } + + // first pass: clean and copy data + for (i = 0; i < series.length; ++i) { + s = series[i]; + + data = s.data; + format = s.datapoints.format; + + if (!format) { + format = []; + // find out how to copy + format.push({ x: true, number: true, required: true }); + format.push({ y: true, number: true, required: true }); + + if (s.bars.show || (s.lines.show && s.lines.fill)) { + var autoscale = !!((s.bars.show && s.bars.zero) || (s.lines.show && s.lines.zero)); + format.push({ y: true, number: true, required: false, defaultValue: 0, autoscale: autoscale }); + if (s.bars.horizontal) { + delete format[format.length - 1].y; + format[format.length - 1].x = true; + } + } + + s.datapoints.format = format; + } + + if (s.datapoints.pointsize != null) + continue; // already filled in + + s.datapoints.pointsize = format.length; + + ps = s.datapoints.pointsize; + points = s.datapoints.points; + + var insertSteps = s.lines.show && s.lines.steps; + s.xaxis.used = s.yaxis.used = true; + + for (j = k = 0; j < data.length; ++j, k += ps) { + p = data[j]; + + var nullify = p == null; + if (!nullify) { + for (m = 0; m < ps; ++m) { + val = p[m]; + f = format[m]; + + if (f) { + if (f.number && val != null) { + val = +val; // convert to number + if (isNaN(val)) + val = null; + else if (val == Infinity) + val = fakeInfinity; + else if (val == -Infinity) + val = -fakeInfinity; + } + + if (val == null) { + if (f.required) + nullify = true; + + if (f.defaultValue != null) + val = f.defaultValue; + } + } + + points[k + m] = val; + } + } + + if (nullify) { + for (m = 0; m < ps; ++m) { + val = points[k + m]; + if (val != null) { + f = format[m]; + // extract min/max info + if (f.autoscale !== false) { + if (f.x) { + updateAxis(s.xaxis, val, val); + } + if (f.y) { + updateAxis(s.yaxis, val, val); + } + } + } + points[k + m] = null; + } + } + else { + // a little bit of line specific stuff that + // perhaps shouldn't be here, but lacking + // better means... + if (insertSteps && k > 0 + && points[k - ps] != null + && points[k - ps] != points[k] + && points[k - ps + 1] != points[k + 1]) { + // copy the point to make room for a middle point + for (m = 0; m < ps; ++m) + points[k + ps + m] = points[k + m]; + + // middle point has same y + points[k + 1] = points[k - ps + 1]; + + // we've added a point, better reflect that + k += ps; + } + } + } + } + + // give the hooks a chance to run + for (i = 0; i < series.length; ++i) { + s = series[i]; + + executeHooks(hooks.processDatapoints, [ s, s.datapoints]); + } + + // second pass: find datamax/datamin for auto-scaling + for (i = 0; i < series.length; ++i) { + s = series[i]; + points = s.datapoints.points; + ps = s.datapoints.pointsize; + format = s.datapoints.format; + + var xmin = topSentry, ymin = topSentry, + xmax = bottomSentry, ymax = bottomSentry; + + for (j = 0; j < points.length; j += ps) { + if (points[j] == null) + continue; + + for (m = 0; m < ps; ++m) { + val = points[j + m]; + f = format[m]; + if (!f || f.autoscale === false || val == fakeInfinity || val == -fakeInfinity) + continue; + + if (f.x) { + if (val < xmin) + xmin = val; + if (val > xmax) + xmax = val; + } + if (f.y) { + if (val < ymin) + ymin = val; + if (val > ymax) + ymax = val; + } + } + } + + if (s.bars.show) { + // make sure we got room for the bar on the dancing floor + var delta; + + switch (s.bars.align) { + case "left": + delta = 0; + break; + case "right": + delta = -s.bars.barWidth; + break; + default: + delta = -s.bars.barWidth / 2; + } + + if (s.bars.horizontal) { + ymin += delta; + ymax += delta + s.bars.barWidth; + } + else { + xmin += delta; + xmax += delta + s.bars.barWidth; + } + } + + updateAxis(s.xaxis, xmin, xmax); + updateAxis(s.yaxis, ymin, ymax); + } + + $.each(allAxes(), function (_, axis) { + if (axis.datamin == topSentry) + axis.datamin = null; + if (axis.datamax == bottomSentry) + axis.datamax = null; + }); + } + + function setupCanvases() { + + // Make sure the placeholder is clear of everything except canvases + // from a previous plot in this container that we'll try to re-use. + + placeholder.css("padding", 0) // padding messes up the positioning + .children().filter(function(){ + return !$(this).hasClass("flot-overlay") && !$(this).hasClass('flot-base'); + }).remove(); + + if (placeholder.css("position") == 'static') + placeholder.css("position", "relative"); // for positioning labels and overlay + + surface = new Canvas("flot-base", placeholder); + overlay = new Canvas("flot-overlay", placeholder); // overlay canvas for interactive features + + ctx = surface.context; + octx = overlay.context; + + // define which element we're listening for events on + eventHolder = $(overlay.element).unbind(); + + // If we're re-using a plot object, shut down the old one + + var existing = placeholder.data("plot"); + + if (existing) { + existing.shutdown(); + overlay.clear(); + } + + // save in case we get replotted + placeholder.data("plot", plot); + } + + function bindEvents() { + // bind events + if (options.grid.hoverable) { + eventHolder.mousemove(onMouseMove); + + // Use bind, rather than .mouseleave, because we officially + // still support jQuery 1.2.6, which doesn't define a shortcut + // for mouseenter or mouseleave. This was a bug/oversight that + // was fixed somewhere around 1.3.x. We can return to using + // .mouseleave when we drop support for 1.2.6. + + eventHolder.bind("mouseleave", onMouseLeave); + } + + if (options.grid.clickable) + eventHolder.click(onClick); + + executeHooks(hooks.bindEvents, [eventHolder]); + } + + function shutdown() { + if (redrawTimeout) + clearTimeout(redrawTimeout); + + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mouseleave", onMouseLeave); + eventHolder.unbind("click", onClick); + + executeHooks(hooks.shutdown, [eventHolder]); + } + + function setTransformationHelpers(axis) { + // set helper functions on the axis, assumes plot area + // has been computed already + + function identity(x) { return x; } + + var s, m, t = axis.options.transform || identity, + it = axis.options.inverseTransform; + + // precompute how much the axis is scaling a point + // in canvas space + if (axis.direction == "x") { + s = axis.scale = plotWidth / Math.abs(t(axis.max) - t(axis.min)); + m = Math.min(t(axis.max), t(axis.min)); + } + else { + s = axis.scale = plotHeight / Math.abs(t(axis.max) - t(axis.min)); + s = -s; + m = Math.max(t(axis.max), t(axis.min)); + } + + // data point to canvas coordinate + if (t == identity) // slight optimization + axis.p2c = function (p) { return (p - m) * s; }; + else + axis.p2c = function (p) { return (t(p) - m) * s; }; + // canvas coordinate to data point + if (!it) + axis.c2p = function (c) { return m + c / s; }; + else + axis.c2p = function (c) { return it(m + c / s); }; + } + + function measureTickLabels(axis) { + + var opts = axis.options, + ticks = axis.ticks || [], + labelWidth = opts.labelWidth || 0, + labelHeight = opts.labelHeight || 0, + maxWidth = labelWidth || (axis.direction == "x" ? Math.floor(surface.width / (ticks.length || 1)) : null), + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = opts.font || "flot-tick-label tickLabel"; + + for (var i = 0; i < ticks.length; ++i) { + + var t = ticks[i]; + + if (!t.label) + continue; + + var info = surface.getTextInfo(layer, t.label, font, null, maxWidth); + + labelWidth = Math.max(labelWidth, info.width); + labelHeight = Math.max(labelHeight, info.height); + } + + axis.labelWidth = opts.labelWidth || labelWidth; + axis.labelHeight = opts.labelHeight || labelHeight; + } + + function allocateAxisBoxFirstPhase(axis) { + // find the bounding box of the axis by looking at label + // widths/heights and ticks, make room by diminishing the + // plotOffset; this first phase only looks at one + // dimension per axis, the other dimension depends on the + // other axes so will have to wait + + var lw = axis.labelWidth, + lh = axis.labelHeight, + pos = axis.options.position, + isXAxis = axis.direction === "x", + tickLength = axis.options.tickLength, + axisMargin = options.grid.axisMargin, + padding = options.grid.labelMargin, + innermost = true, + outermost = true, + first = true, + found = false; + + // Determine the axis's position in its direction and on its side + + $.each(isXAxis ? xaxes : yaxes, function(i, a) { + if (a && (a.show || a.reserveSpace)) { + if (a === axis) { + found = true; + } else if (a.options.position === pos) { + if (found) { + outermost = false; + } else { + innermost = false; + } + } + if (!found) { + first = false; + } + } + }); + + // The outermost axis on each side has no margin + + if (outermost) { + axisMargin = 0; + } + + // The ticks for the first axis in each direction stretch across + + if (tickLength == null) { + tickLength = first ? "full" : 5; + } + + if (!isNaN(+tickLength)) + padding += +tickLength; + + if (isXAxis) { + lh += padding; + + if (pos == "bottom") { + plotOffset.bottom += lh + axisMargin; + axis.box = { top: surface.height - plotOffset.bottom, height: lh }; + } + else { + axis.box = { top: plotOffset.top + axisMargin, height: lh }; + plotOffset.top += lh + axisMargin; + } + } + else { + lw += padding; + + if (pos == "left") { + axis.box = { left: plotOffset.left + axisMargin, width: lw }; + plotOffset.left += lw + axisMargin; + } + else { + plotOffset.right += lw + axisMargin; + axis.box = { left: surface.width - plotOffset.right, width: lw }; + } + } + + // save for future reference + axis.position = pos; + axis.tickLength = tickLength; + axis.box.padding = padding; + axis.innermost = innermost; + } + + function allocateAxisBoxSecondPhase(axis) { + // now that all axis boxes have been placed in one + // dimension, we can set the remaining dimension coordinates + if (axis.direction == "x") { + axis.box.left = plotOffset.left - axis.labelWidth / 2; + axis.box.width = surface.width - plotOffset.left - plotOffset.right + axis.labelWidth; + } + else { + axis.box.top = plotOffset.top - axis.labelHeight / 2; + axis.box.height = surface.height - plotOffset.bottom - plotOffset.top + axis.labelHeight; + } + } + + function adjustLayoutForThingsStickingOut() { + // possibly adjust plot offset to ensure everything stays + // inside the canvas and isn't clipped off + + var minMargin = options.grid.minBorderMargin, + axis, i; + + // check stuff from the plot (FIXME: this should just read + // a value from the series, otherwise it's impossible to + // customize) + if (minMargin == null) { + minMargin = 0; + for (i = 0; i < series.length; ++i) + minMargin = Math.max(minMargin, 2 * (series[i].points.radius + series[i].points.lineWidth/2)); + } + + var margins = { + left: minMargin, + right: minMargin, + top: minMargin, + bottom: minMargin + }; + + // check axis labels, note we don't check the actual + // labels but instead use the overall width/height to not + // jump as much around with replots + $.each(allAxes(), function (_, axis) { + if (axis.reserveSpace && axis.ticks && axis.ticks.length) { + if (axis.direction === "x") { + margins.left = Math.max(margins.left, axis.labelWidth / 2); + margins.right = Math.max(margins.right, axis.labelWidth / 2); + } else { + margins.bottom = Math.max(margins.bottom, axis.labelHeight / 2); + margins.top = Math.max(margins.top, axis.labelHeight / 2); + } + } + }); + + plotOffset.left = Math.ceil(Math.max(margins.left, plotOffset.left)); + plotOffset.right = Math.ceil(Math.max(margins.right, plotOffset.right)); + plotOffset.top = Math.ceil(Math.max(margins.top, plotOffset.top)); + plotOffset.bottom = Math.ceil(Math.max(margins.bottom, plotOffset.bottom)); + } + + function setupGrid() { + var i, axes = allAxes(), showGrid = options.grid.show; + + // Initialize the plot's offset from the edge of the canvas + + for (var a in plotOffset) { + var margin = options.grid.margin || 0; + plotOffset[a] = typeof margin == "number" ? margin : margin[a] || 0; + } + + executeHooks(hooks.processOffset, [plotOffset]); + + // If the grid is visible, add its border width to the offset + + for (var a in plotOffset) { + if(typeof(options.grid.borderWidth) == "object") { + plotOffset[a] += showGrid ? options.grid.borderWidth[a] : 0; + } + else { + plotOffset[a] += showGrid ? options.grid.borderWidth : 0; + } + } + + $.each(axes, function (_, axis) { + var axisOpts = axis.options; + axis.show = axisOpts.show == null ? axis.used : axisOpts.show; + axis.reserveSpace = axisOpts.reserveSpace == null ? axis.show : axisOpts.reserveSpace; + setRange(axis); + }); + + if (showGrid) { + + var allocatedAxes = $.grep(axes, function (axis) { + return axis.show || axis.reserveSpace; + }); + + $.each(allocatedAxes, function (_, axis) { + // make the ticks + setupTickGeneration(axis); + setTicks(axis); + snapRangeToTicks(axis, axis.ticks); + // find labelWidth/Height for axis + measureTickLabels(axis); + }); + + // with all dimensions calculated, we can compute the + // axis bounding boxes, start from the outside + // (reverse order) + for (i = allocatedAxes.length - 1; i >= 0; --i) + allocateAxisBoxFirstPhase(allocatedAxes[i]); + + // make sure we've got enough space for things that + // might stick out + adjustLayoutForThingsStickingOut(); + + $.each(allocatedAxes, function (_, axis) { + allocateAxisBoxSecondPhase(axis); + }); + } + + plotWidth = surface.width - plotOffset.left - plotOffset.right; + plotHeight = surface.height - plotOffset.bottom - plotOffset.top; + + // now we got the proper plot dimensions, we can compute the scaling + $.each(axes, function (_, axis) { + setTransformationHelpers(axis); + }); + + if (showGrid) { + drawAxisLabels(); + } + + insertLegend(); + } + + function setRange(axis) { + var opts = axis.options, + min = +(opts.min != null ? opts.min : axis.datamin), + max = +(opts.max != null ? opts.max : axis.datamax), + delta = max - min; + + if (delta == 0.0) { + // degenerate case + var widen = max == 0 ? 1 : 0.01; + + if (opts.min == null) + min -= widen; + // always widen max if we couldn't widen min to ensure we + // don't fall into min == max which doesn't work + if (opts.max == null || opts.min != null) + max += widen; + } + else { + // consider autoscaling + var margin = opts.autoscaleMargin; + if (margin != null) { + if (opts.min == null) { + min -= delta * margin; + // make sure we don't go below zero if all values + // are positive + if (min < 0 && axis.datamin != null && axis.datamin >= 0) + min = 0; + } + if (opts.max == null) { + max += delta * margin; + if (max > 0 && axis.datamax != null && axis.datamax <= 0) + max = 0; + } + } + } + axis.min = min; + axis.max = max; + } + + function setupTickGeneration(axis) { + var opts = axis.options; + + // estimate number of ticks + var noTicks; + if (typeof opts.ticks == "number" && opts.ticks > 0) + noTicks = opts.ticks; + else + // heuristic based on the model a*sqrt(x) fitted to + // some data points that seemed reasonable + noTicks = 0.3 * Math.sqrt(axis.direction == "x" ? surface.width : surface.height); + + var delta = (axis.max - axis.min) / noTicks, + dec = -Math.floor(Math.log(delta) / Math.LN10), + maxDec = opts.tickDecimals; + + if (maxDec != null && dec > maxDec) { + dec = maxDec; + } + + var magn = Math.pow(10, -dec), + norm = delta / magn, // norm is between 1.0 and 10.0 + size; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + // special case for 2.5, requires an extra decimal + if (norm > 2.25 && (maxDec == null || dec + 1 <= maxDec)) { + size = 2.5; + ++dec; + } + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + + if (opts.minTickSize != null && size < opts.minTickSize) { + size = opts.minTickSize; + } + + axis.delta = delta; + axis.tickDecimals = Math.max(0, maxDec != null ? maxDec : dec); + axis.tickSize = opts.tickSize || size; + + // Time mode was moved to a plug-in in 0.8, and since so many people use it + // we'll add an especially friendly reminder to make sure they included it. + + if (opts.mode == "time" && !axis.tickGenerator) { + throw new Error("Time mode requires the flot.time plugin."); + } + + // Flot supports base-10 axes; any other mode else is handled by a plug-in, + // like flot.time.js. + + if (!axis.tickGenerator) { + + axis.tickGenerator = function (axis) { + + var ticks = [], + start = floorInBase(axis.min, axis.tickSize), + i = 0, + v = Number.NaN, + prev; + + do { + prev = v; + v = start + i * axis.tickSize; + ticks.push(v); + ++i; + } while (v < axis.max && v != prev); + return ticks; + }; + + axis.tickFormatter = function (value, axis) { + + var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1; + var formatted = "" + Math.round(value * factor) / factor; + + // If tickDecimals was specified, ensure that we have exactly that + // much precision; otherwise default to the value's own precision. + + if (axis.tickDecimals != null) { + var decimal = formatted.indexOf("."); + var precision = decimal == -1 ? 0 : formatted.length - decimal - 1; + if (precision < axis.tickDecimals) { + return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision); + } + } + + return formatted; + }; + } + + if ($.isFunction(opts.tickFormatter)) + axis.tickFormatter = function (v, axis) { return "" + opts.tickFormatter(v, axis); }; + + if (opts.alignTicksWithAxis != null) { + var otherAxis = (axis.direction == "x" ? xaxes : yaxes)[opts.alignTicksWithAxis - 1]; + if (otherAxis && otherAxis.used && otherAxis != axis) { + // consider snapping min/max to outermost nice ticks + var niceTicks = axis.tickGenerator(axis); + if (niceTicks.length > 0) { + if (opts.min == null) + axis.min = Math.min(axis.min, niceTicks[0]); + if (opts.max == null && niceTicks.length > 1) + axis.max = Math.max(axis.max, niceTicks[niceTicks.length - 1]); + } + + axis.tickGenerator = function (axis) { + // copy ticks, scaled to this axis + var ticks = [], v, i; + for (i = 0; i < otherAxis.ticks.length; ++i) { + v = (otherAxis.ticks[i].v - otherAxis.min) / (otherAxis.max - otherAxis.min); + v = axis.min + v * (axis.max - axis.min); + ticks.push(v); + } + return ticks; + }; + + // we might need an extra decimal since forced + // ticks don't necessarily fit naturally + if (!axis.mode && opts.tickDecimals == null) { + var extraDec = Math.max(0, -Math.floor(Math.log(axis.delta) / Math.LN10) + 1), + ts = axis.tickGenerator(axis); + + // only proceed if the tick interval rounded + // with an extra decimal doesn't give us a + // zero at end + if (!(ts.length > 1 && /\..*0$/.test((ts[1] - ts[0]).toFixed(extraDec)))) + axis.tickDecimals = extraDec; + } + } + } + } + + function setTicks(axis) { + var oticks = axis.options.ticks, ticks = []; + if (oticks == null || (typeof oticks == "number" && oticks > 0)) + ticks = axis.tickGenerator(axis); + else if (oticks) { + if ($.isFunction(oticks)) + // generate the ticks + ticks = oticks(axis); + else + ticks = oticks; + } + + // clean up/labelify the supplied ticks, copy them over + var i, v; + axis.ticks = []; + for (i = 0; i < ticks.length; ++i) { + var label = null; + var t = ticks[i]; + if (typeof t == "object") { + v = +t[0]; + if (t.length > 1) + label = t[1]; + } + else + v = +t; + if (label == null) + label = axis.tickFormatter(v, axis); + if (!isNaN(v)) + axis.ticks.push({ v: v, label: label }); + } + } + + function snapRangeToTicks(axis, ticks) { + if (axis.options.autoscaleMargin && ticks.length > 0) { + // snap to ticks + if (axis.options.min == null) + axis.min = Math.min(axis.min, ticks[0].v); + if (axis.options.max == null && ticks.length > 1) + axis.max = Math.max(axis.max, ticks[ticks.length - 1].v); + } + } + + function draw() { + + surface.clear(); + + executeHooks(hooks.drawBackground, [ctx]); + + var grid = options.grid; + + // draw background, if any + if (grid.show && grid.backgroundColor) + drawBackground(); + + if (grid.show && !grid.aboveData) { + drawGrid(); + } + + for (var i = 0; i < series.length; ++i) { + executeHooks(hooks.drawSeries, [ctx, series[i]]); + drawSeries(series[i]); + } + + executeHooks(hooks.draw, [ctx]); + + if (grid.show && grid.aboveData) { + drawGrid(); + } + + surface.render(); + + // A draw implies that either the axes or data have changed, so we + // should probably update the overlay highlights as well. + + triggerRedrawOverlay(); + } + + function extractRange(ranges, coord) { + var axis, from, to, key, axes = allAxes(); + + for (var i = 0; i < axes.length; ++i) { + axis = axes[i]; + if (axis.direction == coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n == 1) + key = coord + "axis"; // support x1axis as xaxis + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord == "x" ? xaxes[0] : yaxes[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function drawBackground() { + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + ctx.fillStyle = getColorOrGradient(options.grid.backgroundColor, plotHeight, 0, "rgba(255, 255, 255, 0)"); + ctx.fillRect(0, 0, plotWidth, plotHeight); + ctx.restore(); + } + + function drawGrid() { + var i, axes, bw, bc; + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + // draw markings + var markings = options.grid.markings; + if (markings) { + if ($.isFunction(markings)) { + axes = plot.getAxes(); + // xmin etc. is backwards compatibility, to be + // removed in the future + axes.xmin = axes.xaxis.min; + axes.xmax = axes.xaxis.max; + axes.ymin = axes.yaxis.min; + axes.ymax = axes.yaxis.max; + + markings = markings(axes); + } + + for (i = 0; i < markings.length; ++i) { + var m = markings[i], + xrange = extractRange(m, "x"), + yrange = extractRange(m, "y"); + + // fill in missing + if (xrange.from == null) + xrange.from = xrange.axis.min; + if (xrange.to == null) + xrange.to = xrange.axis.max; + if (yrange.from == null) + yrange.from = yrange.axis.min; + if (yrange.to == null) + yrange.to = yrange.axis.max; + + // clip + if (xrange.to < xrange.axis.min || xrange.from > xrange.axis.max || + yrange.to < yrange.axis.min || yrange.from > yrange.axis.max) + continue; + + xrange.from = Math.max(xrange.from, xrange.axis.min); + xrange.to = Math.min(xrange.to, xrange.axis.max); + yrange.from = Math.max(yrange.from, yrange.axis.min); + yrange.to = Math.min(yrange.to, yrange.axis.max); + + var xequal = xrange.from === xrange.to, + yequal = yrange.from === yrange.to; + + if (xequal && yequal) { + continue; + } + + // then draw + xrange.from = Math.floor(xrange.axis.p2c(xrange.from)); + xrange.to = Math.floor(xrange.axis.p2c(xrange.to)); + yrange.from = Math.floor(yrange.axis.p2c(yrange.from)); + yrange.to = Math.floor(yrange.axis.p2c(yrange.to)); + + if (xequal || yequal) { + var lineWidth = m.lineWidth || options.grid.markingsLineWidth, + subPixel = lineWidth % 2 ? 0.5 : 0; + ctx.beginPath(); + ctx.strokeStyle = m.color || options.grid.markingsColor; + ctx.lineWidth = lineWidth; + if (xequal) { + ctx.moveTo(xrange.to + subPixel, yrange.from); + ctx.lineTo(xrange.to + subPixel, yrange.to); + } else { + ctx.moveTo(xrange.from, yrange.to + subPixel); + ctx.lineTo(xrange.to, yrange.to + subPixel); + } + ctx.stroke(); + } else { + ctx.fillStyle = m.color || options.grid.markingsColor; + ctx.fillRect(xrange.from, yrange.to, + xrange.to - xrange.from, + yrange.from - yrange.to); + } + } + } + + // draw the ticks + axes = allAxes(); + bw = options.grid.borderWidth; + + for (var j = 0; j < axes.length; ++j) { + var axis = axes[j], box = axis.box, + t = axis.tickLength, x, y, xoff, yoff; + if (!axis.show || axis.ticks.length == 0) + continue; + + ctx.lineWidth = 1; + + // find the edges + if (axis.direction == "x") { + x = 0; + if (t == "full") + y = (axis.position == "top" ? 0 : plotHeight); + else + y = box.top - plotOffset.top + (axis.position == "top" ? box.height : 0); + } + else { + y = 0; + if (t == "full") + x = (axis.position == "left" ? 0 : plotWidth); + else + x = box.left - plotOffset.left + (axis.position == "left" ? box.width : 0); + } + + // draw tick bar + if (!axis.innermost) { + ctx.strokeStyle = axis.options.color; + ctx.beginPath(); + xoff = yoff = 0; + if (axis.direction == "x") + xoff = plotWidth + 1; + else + yoff = plotHeight + 1; + + if (ctx.lineWidth == 1) { + if (axis.direction == "x") { + y = Math.floor(y) + 0.5; + } else { + x = Math.floor(x) + 0.5; + } + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + ctx.stroke(); + } + + // draw ticks + + ctx.strokeStyle = axis.options.tickColor; + + ctx.beginPath(); + for (i = 0; i < axis.ticks.length; ++i) { + var v = axis.ticks[i].v; + + xoff = yoff = 0; + + if (isNaN(v) || v < axis.min || v > axis.max + // skip those lying on the axes if we got a border + || (t == "full" + && ((typeof bw == "object" && bw[axis.position] > 0) || bw > 0) + && (v == axis.min || v == axis.max))) + continue; + + if (axis.direction == "x") { + x = axis.p2c(v); + yoff = t == "full" ? -plotHeight : t; + + if (axis.position == "top") + yoff = -yoff; + } + else { + y = axis.p2c(v); + xoff = t == "full" ? -plotWidth : t; + + if (axis.position == "left") + xoff = -xoff; + } + + if (ctx.lineWidth == 1) { + if (axis.direction == "x") + x = Math.floor(x) + 0.5; + else + y = Math.floor(y) + 0.5; + } + + ctx.moveTo(x, y); + ctx.lineTo(x + xoff, y + yoff); + } + + ctx.stroke(); + } + + + // draw border + if (bw) { + // If either borderWidth or borderColor is an object, then draw the border + // line by line instead of as one rectangle + bc = options.grid.borderColor; + if(typeof bw == "object" || typeof bc == "object") { + if (typeof bw !== "object") { + bw = {top: bw, right: bw, bottom: bw, left: bw}; + } + if (typeof bc !== "object") { + bc = {top: bc, right: bc, bottom: bc, left: bc}; + } + + if (bw.top > 0) { + ctx.strokeStyle = bc.top; + ctx.lineWidth = bw.top; + ctx.beginPath(); + ctx.moveTo(0 - bw.left, 0 - bw.top/2); + ctx.lineTo(plotWidth, 0 - bw.top/2); + ctx.stroke(); + } + + if (bw.right > 0) { + ctx.strokeStyle = bc.right; + ctx.lineWidth = bw.right; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right / 2, 0 - bw.top); + ctx.lineTo(plotWidth + bw.right / 2, plotHeight); + ctx.stroke(); + } + + if (bw.bottom > 0) { + ctx.strokeStyle = bc.bottom; + ctx.lineWidth = bw.bottom; + ctx.beginPath(); + ctx.moveTo(plotWidth + bw.right, plotHeight + bw.bottom / 2); + ctx.lineTo(0, plotHeight + bw.bottom / 2); + ctx.stroke(); + } + + if (bw.left > 0) { + ctx.strokeStyle = bc.left; + ctx.lineWidth = bw.left; + ctx.beginPath(); + ctx.moveTo(0 - bw.left/2, plotHeight + bw.bottom); + ctx.lineTo(0- bw.left/2, 0); + ctx.stroke(); + } + } + else { + ctx.lineWidth = bw; + ctx.strokeStyle = options.grid.borderColor; + ctx.strokeRect(-bw/2, -bw/2, plotWidth + bw, plotHeight + bw); + } + } + + ctx.restore(); + } + + function drawAxisLabels() { + + $.each(allAxes(), function (_, axis) { + var box = axis.box, + legacyStyles = axis.direction + "Axis " + axis.direction + axis.n + "Axis", + layer = "flot-" + axis.direction + "-axis flot-" + axis.direction + axis.n + "-axis " + legacyStyles, + font = axis.options.font || "flot-tick-label tickLabel", + tick, x, y, halign, valign; + + // Remove text before checking for axis.show and ticks.length; + // otherwise plugins, like flot-tickrotor, that draw their own + // tick labels will end up with both theirs and the defaults. + + surface.removeText(layer); + + if (!axis.show || axis.ticks.length == 0) + return; + + for (var i = 0; i < axis.ticks.length; ++i) { + + tick = axis.ticks[i]; + if (!tick.label || tick.v < axis.min || tick.v > axis.max) + continue; + + if (axis.direction == "x") { + halign = "center"; + x = plotOffset.left + axis.p2c(tick.v); + if (axis.position == "bottom") { + y = box.top + box.padding; + } else { + y = box.top + box.height - box.padding; + valign = "bottom"; + } + } else { + valign = "middle"; + y = plotOffset.top + axis.p2c(tick.v); + if (axis.position == "left") { + x = box.left + box.width - box.padding; + halign = "right"; + } else { + x = box.left + box.padding; + } + } + + surface.addText(layer, x, y, tick.label, font, null, null, halign, valign); + } + }); + } + + function drawSeries(series) { + if (series.lines.show) + drawSeriesLines(series); + if (series.bars.show) + drawSeriesBars(series); + if (series.points.show) + drawSeriesPoints(series); + } + + function drawSeriesLines(series) { + function plotLine(datapoints, xoffset, yoffset, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + prevx = null, prevy = null; + + ctx.beginPath(); + for (var i = ps; i < points.length; i += ps) { + var x1 = points[i - ps], y1 = points[i - ps + 1], + x2 = points[i], y2 = points[i + 1]; + + if (x1 == null || x2 == null) + continue; + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min) { + if (y2 < axisy.min) + continue; // line segment is outside + // compute new intersection point + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } + else if (y2 <= y1 && y2 < axisy.min) { + if (y1 < axisy.min) + continue; + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max) { + if (y2 > axisy.max) + continue; + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } + else if (y2 >= y1 && y2 > axisy.max) { + if (y1 > axisy.max) + continue; + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) + continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) + continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) + continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) + continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (x1 != prevx || y1 != prevy) + ctx.moveTo(axisx.p2c(x1) + xoffset, axisy.p2c(y1) + yoffset); + + prevx = x2; + prevy = y2; + ctx.lineTo(axisx.p2c(x2) + xoffset, axisy.p2c(y2) + yoffset); + } + ctx.stroke(); + } + + function plotLineArea(datapoints, axisx, axisy) { + var points = datapoints.points, + ps = datapoints.pointsize, + bottom = Math.min(Math.max(0, axisy.min), axisy.max), + i = 0, top, areaOpen = false, + ypos = 1, segmentStart = 0, segmentEnd = 0; + + // we process each segment in two turns, first forward + // direction to sketch out top, then once we hit the + // end we go backwards to sketch the bottom + while (true) { + if (ps > 0 && i > points.length + ps) + break; + + i += ps; // ps is negative if going backwards + + var x1 = points[i - ps], + y1 = points[i - ps + ypos], + x2 = points[i], y2 = points[i + ypos]; + + if (areaOpen) { + if (ps > 0 && x1 != null && x2 == null) { + // at turning point + segmentEnd = i; + ps = -ps; + ypos = 2; + continue; + } + + if (ps < 0 && i == segmentStart + ps) { + // done with the reverse sweep + ctx.fill(); + areaOpen = false; + ps = -ps; + ypos = 1; + i = segmentStart = segmentEnd + ps; + continue; + } + } + + if (x1 == null || x2 == null) + continue; + + // clip x values + + // clip with xmin + if (x1 <= x2 && x1 < axisx.min) { + if (x2 < axisx.min) + continue; + y1 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.min; + } + else if (x2 <= x1 && x2 < axisx.min) { + if (x1 < axisx.min) + continue; + y2 = (axisx.min - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.min; + } + + // clip with xmax + if (x1 >= x2 && x1 > axisx.max) { + if (x2 > axisx.max) + continue; + y1 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x1 = axisx.max; + } + else if (x2 >= x1 && x2 > axisx.max) { + if (x1 > axisx.max) + continue; + y2 = (axisx.max - x1) / (x2 - x1) * (y2 - y1) + y1; + x2 = axisx.max; + } + + if (!areaOpen) { + // open area + ctx.beginPath(); + ctx.moveTo(axisx.p2c(x1), axisy.p2c(bottom)); + areaOpen = true; + } + + // now first check the case where both is outside + if (y1 >= axisy.max && y2 >= axisy.max) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.max)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.max)); + continue; + } + else if (y1 <= axisy.min && y2 <= axisy.min) { + ctx.lineTo(axisx.p2c(x1), axisy.p2c(axisy.min)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(axisy.min)); + continue; + } + + // else it's a bit more complicated, there might + // be a flat maxed out rectangle first, then a + // triangular cutout or reverse; to find these + // keep track of the current x values + var x1old = x1, x2old = x2; + + // clip the y values, without shortcutting, we + // go through all cases in turn + + // clip with ymin + if (y1 <= y2 && y1 < axisy.min && y2 >= axisy.min) { + x1 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.min; + } + else if (y2 <= y1 && y2 < axisy.min && y1 >= axisy.min) { + x2 = (axisy.min - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.min; + } + + // clip with ymax + if (y1 >= y2 && y1 > axisy.max && y2 <= axisy.max) { + x1 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y1 = axisy.max; + } + else if (y2 >= y1 && y2 > axisy.max && y1 <= axisy.max) { + x2 = (axisy.max - y1) / (y2 - y1) * (x2 - x1) + x1; + y2 = axisy.max; + } + + // if the x value was changed we got a rectangle + // to fill + if (x1 != x1old) { + ctx.lineTo(axisx.p2c(x1old), axisy.p2c(y1)); + // it goes to (x1, y1), but we fill that below + } + + // fill triangular section, this sometimes result + // in redundant points if (x1, y1) hasn't changed + // from previous line to, but we just ignore that + ctx.lineTo(axisx.p2c(x1), axisy.p2c(y1)); + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + + // fill the other rectangle if it's there + if (x2 != x2old) { + ctx.lineTo(axisx.p2c(x2), axisy.p2c(y2)); + ctx.lineTo(axisx.p2c(x2old), axisy.p2c(y2)); + } + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + ctx.lineJoin = "round"; + + var lw = series.lines.lineWidth, + sw = series.shadowSize; + // FIXME: consider another form of shadow when filling is turned on + if (lw > 0 && sw > 0) { + // draw shadow as a thick and thin line with transparency + ctx.lineWidth = sw; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + // position shadow at angle from the mid of line + var angle = Math.PI/18; + plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/2), Math.cos(angle) * (lw/2 + sw/2), series.xaxis, series.yaxis); + ctx.lineWidth = sw/2; + plotLine(series.datapoints, Math.sin(angle) * (lw/2 + sw/4), Math.cos(angle) * (lw/2 + sw/4), series.xaxis, series.yaxis); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + var fillStyle = getFillStyle(series.lines, series.color, 0, plotHeight); + if (fillStyle) { + ctx.fillStyle = fillStyle; + plotLineArea(series.datapoints, series.xaxis, series.yaxis); + } + + if (lw > 0) + plotLine(series.datapoints, 0, 0, series.xaxis, series.yaxis); + ctx.restore(); + } + + function drawSeriesPoints(series) { + function plotPoints(datapoints, radius, fillStyle, offset, shadow, axisx, axisy, symbol) { + var points = datapoints.points, ps = datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + var x = points[i], y = points[i + 1]; + if (x == null || x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) + continue; + + ctx.beginPath(); + x = axisx.p2c(x); + y = axisy.p2c(y) + offset; + if (symbol == "circle") + ctx.arc(x, y, radius, 0, shadow ? Math.PI : Math.PI * 2, false); + else + symbol(ctx, x, y, radius, shadow); + ctx.closePath(); + + if (fillStyle) { + ctx.fillStyle = fillStyle; + ctx.fill(); + } + ctx.stroke(); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var lw = series.points.lineWidth, + sw = series.shadowSize, + radius = series.points.radius, + symbol = series.points.symbol; + + // If the user sets the line width to 0, we change it to a very + // small value. A line width of 0 seems to force the default of 1. + // Doing the conditional here allows the shadow setting to still be + // optional even with a lineWidth of 0. + + if( lw == 0 ) + lw = 0.0001; + + if (lw > 0 && sw > 0) { + // draw shadow in two steps + var w = sw / 2; + ctx.lineWidth = w; + ctx.strokeStyle = "rgba(0,0,0,0.1)"; + plotPoints(series.datapoints, radius, null, w + w/2, true, + series.xaxis, series.yaxis, symbol); + + ctx.strokeStyle = "rgba(0,0,0,0.2)"; + plotPoints(series.datapoints, radius, null, w/2, true, + series.xaxis, series.yaxis, symbol); + } + + ctx.lineWidth = lw; + ctx.strokeStyle = series.color; + plotPoints(series.datapoints, radius, + getFillStyle(series.points, series.color), 0, false, + series.xaxis, series.yaxis, symbol); + ctx.restore(); + } + + function drawBar(x, y, b, barLeft, barRight, fillStyleCallback, axisx, axisy, c, horizontal, lineWidth) { + var left, right, bottom, top, + drawLeft, drawRight, drawTop, drawBottom, + tmp; + + // in horizontal mode, we start the bar from the left + // instead of from the bottom so it appears to be + // horizontal rather than vertical + if (horizontal) { + drawBottom = drawRight = drawTop = true; + drawLeft = false; + left = b; + right = x; + top = y + barLeft; + bottom = y + barRight; + + // account for negative bars + if (right < left) { + tmp = right; + right = left; + left = tmp; + drawLeft = true; + drawRight = false; + } + } + else { + drawLeft = drawRight = drawTop = true; + drawBottom = false; + left = x + barLeft; + right = x + barRight; + bottom = b; + top = y; + + // account for negative bars + if (top < bottom) { + tmp = top; + top = bottom; + bottom = tmp; + drawBottom = true; + drawTop = false; + } + } + + // clip + if (right < axisx.min || left > axisx.max || + top < axisy.min || bottom > axisy.max) + return; + + if (left < axisx.min) { + left = axisx.min; + drawLeft = false; + } + + if (right > axisx.max) { + right = axisx.max; + drawRight = false; + } + + if (bottom < axisy.min) { + bottom = axisy.min; + drawBottom = false; + } + + if (top > axisy.max) { + top = axisy.max; + drawTop = false; + } + + left = axisx.p2c(left); + bottom = axisy.p2c(bottom); + right = axisx.p2c(right); + top = axisy.p2c(top); + + // fill the bar + if (fillStyleCallback) { + c.fillStyle = fillStyleCallback(bottom, top); + c.fillRect(left, top, right - left, bottom - top) + } + + // draw outline + if (lineWidth > 0 && (drawLeft || drawRight || drawTop || drawBottom)) { + c.beginPath(); + + // FIXME: inline moveTo is buggy with excanvas + c.moveTo(left, bottom); + if (drawLeft) + c.lineTo(left, top); + else + c.moveTo(left, top); + if (drawTop) + c.lineTo(right, top); + else + c.moveTo(right, top); + if (drawRight) + c.lineTo(right, bottom); + else + c.moveTo(right, bottom); + if (drawBottom) + c.lineTo(left, bottom); + else + c.moveTo(left, bottom); + c.stroke(); + } + } + + function drawSeriesBars(series) { + function plotBars(datapoints, barLeft, barRight, fillStyleCallback, axisx, axisy) { + var points = datapoints.points, ps = datapoints.pointsize; + + for (var i = 0; i < points.length; i += ps) { + if (points[i] == null) + continue; + drawBar(points[i], points[i + 1], points[i + 2], barLeft, barRight, fillStyleCallback, axisx, axisy, ctx, series.bars.horizontal, series.bars.lineWidth); + } + } + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + // FIXME: figure out a way to add shadows (for instance along the right edge) + ctx.lineWidth = series.bars.lineWidth; + ctx.strokeStyle = series.color; + + var barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } + + var fillStyleCallback = series.bars.fill ? function (bottom, top) { return getFillStyle(series.bars, series.color, bottom, top); } : null; + plotBars(series.datapoints, barLeft, barLeft + series.bars.barWidth, fillStyleCallback, series.xaxis, series.yaxis); + ctx.restore(); + } + + function getFillStyle(filloptions, seriesColor, bottom, top) { + var fill = filloptions.fill; + if (!fill) + return null; + + if (filloptions.fillColor) + return getColorOrGradient(filloptions.fillColor, bottom, top, seriesColor); + + var c = $.color.parse(seriesColor); + c.a = typeof fill == "number" ? fill : 0.4; + c.normalize(); + return c.toString(); + } + + function insertLegend() { + + if (options.legend.container != null) { + $(options.legend.container).html(""); + } else { + placeholder.find(".legend").remove(); + } + + if (!options.legend.show) { + return; + } + + var fragments = [], entries = [], rowStarted = false, + lf = options.legend.labelFormatter, s, label; + + // Build a list of legend entries, with each having a label and a color + + for (var i = 0; i < series.length; ++i) { + s = series[i]; + if (s.label) { + label = lf ? lf(s.label, s) : s.label; + if (label) { + entries.push({ + label: label, + color: s.color + }); + } + } + } + + // Sort the legend using either the default or a custom comparator + + if (options.legend.sorted) { + if ($.isFunction(options.legend.sorted)) { + entries.sort(options.legend.sorted); + } else if (options.legend.sorted == "reverse") { + entries.reverse(); + } else { + var ascending = options.legend.sorted != "descending"; + entries.sort(function(a, b) { + return a.label == b.label ? 0 : ( + (a.label < b.label) != ascending ? 1 : -1 // Logical XOR + ); + }); + } + } + + // Generate markup for the list of entries, in their final order + + for (var i = 0; i < entries.length; ++i) { + + var entry = entries[i]; + + if (i % options.legend.noColumns == 0) { + if (rowStarted) + fragments.push(''); + fragments.push(''); + rowStarted = true; + } + + fragments.push( + '
' + + '' + entry.label + '' + ); + } + + if (rowStarted) + fragments.push(''); + + if (fragments.length == 0) + return; + + var table = '' + fragments.join("") + '
'; + if (options.legend.container != null) + $(options.legend.container).html(table); + else { + var pos = "", + p = options.legend.position, + m = options.legend.margin; + if (m[0] == null) + m = [m, m]; + if (p.charAt(0) == "n") + pos += 'top:' + (m[1] + plotOffset.top) + 'px;'; + else if (p.charAt(0) == "s") + pos += 'bottom:' + (m[1] + plotOffset.bottom) + 'px;'; + if (p.charAt(1) == "e") + pos += 'right:' + (m[0] + plotOffset.right) + 'px;'; + else if (p.charAt(1) == "w") + pos += 'left:' + (m[0] + plotOffset.left) + 'px;'; + var legend = $('
' + table.replace('style="', 'style="position:absolute;' + pos +';') + '
').appendTo(placeholder); + if (options.legend.backgroundOpacity != 0.0) { + // put in the transparent background + // separately to avoid blended labels and + // label boxes + var c = options.legend.backgroundColor; + if (c == null) { + c = options.grid.backgroundColor; + if (c && typeof c == "string") + c = $.color.parse(c); + else + c = $.color.extract(legend, 'background-color'); + c.a = 1; + c = c.toString(); + } + var div = legend.children(); + $('
').prependTo(legend).css('opacity', options.legend.backgroundOpacity); + } + } + } + + + // interactive features + + var highlights = [], + redrawTimeout = null; + + // returns the data item the mouse is over, or null if none is found + function findNearbyItem(mouseX, mouseY, seriesFilter) { + var maxDistance = options.grid.mouseActiveRadius, + smallestDistance = maxDistance * maxDistance + 1, + item = null, foundPoint = false, i, j, ps; + + for (i = series.length - 1; i >= 0; --i) { + if (!seriesFilter(series[i])) + continue; + + var s = series[i], + axisx = s.xaxis, + axisy = s.yaxis, + points = s.datapoints.points, + mx = axisx.c2p(mouseX), // precompute some stuff to make the loop faster + my = axisy.c2p(mouseY), + maxx = maxDistance / axisx.scale, + maxy = maxDistance / axisy.scale; + + ps = s.datapoints.pointsize; + // with inverse transforms, we can't use the maxx/maxy + // optimization, sadly + if (axisx.options.inverseTransform) + maxx = Number.MAX_VALUE; + if (axisy.options.inverseTransform) + maxy = Number.MAX_VALUE; + + if (s.lines.show || s.points.show) { + for (j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1]; + if (x == null) + continue; + + // For points and lines, the cursor must be within a + // certain distance to the data point + if (x - mx > maxx || x - mx < -maxx || + y - my > maxy || y - my < -maxy) + continue; + + // We have to calculate distances in pixels, not in + // data units, because the scales of the axes may be different + var dx = Math.abs(axisx.p2c(x) - mouseX), + dy = Math.abs(axisy.p2c(y) - mouseY), + dist = dx * dx + dy * dy; // we save the sqrt + + // use <= to ensure last point takes precedence + // (last generally means on top of) + if (dist < smallestDistance) { + smallestDistance = dist; + item = [i, j / ps]; + } + } + } + + if (s.bars.show && !item) { // no other point can be nearby + + var barLeft, barRight; + + switch (s.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -s.bars.barWidth; + break; + default: + barLeft = -s.bars.barWidth / 2; + } + + barRight = barLeft + s.bars.barWidth; + + for (j = 0; j < points.length; j += ps) { + var x = points[j], y = points[j + 1], b = points[j + 2]; + if (x == null) + continue; + + // for a bar graph, the cursor must be inside the bar + if (series[i].bars.horizontal ? + (mx <= Math.max(b, x) && mx >= Math.min(b, x) && + my >= y + barLeft && my <= y + barRight) : + (mx >= x + barLeft && mx <= x + barRight && + my >= Math.min(b, y) && my <= Math.max(b, y))) + item = [i, j / ps]; + } + } + } + + if (item) { + i = item[0]; + j = item[1]; + ps = series[i].datapoints.pointsize; + + return { datapoint: series[i].datapoints.points.slice(j * ps, (j + 1) * ps), + dataIndex: j, + series: series[i], + seriesIndex: i }; + } + + return null; + } + + function onMouseMove(e) { + if (options.grid.hoverable) + triggerClickHoverEvent("plothover", e, + function (s) { return s["hoverable"] != false; }); + } + + function onMouseLeave(e) { + if (options.grid.hoverable) + triggerClickHoverEvent("plothover", e, + function (s) { return false; }); + } + + function onClick(e) { + triggerClickHoverEvent("plotclick", e, + function (s) { return s["clickable"] != false; }); + } + + // trigger click or hover event (they send the same parameters + // so we share their code) + function triggerClickHoverEvent(eventname, event, seriesFilter) { + var offset = eventHolder.offset(), + canvasX = event.pageX - offset.left - plotOffset.left, + canvasY = event.pageY - offset.top - plotOffset.top, + pos = canvasToAxisCoords({ left: canvasX, top: canvasY }); + + pos.pageX = event.pageX; + pos.pageY = event.pageY; + + var item = findNearbyItem(canvasX, canvasY, seriesFilter); + + if (item) { + // fill in mouse pos for any listeners out there + item.pageX = parseInt(item.series.xaxis.p2c(item.datapoint[0]) + offset.left + plotOffset.left, 10); + item.pageY = parseInt(item.series.yaxis.p2c(item.datapoint[1]) + offset.top + plotOffset.top, 10); + } + + if (options.grid.autoHighlight) { + // clear auto-highlights + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.auto == eventname && + !(item && h.series == item.series && + h.point[0] == item.datapoint[0] && + h.point[1] == item.datapoint[1])) + unhighlight(h.series, h.point); + } + + if (item) + highlight(item.series, item.datapoint, eventname); + } + + placeholder.trigger(eventname, [ pos, item ]); + } + + function triggerRedrawOverlay() { + var t = options.interaction.redrawOverlayInterval; + if (t == -1) { // skip event queue + drawOverlay(); + return; + } + + if (!redrawTimeout) + redrawTimeout = setTimeout(drawOverlay, t); + } + + function drawOverlay() { + redrawTimeout = null; + + // draw highlights + octx.save(); + overlay.clear(); + octx.translate(plotOffset.left, plotOffset.top); + + var i, hi; + for (i = 0; i < highlights.length; ++i) { + hi = highlights[i]; + + if (hi.series.bars.show) + drawBarHighlight(hi.series, hi.point); + else + drawPointHighlight(hi.series, hi.point); + } + octx.restore(); + + executeHooks(hooks.drawOverlay, [octx]); + } + + function highlight(s, point, auto) { + if (typeof s == "number") + s = series[s]; + + if (typeof point == "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i == -1) { + highlights.push({ series: s, point: point, auto: auto }); + + triggerRedrawOverlay(); + } + else if (!auto) + highlights[i].auto = false; + } + + function unhighlight(s, point) { + if (s == null && point == null) { + highlights = []; + triggerRedrawOverlay(); + return; + } + + if (typeof s == "number") + s = series[s]; + + if (typeof point == "number") { + var ps = s.datapoints.pointsize; + point = s.datapoints.points.slice(ps * point, ps * (point + 1)); + } + + var i = indexOfHighlight(s, point); + if (i != -1) { + highlights.splice(i, 1); + + triggerRedrawOverlay(); + } + } + + function indexOfHighlight(s, p) { + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.series == s && h.point[0] == p[0] + && h.point[1] == p[1]) + return i; + } + return -1; + } + + function drawPointHighlight(series, point) { + var x = point[0], y = point[1], + axisx = series.xaxis, axisy = series.yaxis, + highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(); + + if (x < axisx.min || x > axisx.max || y < axisy.min || y > axisy.max) + return; + + var pointRadius = series.points.radius + series.points.lineWidth / 2; + octx.lineWidth = pointRadius; + octx.strokeStyle = highlightColor; + var radius = 1.5 * pointRadius; + x = axisx.p2c(x); + y = axisy.p2c(y); + + octx.beginPath(); + if (series.points.symbol == "circle") + octx.arc(x, y, radius, 0, 2 * Math.PI, false); + else + series.points.symbol(octx, x, y, radius, false); + octx.closePath(); + octx.stroke(); + } + + function drawBarHighlight(series, point) { + var highlightColor = (typeof series.highlightColor === "string") ? series.highlightColor : $.color.parse(series.color).scale('a', 0.5).toString(), + fillStyle = highlightColor, + barLeft; + + switch (series.bars.align) { + case "left": + barLeft = 0; + break; + case "right": + barLeft = -series.bars.barWidth; + break; + default: + barLeft = -series.bars.barWidth / 2; + } + + octx.lineWidth = series.bars.lineWidth; + octx.strokeStyle = highlightColor; + + drawBar(point[0], point[1], point[2] || 0, barLeft, barLeft + series.bars.barWidth, + function () { return fillStyle; }, series.xaxis, series.yaxis, octx, series.bars.horizontal, series.bars.lineWidth); + } + + function getColorOrGradient(spec, bottom, top, defaultColor) { + if (typeof spec == "string") + return spec; + else { + // assume this is a gradient spec; IE currently only + // supports a simple vertical gradient properly, so that's + // what we support too + var gradient = ctx.createLinearGradient(0, top, 0, bottom); + + for (var i = 0, l = spec.colors.length; i < l; ++i) { + var c = spec.colors[i]; + if (typeof c != "string") { + var co = $.color.parse(defaultColor); + if (c.brightness != null) + co = co.scale('rgb', c.brightness); + if (c.opacity != null) + co.a *= c.opacity; + c = co.toString(); + } + gradient.addColorStop(i / (l - 1), c); + } + + return gradient; + } + } + } + + // Add the plot function to the top level of the jQuery object + + $.plot = function(placeholder, data, options) { + //var t0 = new Date(); + var plot = new Plot($(placeholder), data, options, $.plot.plugins); + //(window.console ? console.log : alert)("time used (msecs): " + ((new Date()).getTime() - t0.getTime())); + return plot; + }; + + $.plot.version = "0.8.3"; + + $.plot.plugins = []; + + // Also add the plot function as a chainable property + + $.fn.plot = function(data, options) { + return this.each(function() { + $.plot(this, data, options); + }); + }; + + // round to nearby lower multiple of base + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.log.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.log.js new file mode 100644 index 0000000000000..e32bf5cf7e817 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.log.js @@ -0,0 +1,163 @@ +/* @notice + * + * Pretty handling of logarithmic axes. + * Copyright (c) 2007-2014 IOLA and Ole Laursen. + * Licensed under the MIT license. + * Created by Arne de Laat + * Set axis.mode to "log" and make the axis logarithmic using transform: + * axis: { + * mode: 'log', + * transform: function(v) {v <= 0 ? Math.log(v) / Math.LN10 : null}, + * inverseTransform: function(v) {Math.pow(10, v)} + * } + * The transform filters negative and zero values, because those are + * invalid on logarithmic scales. + * This plugin tries to create good looking logarithmic ticks, using + * unicode superscript characters. If all data to be plotted is between two + * powers of ten then the default flot tick generator and renderer are + * used. Logarithmic ticks are places at powers of ten and at half those + * values if there are not to many ticks already (e.g. [1, 5, 10, 50, 100]). + * For details, see https://github.com/flot/flot/pull/1328 +*/ + +(function($) { + + function log10(value) { + /* Get the Log10 of the value + */ + return Math.log(value) / Math.LN10; + } + + function floorAsLog10(value) { + /* Get power of the first power of 10 below the value + */ + return Math.floor(log10(value)); + } + + function ceilAsLog10(value) { + /* Get power of the first power of 10 above the value + */ + return Math.ceil(log10(value)); + } + + + // round to nearby lower multiple of base + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + + function getUnicodePower(power) { + var superscripts = ["⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"], + result = "", + str_power = "" + power; + for (var i = 0; i < str_power.length; i++) { + if (str_power[i] === "+") { + } + else if (str_power[i] === "-") { + result += "⁻"; + } + else { + result += superscripts[str_power[i]]; + } + } + return result; + } + + function init(plot) { + plot.hooks.processOptions.push(function (plot) { + $.each(plot.getAxes(), function(axisName, axis) { + + var opts = axis.options; + + if (opts.mode === "log") { + + axis.tickGenerator = function (axis) { + + var ticks = [], + end = ceilAsLog10(axis.max), + start = floorAsLog10(axis.min), + tick = Number.NaN, + i = 0; + + if (axis.min === null || axis.min <= 0) { + // Bad minimum, make ticks from 1 (10**0) to max + start = 0; + axis.min = 0.6; + } + + if (end <= start) { + // Start less than end?! + ticks = [1e-6, 1e-5, 1e-4, 1e-3, 1e-2, 1e-1, + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, + 1e7, 1e8, 1e9]; + } + else if (log10(axis.max) - log10(axis.datamin) < 1) { + // Default flot generator incase no powers of 10 + // are between start and end + var prev; + start = floorInBase(axis.min, axis.tickSize); + do { + prev = tick; + tick = start + i * axis.tickSize; + ticks.push(tick); + ++i; + } while (tick < axis.max && tick !== prev); + } + else { + // Make ticks at each power of ten + for (; i <= (end - start); i++) { + tick = Math.pow(10, start + i); + ticks.push(tick); + } + + var length = ticks.length; + + // If not to many ticks also put a tick between + // the powers of ten + if (end - start < 6) { + for (var j = 1; j < length * 2 - 1; j += 2) { + tick = ticks[j - 1] * 5; + ticks.splice(j, 0, tick); + } + } + } + return ticks; + }; + + axis.tickFormatter = function (value, axis) { + var formatted; + if (log10(axis.max) - log10(axis.datamin) < 1) { + // Default flot formatter + var factor = axis.tickDecimals ? Math.pow(10, axis.tickDecimals) : 1; + formatted = "" + Math.round(value * factor) / factor; + if (axis.tickDecimals !== null) { + var decimal = formatted.indexOf("."); + var precision = decimal === -1 ? 0 : formatted.length - decimal - 1; + if (precision < axis.tickDecimals) { + return (precision ? formatted : formatted + ".") + ("" + factor).substr(1, axis.tickDecimals - precision); + } + } + } + else { + var multiplier = "", + exponential = parseFloat(value).toExponential(0), + power = getUnicodePower(exponential.slice(2)); + if (exponential[0] !== "1") { + multiplier = exponential[0] + "x"; + } + formatted = multiplier + "10" + power; + } + return formatted; + }; + } + }); + }); + } + + $.plot.plugins.push({ + init: init, + name: "log", + version: "0.9" + }); + +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.navigate.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.navigate.js new file mode 100644 index 0000000000000..13fb7f17d04b2 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.navigate.js @@ -0,0 +1,346 @@ +/* Flot plugin for adding the ability to pan and zoom the plot. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The default behaviour is double click and scrollwheel up/down to zoom in, drag +to pan. The plugin defines plot.zoom({ center }), plot.zoomOut() and +plot.pan( offset ) so you easily can add custom controls. It also fires +"plotpan" and "plotzoom" events, useful for synchronizing plots. + +The plugin supports these options: + + zoom: { + interactive: false + trigger: "dblclick" // or "click" for single click + amount: 1.5 // 2 = 200% (zoom in), 0.5 = 50% (zoom out) + } + + pan: { + interactive: false + cursor: "move" // CSS mouse cursor value used when dragging, e.g. "pointer" + frameRate: 20 + } + + xaxis, yaxis, x2axis, y2axis: { + zoomRange: null // or [ number, number ] (min range, max range) or false + panRange: null // or [ number, number ] (min, max) or false + } + +"interactive" enables the built-in drag/click behaviour. If you enable +interactive for pan, then you'll have a basic plot that supports moving +around; the same for zoom. + +"amount" specifies the default amount to zoom in (so 1.5 = 150%) relative to +the current viewport. + +"cursor" is a standard CSS mouse cursor string used for visual feedback to the +user when dragging. + +"frameRate" specifies the maximum number of times per second the plot will +update itself while the user is panning around on it (set to null to disable +intermediate pans, the plot will then not update until the mouse button is +released). + +"zoomRange" is the interval in which zooming can happen, e.g. with zoomRange: +[1, 100] the zoom will never scale the axis so that the difference between min +and max is smaller than 1 or larger than 100. You can set either end to null +to ignore, e.g. [1, null]. If you set zoomRange to false, zooming on that axis +will be disabled. + +"panRange" confines the panning to stay within a range, e.g. with panRange: +[-10, 20] panning stops at -10 in one end and at 20 in the other. Either can +be null, e.g. [-10, null]. If you set panRange to false, panning on that axis +will be disabled. + +Example API usage: + + plot = $.plot(...); + + // zoom default amount in on the pixel ( 10, 20 ) + plot.zoom({ center: { left: 10, top: 20 } }); + + // zoom out again + plot.zoomOut({ center: { left: 10, top: 20 } }); + + // zoom 200% in on the pixel (10, 20) + plot.zoom({ amount: 2, center: { left: 10, top: 20 } }); + + // pan 100 pixels to the left and 20 down + plot.pan({ left: -100, top: 20 }) + +Here, "center" specifies where the center of the zooming should happen. Note +that this is defined in pixel space, not the space of the data points (you can +use the p2c helpers on the axes in Flot to help you convert between these). + +"amount" is the amount to zoom the viewport relative to the current range, so +1 is 100% (i.e. no change), 1.5 is 150% (zoom in), 0.7 is 70% (zoom out). You +can set the default in the options. + +*/ + +// First two dependencies, jquery.event.drag.js and +// jquery.mousewheel.js, we put them inline here to save people the +// effort of downloading them. + +/* +jquery.event.drag.js ~ v1.5 ~ Copyright (c) 2008, Three Dub Media (http://threedubmedia.com) +Licensed under the MIT License ~ http://threedubmedia.googlecode.com/files/MIT-LICENSE.txt +*/ +(function(a){function e(h){var k,j=this,l=h.data||{};if(l.elem)j=h.dragTarget=l.elem,h.dragProxy=d.proxy||j,h.cursorOffsetX=l.pageX-l.left,h.cursorOffsetY=l.pageY-l.top,h.offsetX=h.pageX-h.cursorOffsetX,h.offsetY=h.pageY-h.cursorOffsetY;else if(d.dragging||l.which>0&&h.which!=l.which||a(h.target).is(l.not))return;switch(h.type){case"mousedown":return a.extend(l,a(j).offset(),{elem:j,target:h.target,pageX:h.pageX,pageY:h.pageY}),b.add(document,"mousemove mouseup",e,l),i(j,!1),d.dragging=null,!1;case!d.dragging&&"mousemove":if(g(h.pageX-l.pageX)+g(h.pageY-l.pageY) max) { + // make sure min < max + var tmp = min; + min = max; + max = tmp; + } + + //Check that we are in panRange + if (pr) { + if (pr[0] != null && min < pr[0]) { + min = pr[0]; + } + if (pr[1] != null && max > pr[1]) { + max = pr[1]; + } + } + + var range = max - min; + if (zr && + ((zr[0] != null && range < zr[0] && amount >1) || + (zr[1] != null && range > zr[1] && amount <1))) + return; + + opts.min = min; + opts.max = max; + }); + + plot.setupGrid(); + plot.draw(); + + if (!args.preventEvent) + plot.getPlaceholder().trigger("plotzoom", [ plot, args ]); + }; + + plot.pan = function (args) { + var delta = { + x: +args.left, + y: +args.top + }; + + if (isNaN(delta.x)) + delta.x = 0; + if (isNaN(delta.y)) + delta.y = 0; + + $.each(plot.getAxes(), function (_, axis) { + var opts = axis.options, + min, max, d = delta[axis.direction]; + + min = axis.c2p(axis.p2c(axis.min) + d), + max = axis.c2p(axis.p2c(axis.max) + d); + + var pr = opts.panRange; + if (pr === false) // no panning on this axis + return; + + if (pr) { + // check whether we hit the wall + if (pr[0] != null && pr[0] > min) { + d = pr[0] - min; + min += d; + max += d; + } + + if (pr[1] != null && pr[1] < max) { + d = pr[1] - max; + min += d; + max += d; + } + } + + opts.min = min; + opts.max = max; + }); + + plot.setupGrid(); + plot.draw(); + + if (!args.preventEvent) + plot.getPlaceholder().trigger("plotpan", [ plot, args ]); + }; + + function shutdown(plot, eventHolder) { + eventHolder.unbind(plot.getOptions().zoom.trigger, onZoomClick); + eventHolder.unbind("mousewheel", onMouseWheel); + eventHolder.unbind("dragstart", onDragStart); + eventHolder.unbind("drag", onDrag); + eventHolder.unbind("dragend", onDragEnd); + if (panTimeout) + clearTimeout(panTimeout); + } + + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'navigate', + version: '1.3' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.pie.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.pie.js new file mode 100644 index 0000000000000..24148c0a2e223 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.pie.js @@ -0,0 +1,824 @@ +/* Flot plugin for rendering pie charts. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin assumes that each series has a single data value, and that each +value is a positive integer or zero. Negative numbers don't make sense for a +pie chart, and have unpredictable results. The values do NOT need to be +passed in as percentages; the plugin will calculate the total and per-slice +percentages internally. + +* Created by Brian Medendorp + +* Updated with contributions from btburnett3, Anthony Aragues and Xavi Ivars + +The plugin supports these options: + + series: { + pie: { + show: true/false + radius: 0-1 for percentage of fullsize, or a specified pixel length, or 'auto' + innerRadius: 0-1 for percentage of fullsize or a specified pixel length, for creating a donut effect + startAngle: 0-2 factor of PI used for starting angle (in radians) i.e 3/2 starts at the top, 0 and 2 have the same result + tilt: 0-1 for percentage to tilt the pie, where 1 is no tilt, and 0 is completely flat (nothing will show) + offset: { + top: integer value to move the pie up or down + left: integer value to move the pie left or right, or 'auto' + }, + stroke: { + color: any hexadecimal color value (other formats may or may not work, so best to stick with something like '#FFF') + width: integer pixel width of the stroke + }, + label: { + show: true/false, or 'auto' + formatter: a user-defined function that modifies the text/style of the label text + radius: 0-1 for percentage of fullsize, or a specified pixel length + background: { + color: any hexadecimal color value (other formats may or may not work, so best to stick with something like '#000') + opacity: 0-1 + }, + threshold: 0-1 for the percentage value at which to hide labels (if they're too small) + }, + combine: { + threshold: 0-1 for the percentage value at which to combine slices (if they're too small) + color: any hexadecimal color value (other formats may or may not work, so best to stick with something like '#CCC'), if null, the plugin will automatically use the color of the first slice to be combined + label: any text value of what the combined slice should be labeled + } + highlight: { + opacity: 0-1 + } + } + } + +More detail and specific examples can be found in the included HTML file. + +*/ + +import { i18n } from '@kbn/i18n'; + +(function($) { + // Maximum redraw attempts when fitting labels within the plot + + var REDRAW_ATTEMPTS = 10; + + // Factor by which to shrink the pie when fitting labels within the plot + + var REDRAW_SHRINK = 0.95; + + function init(plot) { + + var canvas = null, + target = null, + options = null, + maxRadius = null, + centerLeft = null, + centerTop = null, + processed = false, + ctx = null; + + // interactive variables + + var highlights = []; + + // add hook to determine if pie plugin in enabled, and then perform necessary operations + + plot.hooks.processOptions.push(function(plot, options) { + if (options.series.pie.show) { + + options.grid.show = false; + + // set labels.show + + if (options.series.pie.label.show == "auto") { + if (options.legend.show) { + options.series.pie.label.show = false; + } else { + options.series.pie.label.show = true; + } + } + + // set radius + + if (options.series.pie.radius == "auto") { + if (options.series.pie.label.show) { + options.series.pie.radius = 3/4; + } else { + options.series.pie.radius = 1; + } + } + + // ensure sane tilt + + if (options.series.pie.tilt > 1) { + options.series.pie.tilt = 1; + } else if (options.series.pie.tilt < 0) { + options.series.pie.tilt = 0; + } + } + }); + + plot.hooks.bindEvents.push(function(plot, eventHolder) { + var options = plot.getOptions(); + if (options.series.pie.show) { + if (options.grid.hoverable) { + eventHolder.unbind("mousemove").mousemove(onMouseMove); + } + if (options.grid.clickable) { + eventHolder.unbind("click").click(onClick); + } + } + }); + + plot.hooks.processDatapoints.push(function(plot, series, data, datapoints) { + var options = plot.getOptions(); + if (options.series.pie.show) { + processDatapoints(plot, series, data, datapoints); + } + }); + + plot.hooks.drawOverlay.push(function(plot, octx) { + var options = plot.getOptions(); + if (options.series.pie.show) { + drawOverlay(plot, octx); + } + }); + + plot.hooks.draw.push(function(plot, newCtx) { + var options = plot.getOptions(); + if (options.series.pie.show) { + draw(plot, newCtx); + } + }); + + function processDatapoints(plot, series, datapoints) { + if (!processed) { + processed = true; + canvas = plot.getCanvas(); + target = $(canvas).parent(); + options = plot.getOptions(); + plot.setData(combine(plot.getData())); + } + } + + function combine(data) { + + var total = 0, + combined = 0, + numCombined = 0, + color = options.series.pie.combine.color, + newdata = []; + + // Fix up the raw data from Flot, ensuring the data is numeric + + for (var i = 0; i < data.length; ++i) { + + var value = data[i].data; + + // If the data is an array, we'll assume that it's a standard + // Flot x-y pair, and are concerned only with the second value. + + // Note how we use the original array, rather than creating a + // new one; this is more efficient and preserves any extra data + // that the user may have stored in higher indexes. + + if ($.isArray(value) && value.length == 1) { + value = value[0]; + } + + if ($.isArray(value)) { + // Equivalent to $.isNumeric() but compatible with jQuery < 1.7 + if (!isNaN(parseFloat(value[1])) && isFinite(value[1])) { + value[1] = +value[1]; + } else { + value[1] = 0; + } + } else if (!isNaN(parseFloat(value)) && isFinite(value)) { + value = [1, +value]; + } else { + value = [1, 0]; + } + + data[i].data = [value]; + } + + // Sum up all the slices, so we can calculate percentages for each + + for (var i = 0; i < data.length; ++i) { + total += data[i].data[0][1]; + } + + // Count the number of slices with percentages below the combine + // threshold; if it turns out to be just one, we won't combine. + + for (var i = 0; i < data.length; ++i) { + var value = data[i].data[0][1]; + if (value / total <= options.series.pie.combine.threshold) { + combined += value; + numCombined++; + if (!color) { + color = data[i].color; + } + } + } + + for (var i = 0; i < data.length; ++i) { + var value = data[i].data[0][1]; + if (numCombined < 2 || value / total > options.series.pie.combine.threshold) { + newdata.push( + $.extend(data[i], { /* extend to allow keeping all other original data values + and using them e.g. in labelFormatter. */ + data: [[1, value]], + color: data[i].color, + label: data[i].label, + angle: value * Math.PI * 2 / total, + percent: value / (total / 100) + }) + ); + } + } + + if (numCombined > 1) { + newdata.push({ + data: [[1, combined]], + color: color, + label: options.series.pie.combine.label, + angle: combined * Math.PI * 2 / total, + percent: combined / (total / 100) + }); + } + + return newdata; + } + + function draw(plot, newCtx) { + + if (!target) { + return; // if no series were passed + } + + var canvasWidth = plot.getPlaceholder().width(), + canvasHeight = plot.getPlaceholder().height(), + legendWidth = target.children().filter(".legend").children().width() || 0; + + ctx = newCtx; + + // WARNING: HACK! REWRITE THIS CODE AS SOON AS POSSIBLE! + + // When combining smaller slices into an 'other' slice, we need to + // add a new series. Since Flot gives plugins no way to modify the + // list of series, the pie plugin uses a hack where the first call + // to processDatapoints results in a call to setData with the new + // list of series, then subsequent processDatapoints do nothing. + + // The plugin-global 'processed' flag is used to control this hack; + // it starts out false, and is set to true after the first call to + // processDatapoints. + + // Unfortunately this turns future setData calls into no-ops; they + // call processDatapoints, the flag is true, and nothing happens. + + // To fix this we'll set the flag back to false here in draw, when + // all series have been processed, so the next sequence of calls to + // processDatapoints once again starts out with a slice-combine. + // This is really a hack; in 0.9 we need to give plugins a proper + // way to modify series before any processing begins. + + processed = false; + + // calculate maximum radius and center point + + maxRadius = Math.min(canvasWidth, canvasHeight / options.series.pie.tilt) / 2; + centerTop = canvasHeight / 2 + options.series.pie.offset.top; + centerLeft = canvasWidth / 2; + + if (options.series.pie.offset.left == "auto") { + if (options.legend.position.match("w")) { + centerLeft += legendWidth / 2; + } else { + centerLeft -= legendWidth / 2; + } + if (centerLeft < maxRadius) { + centerLeft = maxRadius; + } else if (centerLeft > canvasWidth - maxRadius) { + centerLeft = canvasWidth - maxRadius; + } + } else { + centerLeft += options.series.pie.offset.left; + } + + var slices = plot.getData(), + attempts = 0; + + // Keep shrinking the pie's radius until drawPie returns true, + // indicating that all the labels fit, or we try too many times. + + do { + if (attempts > 0) { + maxRadius *= REDRAW_SHRINK; + } + attempts += 1; + clear(); + if (options.series.pie.tilt <= 0.8) { + drawShadow(); + } + } while (!drawPie() && attempts < REDRAW_ATTEMPTS) + + if (attempts >= REDRAW_ATTEMPTS) { + clear(); + const errorMessage = i18n.translate('xpack.monitoring.pie.unableToDrawLabelsInsideCanvasErrorMessage', { + defaultMessage: 'Could not draw pie with labels contained inside canvas', + }); + target.prepend(`
${errorMessage}
`); + } + + if (plot.setSeries && plot.insertLegend) { + plot.setSeries(slices); + plot.insertLegend(); + } + + // we're actually done at this point, just defining internal functions at this point + + function clear() { + ctx.clearRect(0, 0, canvasWidth, canvasHeight); + target.children().filter(".pieLabel, .pieLabelBackground").remove(); + } + + function drawShadow() { + + var shadowLeft = options.series.pie.shadow.left; + var shadowTop = options.series.pie.shadow.top; + var edge = 10; + var alpha = options.series.pie.shadow.alpha; + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + + if (radius >= canvasWidth / 2 - shadowLeft || radius * options.series.pie.tilt >= canvasHeight / 2 - shadowTop || radius <= edge) { + return; // shadow would be outside canvas, so don't draw it + } + + ctx.save(); + ctx.translate(shadowLeft,shadowTop); + ctx.globalAlpha = alpha; + ctx.fillStyle = "#000"; + + // center and rotate to starting position + + ctx.translate(centerLeft,centerTop); + ctx.scale(1, options.series.pie.tilt); + + //radius -= edge; + + for (var i = 1; i <= edge; i++) { + ctx.beginPath(); + ctx.arc(0, 0, radius, 0, Math.PI * 2, false); + ctx.fill(); + radius -= i; + } + + ctx.restore(); + } + + function drawPie() { + + var startAngle = Math.PI * options.series.pie.startAngle; + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + + // center and rotate to starting position + + ctx.save(); + ctx.translate(centerLeft,centerTop); + ctx.scale(1, options.series.pie.tilt); + //ctx.rotate(startAngle); // start at top; -- This doesn't work properly in Opera + + // draw slices + + ctx.save(); + var currentAngle = startAngle; + for (var i = 0; i < slices.length; ++i) { + slices[i].startAngle = currentAngle; + drawSlice(slices[i].angle, slices[i].color, true); + } + ctx.restore(); + + // draw slice outlines + + if (options.series.pie.stroke.width > 0) { + ctx.save(); + ctx.lineWidth = options.series.pie.stroke.width; + currentAngle = startAngle; + for (var i = 0; i < slices.length; ++i) { + drawSlice(slices[i].angle, options.series.pie.stroke.color, false); + } + ctx.restore(); + } + + // draw donut hole + + drawDonutHole(ctx); + + ctx.restore(); + + // Draw the labels, returning true if they fit within the plot + + if (options.series.pie.label.show) { + return drawLabels(); + } else return true; + + function drawSlice(angle, color, fill) { + + if (angle <= 0 || isNaN(angle)) { + return; + } + + if (fill) { + ctx.fillStyle = color; + } else { + ctx.strokeStyle = color; + ctx.lineJoin = "round"; + } + + ctx.beginPath(); + if (Math.abs(angle - Math.PI * 2) > 0.000000001) { + ctx.moveTo(0, 0); // Center of the pie + } + + //ctx.arc(0, 0, radius, 0, angle, false); // This doesn't work properly in Opera + ctx.arc(0, 0, radius,currentAngle, currentAngle + angle / 2, false); + ctx.arc(0, 0, radius,currentAngle + angle / 2, currentAngle + angle, false); + ctx.closePath(); + //ctx.rotate(angle); // This doesn't work properly in Opera + currentAngle += angle; + + if (fill) { + ctx.fill(); + } else { + ctx.stroke(); + } + } + + function drawLabels() { + + var currentAngle = startAngle; + var radius = options.series.pie.label.radius > 1 ? options.series.pie.label.radius : maxRadius * options.series.pie.label.radius; + + for (var i = 0; i < slices.length; ++i) { + if (slices[i].percent >= options.series.pie.label.threshold * 100) { + if (!drawLabel(slices[i], currentAngle, i)) { + return false; + } + } + currentAngle += slices[i].angle; + } + + return true; + + function drawLabel(slice, startAngle, index) { + + if (slice.data[0][1] == 0) { + return true; + } + + // format label text + + var lf = options.legend.labelFormatter, text, plf = options.series.pie.label.formatter; + + if (lf) { + text = lf(slice.label, slice); + } else { + text = slice.label; + } + + if (plf) { + text = plf(text, slice); + } + + var halfAngle = ((startAngle + slice.angle) + startAngle) / 2; + var x = centerLeft + Math.round(Math.cos(halfAngle) * radius); + var y = centerTop + Math.round(Math.sin(halfAngle) * radius) * options.series.pie.tilt; + + var html = "" + text + ""; + target.append(html); + + var label = target.children("#pieLabel" + index); + var labelTop = (y - label.height() / 2); + var labelLeft = (x - label.width() / 2); + + label.css("top", labelTop); + label.css("left", labelLeft); + + // check to make sure that the label is not outside the canvas + + if (0 - labelTop > 0 || 0 - labelLeft > 0 || canvasHeight - (labelTop + label.height()) < 0 || canvasWidth - (labelLeft + label.width()) < 0) { + return false; + } + + if (options.series.pie.label.background.opacity != 0) { + + // put in the transparent background separately to avoid blended labels and label boxes + + var c = options.series.pie.label.background.color; + + if (c == null) { + c = slice.color; + } + + var pos = "top:" + labelTop + "px;left:" + labelLeft + "px;"; + $("
") + .css("opacity", options.series.pie.label.background.opacity) + .insertBefore(label); + } + + return true; + } // end individual label function + } // end drawLabels function + } // end drawPie function + } // end draw function + + // Placed here because it needs to be accessed from multiple locations + + function drawDonutHole(layer) { + if (options.series.pie.innerRadius > 0) { + + // subtract the center + + layer.save(); + var innerRadius = options.series.pie.innerRadius > 1 ? options.series.pie.innerRadius : maxRadius * options.series.pie.innerRadius; + layer.globalCompositeOperation = "destination-out"; // this does not work with excanvas, but it will fall back to using the stroke color + layer.beginPath(); + layer.fillStyle = options.series.pie.stroke.color; + layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false); + layer.fill(); + layer.closePath(); + layer.restore(); + + // add inner stroke + + layer.save(); + layer.beginPath(); + layer.strokeStyle = options.series.pie.stroke.color; + layer.arc(0, 0, innerRadius, 0, Math.PI * 2, false); + layer.stroke(); + layer.closePath(); + layer.restore(); + + // TODO: add extra shadow inside hole (with a mask) if the pie is tilted. + } + } + + //-- Additional Interactive related functions -- + + function isPointInPoly(poly, pt) { + for(var c = false, i = -1, l = poly.length, j = l - 1; ++i < l; j = i) + ((poly[i][1] <= pt[1] && pt[1] < poly[j][1]) || (poly[j][1] <= pt[1] && pt[1]< poly[i][1])) + && (pt[0] < (poly[j][0] - poly[i][0]) * (pt[1] - poly[i][1]) / (poly[j][1] - poly[i][1]) + poly[i][0]) + && (c = !c); + return c; + } + + function findNearbySlice(mouseX, mouseY) { + + var slices = plot.getData(), + options = plot.getOptions(), + radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius, + x, y; + + for (var i = 0; i < slices.length; ++i) { + + var s = slices[i]; + + if (s.pie.show) { + + ctx.save(); + ctx.beginPath(); + ctx.moveTo(0, 0); // Center of the pie + //ctx.scale(1, options.series.pie.tilt); // this actually seems to break everything when here. + ctx.arc(0, 0, radius, s.startAngle, s.startAngle + s.angle / 2, false); + ctx.arc(0, 0, radius, s.startAngle + s.angle / 2, s.startAngle + s.angle, false); + ctx.closePath(); + x = mouseX - centerLeft; + y = mouseY - centerTop; + + if (ctx.isPointInPath) { + if (ctx.isPointInPath(mouseX - centerLeft, mouseY - centerTop)) { + ctx.restore(); + return { + datapoint: [s.percent, s.data], + dataIndex: 0, + series: s, + seriesIndex: i + }; + } + } else { + + // excanvas for IE doesn;t support isPointInPath, this is a workaround. + + var p1X = radius * Math.cos(s.startAngle), + p1Y = radius * Math.sin(s.startAngle), + p2X = radius * Math.cos(s.startAngle + s.angle / 4), + p2Y = radius * Math.sin(s.startAngle + s.angle / 4), + p3X = radius * Math.cos(s.startAngle + s.angle / 2), + p3Y = radius * Math.sin(s.startAngle + s.angle / 2), + p4X = radius * Math.cos(s.startAngle + s.angle / 1.5), + p4Y = radius * Math.sin(s.startAngle + s.angle / 1.5), + p5X = radius * Math.cos(s.startAngle + s.angle), + p5Y = radius * Math.sin(s.startAngle + s.angle), + arrPoly = [[0, 0], [p1X, p1Y], [p2X, p2Y], [p3X, p3Y], [p4X, p4Y], [p5X, p5Y]], + arrPoint = [x, y]; + + // TODO: perhaps do some mathematical trickery here with the Y-coordinate to compensate for pie tilt? + + if (isPointInPoly(arrPoly, arrPoint)) { + ctx.restore(); + return { + datapoint: [s.percent, s.data], + dataIndex: 0, + series: s, + seriesIndex: i + }; + } + } + + ctx.restore(); + } + } + + return null; + } + + function onMouseMove(e) { + triggerClickHoverEvent("plothover", e); + } + + function onClick(e) { + triggerClickHoverEvent("plotclick", e); + } + + // trigger click or hover event (they send the same parameters so we share their code) + + function triggerClickHoverEvent(eventname, e) { + + var offset = plot.offset(); + var canvasX = parseInt(e.pageX - offset.left); + var canvasY = parseInt(e.pageY - offset.top); + var item = findNearbySlice(canvasX, canvasY); + + if (options.grid.autoHighlight) { + + // clear auto-highlights + + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.auto == eventname && !(item && h.series == item.series)) { + unhighlight(h.series); + } + } + } + + // highlight the slice + + if (item) { + highlight(item.series, eventname); + } + + // trigger any hover bind events + + var pos = { pageX: e.pageX, pageY: e.pageY }; + target.trigger(eventname, [pos, item]); + } + + function highlight(s, auto) { + //if (typeof s == "number") { + // s = series[s]; + //} + + var i = indexOfHighlight(s); + + if (i == -1) { + highlights.push({ series: s, auto: auto }); + plot.triggerRedrawOverlay(); + } else if (!auto) { + highlights[i].auto = false; + } + } + + function unhighlight(s) { + if (s == null) { + highlights = []; + plot.triggerRedrawOverlay(); + } + + //if (typeof s == "number") { + // s = series[s]; + //} + + var i = indexOfHighlight(s); + + if (i != -1) { + highlights.splice(i, 1); + plot.triggerRedrawOverlay(); + } + } + + function indexOfHighlight(s) { + for (var i = 0; i < highlights.length; ++i) { + var h = highlights[i]; + if (h.series == s) + return i; + } + return -1; + } + + function drawOverlay(plot, octx) { + + var options = plot.getOptions(); + + var radius = options.series.pie.radius > 1 ? options.series.pie.radius : maxRadius * options.series.pie.radius; + + octx.save(); + octx.translate(centerLeft, centerTop); + octx.scale(1, options.series.pie.tilt); + + for (var i = 0; i < highlights.length; ++i) { + drawHighlight(highlights[i].series); + } + + drawDonutHole(octx); + + octx.restore(); + + function drawHighlight(series) { + + if (series.angle <= 0 || isNaN(series.angle)) { + return; + } + + //octx.fillStyle = parseColor(options.series.pie.highlight.color).scale(null, null, null, options.series.pie.highlight.opacity).toString(); + octx.fillStyle = "rgba(255, 255, 255, " + options.series.pie.highlight.opacity + ")"; // this is temporary until we have access to parseColor + octx.beginPath(); + if (Math.abs(series.angle - Math.PI * 2) > 0.000000001) { + octx.moveTo(0, 0); // Center of the pie + } + octx.arc(0, 0, radius, series.startAngle, series.startAngle + series.angle / 2, false); + octx.arc(0, 0, radius, series.startAngle + series.angle / 2, series.startAngle + series.angle, false); + octx.closePath(); + octx.fill(); + } + } + } // end init (plugin body) + + // define pie specific options and their default values + + var options = { + series: { + pie: { + show: false, + radius: "auto", // actual radius of the visible pie (based on full calculated radius if <=1, or hard pixel value) + innerRadius: 0, /* for donut */ + startAngle: 3/2, + tilt: 1, + shadow: { + left: 5, // shadow left offset + top: 15, // shadow top offset + alpha: 0.02 // shadow alpha + }, + offset: { + top: 0, + left: "auto" + }, + stroke: { + color: "#fff", + width: 1 + }, + label: { + show: "auto", + formatter: function(label, slice) { + return "
" + label + "
" + Math.round(slice.percent) + "%
"; + }, // formatter function + radius: 1, // radius at which to place the labels (based on full calculated radius if <=1, or hard pixel value) + background: { + color: null, + opacity: 0 + }, + threshold: 0 // percentage at which to hide the label (i.e. the slice is too narrow) + }, + combine: { + threshold: -1, // percentage at which to combine little slices into one larger slice + color: null, // color to give the new slice (auto-generated if null) + label: "Other" // label to give the new slice + }, + highlight: { + //color: "#fff", // will add this functionality once parseColor is available + opacity: 0.5 + } + } + } + }; + + $.plot.plugins.push({ + init: init, + options: options, + name: "pie", + version: "1.1" + }); + +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.resize.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.resize.js new file mode 100644 index 0000000000000..8a626dda0addb --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.resize.js @@ -0,0 +1,59 @@ +/* Flot plugin for automatically redrawing plots as the placeholder resizes. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +It works by listening for changes on the placeholder div (through the jQuery +resize event plugin) - if the size changes, it will redraw the plot. + +There are no options. If you need to disable the plugin for some plots, you +can just fix the size of their placeholders. + +*/ + +/* Inline dependency: + * jQuery resize event - v1.1 - 3/14/2010 + * http://benalman.com/projects/jquery-resize-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function($,e,t){"$:nomunge";var i=[],n=$.resize=$.extend($.resize,{}),a,r=false,s="setTimeout",u="resize",m=u+"-special-event",o="pendingDelay",l="activeDelay",f="throttleWindow";n[o]=200;n[l]=20;n[f]=true;$.event.special[u]={setup:function(){if(!n[f]&&this[s]){return false}var e=$(this);i.push(this);e.data(m,{w:e.width(),h:e.height()});if(i.length===1){a=t;h()}},teardown:function(){if(!n[f]&&this[s]){return false}var e=$(this);for(var t=i.length-1;t>=0;t--){if(i[t]==this){i.splice(t,1);break}}e.removeData(m);if(!i.length){if(r){cancelAnimationFrame(a)}else{clearTimeout(a)}a=null}},add:function(e){if(!n[f]&&this[s]){return false}var i;function a(e,n,a){var r=$(this),s=r.data(m)||{};s.w=n!==t?n:r.width();s.h=a!==t?a:r.height();i.apply(this,arguments)}if($.isFunction(e)){i=e;return a}else{i=e.handler;e.handler=a}}};function h(t){if(r===true){r=t||1}for(var s=i.length-1;s>=0;s--){var l=$(i[s]);if(l[0]==e||l.is(":visible")){var f=l.width(),c=l.height(),d=l.data(m);if(d&&(f!==d.w||c!==d.h)){l.trigger(u,[d.w=f,d.h=c]);r=t||true}}else{d=l.data(m);d.w=0;d.h=0}}if(a!==null){if(r&&(t==null||t-r<1e3)){a=e.requestAnimationFrame(h)}else{a=setTimeout(h,n[o]);r=false}}}if(!e.requestAnimationFrame){e.requestAnimationFrame=function(){return e.webkitRequestAnimationFrame||e.mozRequestAnimationFrame||e.oRequestAnimationFrame||e.msRequestAnimationFrame||function(t,i){return e.setTimeout(function(){t((new Date).getTime())},n[l])}}()}if(!e.cancelAnimationFrame){e.cancelAnimationFrame=function(){return e.webkitCancelRequestAnimationFrame||e.mozCancelRequestAnimationFrame||e.oCancelRequestAnimationFrame||e.msCancelRequestAnimationFrame||clearTimeout}()}})(jQuery,this); + +(function ($) { + var options = { }; // no options + + function init(plot) { + function onResize() { + var placeholder = plot.getPlaceholder(); + + // somebody might have hidden us and we can't plot + // when we don't have the dimensions + if (placeholder.width() == 0 || placeholder.height() == 0) + return; + + plot.resize(); + plot.setupGrid(); + plot.draw(); + } + + function bindEvents(plot, eventHolder) { + plot.getPlaceholder().resize(onResize); + } + + function shutdown(plot, eventHolder) { + plot.getPlaceholder().unbind("resize", onResize); + } + + plot.hooks.bindEvents.push(bindEvents); + plot.hooks.shutdown.push(shutdown); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'resize', + version: '1.0' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.selection.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.selection.js new file mode 100644 index 0000000000000..c8707b30f4e6f --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.selection.js @@ -0,0 +1,360 @@ +/* Flot plugin for selecting regions of a plot. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + +selection: { + mode: null or "x" or "y" or "xy", + color: color, + shape: "round" or "miter" or "bevel", + minSize: number of pixels +} + +Selection support is enabled by setting the mode to one of "x", "y" or "xy". +In "x" mode, the user will only be able to specify the x range, similarly for +"y" mode. For "xy", the selection becomes a rectangle where both ranges can be +specified. "color" is color of the selection (if you need to change the color +later on, you can get to it with plot.getOptions().selection.color). "shape" +is the shape of the corners of the selection. + +"minSize" is the minimum size a selection can be in pixels. This value can +be customized to determine the smallest size a selection can be and still +have the selection rectangle be displayed. When customizing this value, the +fact that it refers to pixels, not axis units must be taken into account. +Thus, for example, if there is a bar graph in time mode with BarWidth set to 1 +minute, setting "minSize" to 1 will not make the minimum selection size 1 +minute, but rather 1 pixel. Note also that setting "minSize" to 0 will prevent +"plotunselected" events from being fired when the user clicks the mouse without +dragging. + +When selection support is enabled, a "plotselected" event will be emitted on +the DOM element you passed into the plot function. The event handler gets a +parameter with the ranges selected on the axes, like this: + + placeholder.bind( "plotselected", function( event, ranges ) { + alert("You selected " + ranges.xaxis.from + " to " + ranges.xaxis.to) + // similar for yaxis - with multiple axes, the extra ones are in + // x2axis, x3axis, ... + }); + +The "plotselected" event is only fired when the user has finished making the +selection. A "plotselecting" event is fired during the process with the same +parameters as the "plotselected" event, in case you want to know what's +happening while it's happening, + +A "plotunselected" event with no arguments is emitted when the user clicks the +mouse to remove the selection. As stated above, setting "minSize" to 0 will +destroy this behavior. + +The plugin also adds the following methods to the plot object: + +- setSelection( ranges, preventEvent ) + + Set the selection rectangle. The passed in ranges is on the same form as + returned in the "plotselected" event. If the selection mode is "x", you + should put in either an xaxis range, if the mode is "y" you need to put in + an yaxis range and both xaxis and yaxis if the selection mode is "xy", like + this: + + setSelection({ xaxis: { from: 0, to: 10 }, yaxis: { from: 40, to: 60 } }); + + setSelection will trigger the "plotselected" event when called. If you don't + want that to happen, e.g. if you're inside a "plotselected" handler, pass + true as the second parameter. If you are using multiple axes, you can + specify the ranges on any of those, e.g. as x2axis/x3axis/... instead of + xaxis, the plugin picks the first one it sees. + +- clearSelection( preventEvent ) + + Clear the selection rectangle. Pass in true to avoid getting a + "plotunselected" event. + +- getSelection() + + Returns the current selection in the same format as the "plotselected" + event. If there's currently no selection, the function returns null. + +*/ + +(function ($) { + function init(plot) { + var selection = { + first: { x: -1, y: -1}, second: { x: -1, y: -1}, + show: false, + active: false + }; + + // FIXME: The drag handling implemented here should be + // abstracted out, there's some similar code from a library in + // the navigation plugin, this should be massaged a bit to fit + // the Flot cases here better and reused. Doing this would + // make this plugin much slimmer. + var savedhandlers = {}; + + var mouseUpHandler = null; + + function onMouseMove(e) { + if (selection.active) { + updateSelection(e); + + plot.getPlaceholder().trigger("plotselecting", [ getSelection() ]); + } + } + + function onMouseDown(e) { + if (e.which != 1) // only accept left-click + return; + + // cancel out any text selections + document.body.focus(); + + // prevent text selection and drag in old-school browsers + if (document.onselectstart !== undefined && savedhandlers.onselectstart == null) { + savedhandlers.onselectstart = document.onselectstart; + document.onselectstart = function () { return false; }; + } + if (document.ondrag !== undefined && savedhandlers.ondrag == null) { + savedhandlers.ondrag = document.ondrag; + document.ondrag = function () { return false; }; + } + + setSelectionPos(selection.first, e); + + selection.active = true; + + // this is a bit silly, but we have to use a closure to be + // able to whack the same handler again + mouseUpHandler = function (e) { onMouseUp(e); }; + + $(document).one("mouseup", mouseUpHandler); + } + + function onMouseUp(e) { + mouseUpHandler = null; + + // revert drag stuff for old-school browsers + if (document.onselectstart !== undefined) + document.onselectstart = savedhandlers.onselectstart; + if (document.ondrag !== undefined) + document.ondrag = savedhandlers.ondrag; + + // no more dragging + selection.active = false; + updateSelection(e); + + if (selectionIsSane()) + triggerSelectedEvent(); + else { + // this counts as a clear + plot.getPlaceholder().trigger("plotunselected", [ ]); + plot.getPlaceholder().trigger("plotselecting", [ null ]); + } + + return false; + } + + function getSelection() { + if (!selectionIsSane()) + return null; + + if (!selection.show) return null; + + var r = {}, c1 = selection.first, c2 = selection.second; + $.each(plot.getAxes(), function (name, axis) { + if (axis.used) { + var p1 = axis.c2p(c1[axis.direction]), p2 = axis.c2p(c2[axis.direction]); + r[name] = { from: Math.min(p1, p2), to: Math.max(p1, p2) }; + } + }); + return r; + } + + function triggerSelectedEvent() { + var r = getSelection(); + + plot.getPlaceholder().trigger("plotselected", [ r ]); + + // backwards-compat stuff, to be removed in future + if (r.xaxis && r.yaxis) + plot.getPlaceholder().trigger("selected", [ { x1: r.xaxis.from, y1: r.yaxis.from, x2: r.xaxis.to, y2: r.yaxis.to } ]); + } + + function clamp(min, value, max) { + return value < min ? min: (value > max ? max: value); + } + + function setSelectionPos(pos, e) { + var o = plot.getOptions(); + var offset = plot.getPlaceholder().offset(); + var plotOffset = plot.getPlotOffset(); + pos.x = clamp(0, e.pageX - offset.left - plotOffset.left, plot.width()); + pos.y = clamp(0, e.pageY - offset.top - plotOffset.top, plot.height()); + + if (o.selection.mode == "y") + pos.x = pos == selection.first ? 0 : plot.width(); + + if (o.selection.mode == "x") + pos.y = pos == selection.first ? 0 : plot.height(); + } + + function updateSelection(pos) { + if (pos.pageX == null) + return; + + setSelectionPos(selection.second, pos); + if (selectionIsSane()) { + selection.show = true; + plot.triggerRedrawOverlay(); + } + else + clearSelection(true); + } + + function clearSelection(preventEvent) { + if (selection.show) { + selection.show = false; + plot.triggerRedrawOverlay(); + if (!preventEvent) + plot.getPlaceholder().trigger("plotunselected", [ ]); + } + } + + // function taken from markings support in Flot + function extractRange(ranges, coord) { + var axis, from, to, key, axes = plot.getAxes(); + + for (var k in axes) { + axis = axes[k]; + if (axis.direction == coord) { + key = coord + axis.n + "axis"; + if (!ranges[key] && axis.n == 1) + key = coord + "axis"; // support x1axis as xaxis + if (ranges[key]) { + from = ranges[key].from; + to = ranges[key].to; + break; + } + } + } + + // backwards-compat stuff - to be removed in future + if (!ranges[key]) { + axis = coord == "x" ? plot.getXAxes()[0] : plot.getYAxes()[0]; + from = ranges[coord + "1"]; + to = ranges[coord + "2"]; + } + + // auto-reverse as an added bonus + if (from != null && to != null && from > to) { + var tmp = from; + from = to; + to = tmp; + } + + return { from: from, to: to, axis: axis }; + } + + function setSelection(ranges, preventEvent) { + var axis, range, o = plot.getOptions(); + + if (o.selection.mode == "y") { + selection.first.x = 0; + selection.second.x = plot.width(); + } + else { + range = extractRange(ranges, "x"); + + selection.first.x = range.axis.p2c(range.from); + selection.second.x = range.axis.p2c(range.to); + } + + if (o.selection.mode == "x") { + selection.first.y = 0; + selection.second.y = plot.height(); + } + else { + range = extractRange(ranges, "y"); + + selection.first.y = range.axis.p2c(range.from); + selection.second.y = range.axis.p2c(range.to); + } + + selection.show = true; + plot.triggerRedrawOverlay(); + if (!preventEvent && selectionIsSane()) + triggerSelectedEvent(); + } + + function selectionIsSane() { + var minSize = plot.getOptions().selection.minSize; + return Math.abs(selection.second.x - selection.first.x) >= minSize && + Math.abs(selection.second.y - selection.first.y) >= minSize; + } + + plot.clearSelection = clearSelection; + plot.setSelection = setSelection; + plot.getSelection = getSelection; + + plot.hooks.bindEvents.push(function(plot, eventHolder) { + var o = plot.getOptions(); + if (o.selection.mode != null) { + eventHolder.mousemove(onMouseMove); + eventHolder.mousedown(onMouseDown); + } + }); + + + plot.hooks.drawOverlay.push(function (plot, ctx) { + // draw selection + if (selection.show && selectionIsSane()) { + var plotOffset = plot.getPlotOffset(); + var o = plot.getOptions(); + + ctx.save(); + ctx.translate(plotOffset.left, plotOffset.top); + + var c = $.color.parse(o.selection.color); + + ctx.strokeStyle = c.scale('a', 0.8).toString(); + ctx.lineWidth = 1; + ctx.lineJoin = o.selection.shape; + ctx.fillStyle = c.scale('a', 0.4).toString(); + + var x = Math.min(selection.first.x, selection.second.x) + 0.5, + y = Math.min(selection.first.y, selection.second.y) + 0.5, + w = Math.abs(selection.second.x - selection.first.x) - 1, + h = Math.abs(selection.second.y - selection.first.y) - 1; + + ctx.fillRect(x, y, w, h); + ctx.strokeRect(x, y, w, h); + + ctx.restore(); + } + }); + + plot.hooks.shutdown.push(function (plot, eventHolder) { + eventHolder.unbind("mousemove", onMouseMove); + eventHolder.unbind("mousedown", onMouseDown); + + if (mouseUpHandler) + $(document).unbind("mouseup", mouseUpHandler); + }); + + } + + $.plot.plugins.push({ + init: init, + options: { + selection: { + mode: null, // one of null, "x", "y" or "xy" + color: "#e8cfac", + shape: "round", // one of "round", "miter", or "bevel" + minSize: 5 // minimum number of pixels + } + }, + name: 'selection', + version: '1.1' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.stack.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.stack.js new file mode 100644 index 0000000000000..0d91c0f3c0160 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.stack.js @@ -0,0 +1,188 @@ +/* Flot plugin for stacking data sets rather than overlaying them. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin assumes the data is sorted on x (or y if stacking horizontally). +For line charts, it is assumed that if a line has an undefined gap (from a +null point), then the line above it should have the same gap - insert zeros +instead of "null" if you want another behaviour. This also holds for the start +and end of the chart. Note that stacking a mix of positive and negative values +in most instances doesn't make sense (so it looks weird). + +Two or more series are stacked when their "stack" attribute is set to the same +key (which can be any number or string or just "true"). To specify the default +stack, you can set the stack option like this: + + series: { + stack: null/false, true, or a key (number/string) + } + +You can also specify it for a single series, like this: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + stack: true + }]) + +The stacking order is determined by the order of the data series in the array +(later series end up on top of the previous). + +Internally, the plugin modifies the datapoints in each series, adding an +offset to the y value. For line series, extra data points are inserted through +interpolation. If there's a second y value, it's also adjusted (e.g for bar +charts or filled areas). + +*/ + +(function ($) { + var options = { + series: { stack: null } // or number/string + }; + + function init(plot) { + function findMatchingSeries(s, allseries) { + var res = null; + for (var i = 0; i < allseries.length; ++i) { + if (s == allseries[i]) + break; + + if (allseries[i].stack == s.stack) + res = allseries[i]; + } + + return res; + } + + function stackData(plot, s, datapoints) { + if (s.stack == null || s.stack === false) + return; + + var other = findMatchingSeries(s, plot.getData()); + if (!other) + return; + + var ps = datapoints.pointsize, + points = datapoints.points, + otherps = other.datapoints.pointsize, + otherpoints = other.datapoints.points, + newpoints = [], + px, py, intery, qx, qy, bottom, + withlines = s.lines.show, + horizontal = s.bars.horizontal, + withbottom = ps > 2 && (horizontal ? datapoints.format[2].x : datapoints.format[2].y), + withsteps = withlines && s.lines.steps, + fromgap = true, + keyOffset = horizontal ? 1 : 0, + accumulateOffset = horizontal ? 0 : 1, + i = 0, j = 0, l, m; + + while (true) { + if (i >= points.length) + break; + + l = newpoints.length; + + if (points[i] == null) { + // copy gaps + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + i += ps; + } + else if (j >= otherpoints.length) { + // for lines, we can't use the rest of the points + if (!withlines) { + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + } + i += ps; + } + else if (otherpoints[j] == null) { + // oops, got a gap + for (m = 0; m < ps; ++m) + newpoints.push(null); + fromgap = true; + j += otherps; + } + else { + // cases where we actually got two points + px = points[i + keyOffset]; + py = points[i + accumulateOffset]; + qx = otherpoints[j + keyOffset]; + qy = otherpoints[j + accumulateOffset]; + bottom = 0; + + if (px == qx) { + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + + newpoints[l + accumulateOffset] += qy; + bottom = qy; + + i += ps; + j += otherps; + } + else if (px > qx) { + // we got past point below, might need to + // insert interpolated extra point + if (withlines && i > 0 && points[i - ps] != null) { + intery = py + (points[i - ps + accumulateOffset] - py) * (qx - px) / (points[i - ps + keyOffset] - px); + newpoints.push(qx); + newpoints.push(intery + qy); + for (m = 2; m < ps; ++m) + newpoints.push(points[i + m]); + bottom = qy; + } + + j += otherps; + } + else { // px < qx + if (fromgap && withlines) { + // if we come from a gap, we just skip this point + i += ps; + continue; + } + + for (m = 0; m < ps; ++m) + newpoints.push(points[i + m]); + + // we might be able to interpolate a point below, + // this can give us a better y + if (withlines && j > 0 && otherpoints[j - otherps] != null) + bottom = qy + (otherpoints[j - otherps + accumulateOffset] - qy) * (px - qx) / (otherpoints[j - otherps + keyOffset] - qx); + + newpoints[l + accumulateOffset] += bottom; + + i += ps; + } + + fromgap = false; + + if (l != newpoints.length && withbottom) + newpoints[l + 2] += bottom; + } + + // maintain the line steps invariant + if (withsteps && l != newpoints.length && l > 0 + && newpoints[l] != null + && newpoints[l] != newpoints[l - ps] + && newpoints[l + 1] != newpoints[l - ps + 1]) { + for (m = 0; m < ps; ++m) + newpoints[l + ps + m] = newpoints[l + m]; + newpoints[l + 1] = newpoints[l - ps + 1]; + } + } + + datapoints.points = newpoints; + } + + plot.hooks.processDatapoints.push(stackData); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'stack', + version: '1.2' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.symbol.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.symbol.js new file mode 100644 index 0000000000000..79f634971b6fa --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.symbol.js @@ -0,0 +1,71 @@ +/* Flot plugin that adds some extra symbols for plotting points. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The symbols are accessed as strings through the standard symbol options: + + series: { + points: { + symbol: "square" // or "diamond", "triangle", "cross" + } + } + +*/ + +(function ($) { + function processRawData(plot, series, datapoints) { + // we normalize the area of each symbol so it is approximately the + // same as a circle of the given radius + + var handlers = { + square: function (ctx, x, y, radius, shadow) { + // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2 + var size = radius * Math.sqrt(Math.PI) / 2; + ctx.rect(x - size, y - size, size + size, size + size); + }, + diamond: function (ctx, x, y, radius, shadow) { + // pi * r^2 = 2s^2 => s = r * sqrt(pi/2) + var size = radius * Math.sqrt(Math.PI / 2); + ctx.moveTo(x - size, y); + ctx.lineTo(x, y - size); + ctx.lineTo(x + size, y); + ctx.lineTo(x, y + size); + ctx.lineTo(x - size, y); + }, + triangle: function (ctx, x, y, radius, shadow) { + // pi * r^2 = 1/2 * s^2 * sin (pi / 3) => s = r * sqrt(2 * pi / sin(pi / 3)) + var size = radius * Math.sqrt(2 * Math.PI / Math.sin(Math.PI / 3)); + var height = size * Math.sin(Math.PI / 3); + ctx.moveTo(x - size/2, y + height/2); + ctx.lineTo(x + size/2, y + height/2); + if (!shadow) { + ctx.lineTo(x, y - height/2); + ctx.lineTo(x - size/2, y + height/2); + } + }, + cross: function (ctx, x, y, radius, shadow) { + // pi * r^2 = (2s)^2 => s = r * sqrt(pi)/2 + var size = radius * Math.sqrt(Math.PI) / 2; + ctx.moveTo(x - size, y - size); + ctx.lineTo(x + size, y + size); + ctx.moveTo(x - size, y + size); + ctx.lineTo(x + size, y - size); + } + }; + + var s = series.points.symbol; + if (handlers[s]) + series.points.symbol = handlers[s]; + } + + function init(plot) { + plot.hooks.processDatapoints.push(processRawData); + } + + $.plot.plugins.push({ + init: init, + name: 'symbols', + version: '1.0' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.threshold.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.threshold.js new file mode 100644 index 0000000000000..8c99c401d87e5 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.threshold.js @@ -0,0 +1,142 @@ +/* Flot plugin for thresholding data. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +The plugin supports these options: + + series: { + threshold: { + below: number + color: colorspec + } + } + +It can also be applied to a single series, like this: + + $.plot( $("#placeholder"), [{ + data: [ ... ], + threshold: { ... } + }]) + +An array can be passed for multiple thresholding, like this: + + threshold: [{ + below: number1 + color: color1 + },{ + below: number2 + color: color2 + }] + +These multiple threshold objects can be passed in any order since they are +sorted by the processing function. + +The data points below "below" are drawn with the specified color. This makes +it easy to mark points below 0, e.g. for budget data. + +Internally, the plugin works by splitting the data into two series, above and +below the threshold. The extra series below the threshold will have its label +cleared and the special "originSeries" attribute set to the original series. +You may need to check for this in hover events. + +*/ + +(function ($) { + var options = { + series: { threshold: null } // or { below: number, color: color spec} + }; + + function init(plot) { + function thresholdData(plot, s, datapoints, below, color) { + var ps = datapoints.pointsize, i, x, y, p, prevp, + thresholded = $.extend({}, s); // note: shallow copy + + thresholded.datapoints = { points: [], pointsize: ps, format: datapoints.format }; + thresholded.label = null; + thresholded.color = color; + thresholded.threshold = null; + thresholded.originSeries = s; + thresholded.data = []; + + var origpoints = datapoints.points, + addCrossingPoints = s.lines.show; + + var threspoints = []; + var newpoints = []; + var m; + + for (i = 0; i < origpoints.length; i += ps) { + x = origpoints[i]; + y = origpoints[i + 1]; + + prevp = p; + if (y < below) + p = threspoints; + else + p = newpoints; + + if (addCrossingPoints && prevp != p && x != null + && i > 0 && origpoints[i - ps] != null) { + var interx = x + (below - y) * (x - origpoints[i - ps]) / (y - origpoints[i - ps + 1]); + prevp.push(interx); + prevp.push(below); + for (m = 2; m < ps; ++m) + prevp.push(origpoints[i + m]); + + p.push(null); // start new segment + p.push(null); + for (m = 2; m < ps; ++m) + p.push(origpoints[i + m]); + p.push(interx); + p.push(below); + for (m = 2; m < ps; ++m) + p.push(origpoints[i + m]); + } + + p.push(x); + p.push(y); + for (m = 2; m < ps; ++m) + p.push(origpoints[i + m]); + } + + datapoints.points = newpoints; + thresholded.datapoints.points = threspoints; + + if (thresholded.datapoints.points.length > 0) { + var origIndex = $.inArray(s, plot.getData()); + // Insert newly-generated series right after original one (to prevent it from becoming top-most) + plot.getData().splice(origIndex + 1, 0, thresholded); + } + + // FIXME: there are probably some edge cases left in bars + } + + function processThresholds(plot, s, datapoints) { + if (!s.threshold) + return; + + if (s.threshold instanceof Array) { + s.threshold.sort(function(a, b) { + return a.below - b.below; + }); + + $(s.threshold).each(function(i, th) { + thresholdData(plot, s, datapoints, th.below, th.color); + }); + } + else { + thresholdData(plot, s, datapoints, s.threshold.below, s.threshold.color); + } + } + + plot.hooks.processDatapoints.push(processThresholds); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'threshold', + version: '1.2' + }); +})(jQuery); diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.time.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.time.js new file mode 100644 index 0000000000000..991e87d364e8a --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/flot-charts/jquery.flot.time.js @@ -0,0 +1,473 @@ +/* Pretty handling of time axes. + +Copyright (c) 2007-2014 IOLA and Ole Laursen. +Licensed under the MIT license. + +Set axis.mode to "time" to enable. See the section "Time series data" in +API.txt for details. + +*/ + +import { i18n } from '@kbn/i18n'; + +(function($) { + + var options = { + xaxis: { + timezone: null, // "browser" for local to the client or timezone for timezone-js + timeformat: null, // format string to use + twelveHourClock: false, // 12 or 24 time in time mode + monthNames: null // list of names of months + } + }; + + // round to nearby lower multiple of base + + function floorInBase(n, base) { + return base * Math.floor(n / base); + } + + // Returns a string with the date d formatted according to fmt. + // A subset of the Open Group's strftime format is supported. + + function formatDate(d, fmt, monthNames, dayNames) { + + if (typeof d.strftime == "function") { + return d.strftime(fmt); + } + + var leftPad = function(n, pad) { + n = "" + n; + pad = "" + (pad == null ? "0" : pad); + return n.length == 1 ? pad + n : n; + }; + + var r = []; + var escape = false; + var hours = d.getHours(); + var isAM = hours < 12; + + if (monthNames == null) { + monthNames = [ + i18n.translate('xpack.monitoring.janLabel', { + defaultMessage: 'Jan', + }), i18n.translate('xpack.monitoring.febLabel', { + defaultMessage: 'Feb', + }), i18n.translate('xpack.monitoring.marLabel', { + defaultMessage: 'Mar', + }), i18n.translate('xpack.monitoring.aprLabel', { + defaultMessage: 'Apr', + }), i18n.translate('xpack.monitoring.mayLabel', { + defaultMessage: 'May', + }), i18n.translate('xpack.monitoring.junLabel', { + defaultMessage: 'Jun', + }), i18n.translate('xpack.monitoring.julLabel', { + defaultMessage: 'Jul', + }), i18n.translate('xpack.monitoring.augLabel', { + defaultMessage: 'Aug', + }), i18n.translate('xpack.monitoring.sepLabel', { + defaultMessage: 'Sep', + }), i18n.translate('xpack.monitoring.octLabel', { + defaultMessage: 'Oct', + }), i18n.translate('xpack.monitoring.novLabel', { + defaultMessage: 'Nov', + }), i18n.translate('xpack.monitoring.decLabel', { + defaultMessage: 'Dec', + })]; + } + + if (dayNames == null) { + dayNames = [i18n.translate('xpack.monitoring.sunLabel', { + defaultMessage: 'Sun', + }), i18n.translate('xpack.monitoring.monLabel', { + defaultMessage: 'Mon', + }), i18n.translate('xpack.monitoring.tueLabel', { + defaultMessage: 'Tue', + }), i18n.translate('xpack.monitoring.wedLabel', { + defaultMessage: 'Wed', + }), i18n.translate('xpack.monitoring.thuLabel', { + defaultMessage: 'Thu', + }), i18n.translate('xpack.monitoring.friLabel', { + defaultMessage: 'Fri', + }), i18n.translate('xpack.monitoring.satLabel', { + defaultMessage: 'Sat', + })]; + } + + var hours12; + + if (hours > 12) { + hours12 = hours - 12; + } else if (hours == 0) { + hours12 = 12; + } else { + hours12 = hours; + } + + for (var i = 0; i < fmt.length; ++i) { + + var c = fmt.charAt(i); + + if (escape) { + switch (c) { + case 'a': c = "" + dayNames[d.getDay()]; break; + case 'b': c = "" + monthNames[d.getMonth()]; break; + case 'd': c = leftPad(d.getDate()); break; + case 'e': c = leftPad(d.getDate(), " "); break; + case 'h': // For back-compat with 0.7; remove in 1.0 + case 'H': c = leftPad(hours); break; + case 'I': c = leftPad(hours12); break; + case 'l': c = leftPad(hours12, " "); break; + case 'm': c = leftPad(d.getMonth() + 1); break; + case 'M': c = leftPad(d.getMinutes()); break; + // quarters not in Open Group's strftime specification + case 'q': + c = "" + (Math.floor(d.getMonth() / 3) + 1); break; + case 'S': c = leftPad(d.getSeconds()); break; + case 'y': c = leftPad(d.getFullYear() % 100); break; + case 'Y': c = "" + d.getFullYear(); break; + case 'p': c = (isAM) ? ("" + "am") : ("" + "pm"); break; + case 'P': c = (isAM) ? ("" + "AM") : ("" + "PM"); break; + case 'w': c = "" + d.getDay(); break; + } + r.push(c); + escape = false; + } else { + if (c == "%") { + escape = true; + } else { + r.push(c); + } + } + } + + return r.join(""); + } + + // To have a consistent view of time-based data independent of which time + // zone the client happens to be in we need a date-like object independent + // of time zones. This is done through a wrapper that only calls the UTC + // versions of the accessor methods. + + function makeUtcWrapper(d) { + + function addProxyMethod(sourceObj, sourceMethod, targetObj, targetMethod) { + sourceObj[sourceMethod] = function() { + return targetObj[targetMethod].apply(targetObj, arguments); + }; + }; + + var utc = { + date: d + }; + + // support strftime, if found + + if (d.strftime != undefined) { + addProxyMethod(utc, "strftime", d, "strftime"); + } + + addProxyMethod(utc, "getTime", d, "getTime"); + addProxyMethod(utc, "setTime", d, "setTime"); + + var props = ["Date", "Day", "FullYear", "Hours", "Milliseconds", "Minutes", "Month", "Seconds"]; + + for (var p = 0; p < props.length; p++) { + addProxyMethod(utc, "get" + props[p], d, "getUTC" + props[p]); + addProxyMethod(utc, "set" + props[p], d, "setUTC" + props[p]); + } + + return utc; + }; + + // select time zone strategy. This returns a date-like object tied to the + // desired timezone + + function dateGenerator(ts, opts) { + if (opts.timezone == "browser") { + return new Date(ts); + } else if (!opts.timezone || opts.timezone == "utc") { + return makeUtcWrapper(new Date(ts)); + } else if (typeof timezoneJS != "undefined" && typeof timezoneJS.Date != "undefined") { + var d = new timezoneJS.Date(); + // timezone-js is fickle, so be sure to set the time zone before + // setting the time. + d.setTimezone(opts.timezone); + d.setTime(ts); + return d; + } else { + return makeUtcWrapper(new Date(ts)); + } + } + + // map of app. size of time units in milliseconds + + var timeUnitSize = { + "second": 1000, + "minute": 60 * 1000, + "hour": 60 * 60 * 1000, + "day": 24 * 60 * 60 * 1000, + "month": 30 * 24 * 60 * 60 * 1000, + "quarter": 3 * 30 * 24 * 60 * 60 * 1000, + "year": 365.2425 * 24 * 60 * 60 * 1000 + }; + + // the allowed tick sizes, after 1 year we use + // an integer algorithm + + var baseSpec = [ + [1, "second"], [2, "second"], [5, "second"], [10, "second"], + [30, "second"], + [1, "minute"], [2, "minute"], [5, "minute"], [10, "minute"], + [30, "minute"], + [1, "hour"], [2, "hour"], [4, "hour"], + [8, "hour"], [12, "hour"], + [1, "day"], [2, "day"], [3, "day"], + [0.25, "month"], [0.5, "month"], [1, "month"], + [2, "month"] + ]; + + // we don't know which variant(s) we'll need yet, but generating both is + // cheap + + var specMonths = baseSpec.concat([[3, "month"], [6, "month"], + [1, "year"]]); + var specQuarters = baseSpec.concat([[1, "quarter"], [2, "quarter"], + [1, "year"]]); + + function init(plot) { + plot.hooks.processOptions.push(function (plot, options) { + $.each(plot.getAxes(), function(axisName, axis) { + + var opts = axis.options; + + if (opts.mode == "time") { + axis.tickGenerator = function(axis) { + + var ticks = []; + var d = dateGenerator(axis.min, opts); + var minSize = 0; + + // make quarter use a possibility if quarters are + // mentioned in either of these options + + var spec = (opts.tickSize && opts.tickSize[1] === + "quarter") || + (opts.minTickSize && opts.minTickSize[1] === + "quarter") ? specQuarters : specMonths; + + if (opts.minTickSize != null) { + if (typeof opts.tickSize == "number") { + minSize = opts.tickSize; + } else { + minSize = opts.minTickSize[0] * timeUnitSize[opts.minTickSize[1]]; + } + } + + for (var i = 0; i < spec.length - 1; ++i) { + if (axis.delta < (spec[i][0] * timeUnitSize[spec[i][1]] + + spec[i + 1][0] * timeUnitSize[spec[i + 1][1]]) / 2 + && spec[i][0] * timeUnitSize[spec[i][1]] >= minSize) { + break; + } + } + + var size = spec[i][0]; + var unit = spec[i][1]; + + // special-case the possibility of several years + + if (unit == "year") { + + // if given a minTickSize in years, just use it, + // ensuring that it's an integer + + if (opts.minTickSize != null && opts.minTickSize[1] == "year") { + size = Math.floor(opts.minTickSize[0]); + } else { + + var magn = Math.pow(10, Math.floor(Math.log(axis.delta / timeUnitSize.year) / Math.LN10)); + var norm = (axis.delta / timeUnitSize.year) / magn; + + if (norm < 1.5) { + size = 1; + } else if (norm < 3) { + size = 2; + } else if (norm < 7.5) { + size = 5; + } else { + size = 10; + } + + size *= magn; + } + + // minimum size for years is 1 + + if (size < 1) { + size = 1; + } + } + + axis.tickSize = opts.tickSize || [size, unit]; + var tickSize = axis.tickSize[0]; + unit = axis.tickSize[1]; + + var step = tickSize * timeUnitSize[unit]; + + if (unit == "second") { + d.setSeconds(floorInBase(d.getSeconds(), tickSize)); + } else if (unit == "minute") { + d.setMinutes(floorInBase(d.getMinutes(), tickSize)); + } else if (unit == "hour") { + d.setHours(floorInBase(d.getHours(), tickSize)); + } else if (unit == "month") { + d.setMonth(floorInBase(d.getMonth(), tickSize)); + } else if (unit == "quarter") { + d.setMonth(3 * floorInBase(d.getMonth() / 3, + tickSize)); + } else if (unit == "year") { + d.setFullYear(floorInBase(d.getFullYear(), tickSize)); + } + + // reset smaller components + + d.setMilliseconds(0); + + if (step >= timeUnitSize.minute) { + d.setSeconds(0); + } + if (step >= timeUnitSize.hour) { + d.setMinutes(0); + } + if (step >= timeUnitSize.day) { + d.setHours(0); + } + if (step >= timeUnitSize.day * 4) { + d.setDate(1); + } + if (step >= timeUnitSize.month * 2) { + d.setMonth(floorInBase(d.getMonth(), 3)); + } + if (step >= timeUnitSize.quarter * 2) { + d.setMonth(floorInBase(d.getMonth(), 6)); + } + if (step >= timeUnitSize.year) { + d.setMonth(0); + } + + var carry = 0; + var v = Number.NaN; + var prev; + + do { + + prev = v; + v = d.getTime(); + ticks.push(v); + + if (unit == "month" || unit == "quarter") { + if (tickSize < 1) { + + // a bit complicated - we'll divide the + // month/quarter up but we need to take + // care of fractions so we don't end up in + // the middle of a day + + d.setDate(1); + var start = d.getTime(); + d.setMonth(d.getMonth() + + (unit == "quarter" ? 3 : 1)); + var end = d.getTime(); + d.setTime(v + carry * timeUnitSize.hour + (end - start) * tickSize); + carry = d.getHours(); + d.setHours(0); + } else { + d.setMonth(d.getMonth() + + tickSize * (unit == "quarter" ? 3 : 1)); + } + } else if (unit == "year") { + d.setFullYear(d.getFullYear() + tickSize); + } else { + d.setTime(v + step); + } + } while (v < axis.max && v != prev); + + return ticks; + }; + + axis.tickFormatter = function (v, axis) { + + var d = dateGenerator(v, axis.options); + + // first check global format + + if (opts.timeformat != null) { + return formatDate(d, opts.timeformat, opts.monthNames, opts.dayNames); + } + + // possibly use quarters if quarters are mentioned in + // any of these places + + var useQuarters = (axis.options.tickSize && + axis.options.tickSize[1] == "quarter") || + (axis.options.minTickSize && + axis.options.minTickSize[1] == "quarter"); + + var t = axis.tickSize[0] * timeUnitSize[axis.tickSize[1]]; + var span = axis.max - axis.min; + var suffix = (opts.twelveHourClock) ? " %p" : ""; + var hourCode = (opts.twelveHourClock) ? "%I" : "%H"; + var fmt; + + if (t < timeUnitSize.minute) { + fmt = hourCode + ":%M:%S" + suffix; + } else if (t < timeUnitSize.day) { + if (span < 2 * timeUnitSize.day) { + fmt = hourCode + ":%M" + suffix; + } else { + fmt = "%b %d " + hourCode + ":%M" + suffix; + } + } else if (t < timeUnitSize.month) { + fmt = "%b %d"; + } else if ((useQuarters && t < timeUnitSize.quarter) || + (!useQuarters && t < timeUnitSize.year)) { + if (span < timeUnitSize.year) { + fmt = "%b"; + } else { + fmt = "%b %Y"; + } + } else if (useQuarters && t < timeUnitSize.year) { + if (span < timeUnitSize.year) { + fmt = "Q%q"; + } else { + fmt = "Q%q %Y"; + } + } else { + fmt = "%Y"; + } + + var rt = formatDate(d, fmt, opts.monthNames, opts.dayNames); + + return rt; + }; + } + }); + }); + } + + $.plot.plugins.push({ + init: init, + options: options, + name: 'time', + version: '1.0' + }); + + // Time-axis support used to be in Flot core, which exposed the + // formatDate function on the plot object. Various plugins depend + // on the function, so we need to re-expose it here. + + $.plot.formatDate = formatDate; + $.plot.dateGenerator = dateGenerator; + +})(jQuery); diff --git a/x-pack/legacy/plugins/monitoring/common/index.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/index.js similarity index 76% rename from x-pack/legacy/plugins/monitoring/common/index.js rename to x-pack/plugins/monitoring/public/lib/jquery_flot/index.js index 183396f8f0d72..abf060aca8c08 100644 --- a/x-pack/legacy/plugins/monitoring/common/index.js +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/index.js @@ -4,4 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export { formatTimestampToDuration } from './format_timestamp_to_duration'; +export { default } from './jquery_flot'; diff --git a/x-pack/plugins/monitoring/public/lib/jquery_flot/jquery_flot.js b/x-pack/plugins/monitoring/public/lib/jquery_flot/jquery_flot.js new file mode 100644 index 0000000000000..28a4d5f56df15 --- /dev/null +++ b/x-pack/plugins/monitoring/public/lib/jquery_flot/jquery_flot.js @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 'jquery'; +if (window) { + window.jQuery = $; +} +import './flot-charts/jquery.flot'; + +// load flot plugins +// avoid the `canvas` plugin, it causes blurry fonts +import './flot-charts/jquery.flot.time'; +import './flot-charts/jquery.flot.crosshair'; +import './flot-charts/jquery.flot.selection'; + +export default $; diff --git a/x-pack/legacy/plugins/monitoring/public/lib/logstash/__tests__/pipelines.js b/x-pack/plugins/monitoring/public/lib/logstash/__tests__/pipelines.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/lib/logstash/__tests__/pipelines.js rename to x-pack/plugins/monitoring/public/lib/logstash/__tests__/pipelines.js diff --git a/x-pack/legacy/plugins/monitoring/public/lib/logstash/pipelines.js b/x-pack/plugins/monitoring/public/lib/logstash/pipelines.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/lib/logstash/pipelines.js rename to x-pack/plugins/monitoring/public/lib/logstash/pipelines.js diff --git a/x-pack/legacy/plugins/monitoring/public/lib/route_init.js b/x-pack/plugins/monitoring/public/lib/route_init.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/lib/route_init.js rename to x-pack/plugins/monitoring/public/lib/route_init.js index 97a55303dae67..2c928334ef63e 100644 --- a/x-pack/legacy/plugins/monitoring/public/lib/route_init.js +++ b/x-pack/plugins/monitoring/public/lib/route_init.js @@ -5,7 +5,7 @@ */ import _ from 'lodash'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; +import { ajaxErrorHandlersProvider } from './ajax_error_handler'; import { isInSetupMode } from './setup_mode'; import { getClusterFromClusters } from './get_cluster_from_clusters'; diff --git a/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.test.js b/x-pack/plugins/monitoring/public/lib/setup_mode.test.js similarity index 72% rename from x-pack/legacy/plugins/monitoring/public/lib/setup_mode.test.js rename to x-pack/plugins/monitoring/public/lib/setup_mode.test.js index 765909f0aa251..c54c29df09685 100644 --- a/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.test.js +++ b/x-pack/plugins/monitoring/public/lib/setup_mode.test.js @@ -4,12 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - coreMock, - overlayServiceMock, - notificationServiceMock, -} from '../../../../../../src/core/public/mocks'; - let toggleSetupMode; let initSetupModeState; let getSetupModeState; @@ -26,6 +20,14 @@ jest.mock('react-dom', () => ({ render: jest.fn(), })); +jest.mock('../legacy_shims', () => { + return { + Legacy: { + shims: { getAngularInjector: () => ({ get: () => ({ get: () => 'utc' }) }) }, + }, + }; +}); + let data = {}; const injectorModulesMock = { @@ -61,70 +63,10 @@ function waitForSetupModeData(action) { process.nextTick(action); } -function mockFilterManager() { - let subscriber; - let filters = []; - return { - getUpdates$: () => ({ - subscribe: ({ next }) => { - subscriber = next; - return jest.fn(); - }, - }), - setFilters: newFilters => { - filters = newFilters; - subscriber(); - }, - getFilters: () => filters, - removeAll: () => { - filters = []; - subscriber(); - }, - }; -} - -const pluginData = { - query: { - filterManager: mockFilterManager(), - timefilter: { - timefilter: { - getTime: jest.fn(() => ({ from: 'now-1h', to: 'now' })), - setTime: jest.fn(), - }, - }, - }, -}; - -function setModulesAndMocks(isOnCloud = false) { +function setModulesAndMocks() { jest.clearAllMocks().resetModules(); injectorModulesMock.globalState.inSetupMode = false; - jest.doMock('ui/new_platform', () => ({ - npSetup: { - plugins: { - cloud: isOnCloud ? { cloudId: 'test', isCloudEnabled: true } : {}, - uiActions: { - registerAction: jest.fn(), - attachAction: jest.fn(), - }, - }, - core: { - ...coreMock.createSetup(), - notifications: notificationServiceMock.createStartContract(), - }, - }, - npStart: { - plugins: { - data: pluginData, - navigation: { ui: {} }, - }, - core: { - ...coreMock.createStart(), - overlays: overlayServiceMock.createStartContract(), - }, - }, - })); - const setupMode = require('./setup_mode'); toggleSetupMode = setupMode.toggleSetupMode; initSetupModeState = setupMode.initSetupModeState; @@ -179,37 +121,15 @@ describe('setup_mode', () => { data = {}; }); - it('should not fetch data if on cloud', async done => { - const addDanger = jest.fn(); - data = { - _meta: { - hasPermissions: true, - }, - }; - jest.doMock('ui/notify', () => ({ - toastNotifications: { - addDanger, - }, - })); - setModulesAndMocks(true); - initSetupModeState(angularStateMock.scope, angularStateMock.injector); - await toggleSetupMode(true); - waitForSetupModeData(() => { - const state = getSetupModeState(); - expect(state.enabled).toBe(false); - expect(addDanger).toHaveBeenCalledWith({ - title: 'Setup mode is not available', - text: 'This feature is not available on cloud.', - }); - done(); - }); - }); - it('should not fetch data if the user does not have sufficient permissions', async done => { const addDanger = jest.fn(); - jest.doMock('ui/notify', () => ({ - toastNotifications: { - addDanger, + jest.doMock('../legacy_shims', () => ({ + Legacy: { + shims: { + toastNotifications: { + addDanger, + }, + }, }, })); data = { diff --git a/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.tsx b/x-pack/plugins/monitoring/public/lib/setup_mode.tsx similarity index 82% rename from x-pack/legacy/plugins/monitoring/public/lib/setup_mode.tsx rename to x-pack/plugins/monitoring/public/lib/setup_mode.tsx index 7b081b79d6acd..5afb382b7cda8 100644 --- a/x-pack/legacy/plugins/monitoring/public/lib/setup_mode.tsx +++ b/x-pack/plugins/monitoring/public/lib/setup_mode.tsx @@ -7,19 +7,11 @@ import React from 'react'; import { render } from 'react-dom'; import { get, contains } from 'lodash'; -import { toastNotifications } from 'ui/notify'; import { i18n } from '@kbn/i18n'; -import { npSetup } from 'ui/new_platform'; -import { PluginsSetup } from 'ui/new_platform/new_platform'; -import chrome from '../np_imports/ui/chrome'; -import { CloudSetup } from '../../../../../plugins/cloud/public'; +import { Legacy } from '../legacy_shims'; import { ajaxErrorHandlersProvider } from './ajax_error_handler'; import { SetupModeEnterButton } from '../components/setup_mode/enter_button'; -interface PluginsSetupWithCloud extends PluginsSetup { - cloud: CloudSetup; -} - function isOnPage(hash: string) { return contains(window.location.hash, hash); } @@ -46,12 +38,12 @@ const checkAngularState = () => { interface ISetupModeState { enabled: boolean; data: any; - callbacks: Function[]; + callback?: (() => void) | null; } const setupModeState: ISetupModeState = { enabled: false, data: null, - callbacks: [], + callback: null, }; export const getSetupModeState = () => setupModeState; @@ -93,18 +85,13 @@ export const fetchCollectionData = async (uuid?: string, fetchWithoutClusterUuid } }; -const notifySetupModeDataChange = (oldData?: any) => { - setupModeState.callbacks.forEach((cb: Function) => cb(oldData)); -}; +const notifySetupModeDataChange = () => setupModeState.callback && setupModeState.callback(); export const updateSetupModeData = async (uuid?: string, fetchWithoutClusterUuid = false) => { - const oldData = setupModeState.data; const data = await fetchCollectionData(uuid, fetchWithoutClusterUuid); setupModeState.data = data; - const { cloud } = npSetup.plugins as PluginsSetupWithCloud; - const isCloudEnabled = !!(cloud && cloud.isCloudEnabled); const hasPermissions = get(data, '_meta.hasPermissions', false); - if (isCloudEnabled || !hasPermissions) { + if (Legacy.shims.isCloud || !hasPermissions) { let text: string = ''; if (!hasPermissions) { text = i18n.translate('xpack.monitoring.setupMode.notAvailablePermissions', { @@ -117,7 +104,7 @@ export const updateSetupModeData = async (uuid?: string, fetchWithoutClusterUuid } angularState.scope.$evalAsync(() => { - toastNotifications.addDanger({ + Legacy.shims.toastNotifications.addDanger({ title: i18n.translate('xpack.monitoring.setupMode.notAvailableTitle', { defaultMessage: 'Setup mode is not available', }), @@ -126,7 +113,7 @@ export const updateSetupModeData = async (uuid?: string, fetchWithoutClusterUuid }); return toggleSetupMode(false); // eslint-disable-line no-use-before-define } - notifySetupModeDataChange(oldData); + notifySetupModeDataChange(); const globalState = angularState.injector.get('globalState'); const clusterUuid = globalState.cluster_uuid; @@ -182,9 +169,7 @@ export const setSetupModeMenuItem = () => { } const globalState = angularState.injector.get('globalState'); - const { cloud } = npSetup.plugins as PluginsSetupWithCloud; - const isCloudEnabled = !!(cloud && cloud.isCloudEnabled); - const enabled = !globalState.inSetupMode && !isCloudEnabled; + const enabled = !globalState.inSetupMode && !Legacy.shims.isCloud; render( , @@ -192,13 +177,13 @@ export const setSetupModeMenuItem = () => { ); }; -export const addSetupModeCallback = (callback: Function) => setupModeState.callbacks.push(callback); +export const addSetupModeCallback = (callback: () => void) => (setupModeState.callback = callback); -export const initSetupModeState = async ($scope: any, $injector: any, callback?: Function) => { +export const initSetupModeState = async ($scope: any, $injector: any, callback?: () => void) => { angularState.scope = $scope; angularState.injector = $injector; if (callback) { - setupModeState.callbacks.push(callback); + setupModeState.callback = callback; } const globalState = $injector.get('globalState'); @@ -212,7 +197,7 @@ export const isInSetupMode = () => { return true; } - const $injector = angularState.injector || chrome.dangerouslyGetActiveInjector(); + const $injector = angularState.injector || Legacy.shims.getAngularInjector(); const globalState = $injector.get('globalState'); return globalState.inSetupMode; }; diff --git a/x-pack/plugins/monitoring/public/plugin.ts b/x-pack/plugins/monitoring/public/plugin.ts new file mode 100644 index 0000000000000..63f0c46c14096 --- /dev/null +++ b/x-pack/plugins/monitoring/public/plugin.ts @@ -0,0 +1,147 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { + App, + AppMountParameters, + CoreSetup, + CoreStart, + Plugin, + PluginInitializerContext, +} from 'kibana/public'; +import { + FeatureCatalogueCategory, + HomePublicPluginSetup, +} from '../../../../src/plugins/home/public'; +import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; +import { MonitoringPluginDependencies, MonitoringConfig } from './types'; +import { + MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS, + KIBANA_ALERTING_ENABLED, +} from '../common/constants'; + +export class MonitoringPlugin + implements Plugin { + constructor(private initializerContext: PluginInitializerContext) {} + + public setup( + core: CoreSetup, + plugins: object & { home?: HomePublicPluginSetup; cloud?: { isCloudEnabled: boolean } } + ) { + const { home } = plugins; + const id = 'monitoring'; + const icon = 'monitoringApp'; + const title = i18n.translate('xpack.monitoring.stackMonitoringTitle', { + defaultMessage: 'Stack Monitoring', + }); + const monitoring = this.initializerContext.config.get(); + + if (!monitoring.ui.enabled || !monitoring.enabled) { + return false; + } + + if (home) { + home.featureCatalogue.register({ + id, + title, + icon, + path: '/app/monitoring', + showOnHomePage: true, + category: FeatureCatalogueCategory.ADMIN, + description: i18n.translate('xpack.monitoring.monitoringDescription', { + defaultMessage: 'Track the real-time health and performance of your Elastic Stack.', + }), + }); + } + + const app: App = { + id, + title, + order: 9002, + euiIconType: icon, + category: DEFAULT_APP_CATEGORIES.management, + mount: async (params: AppMountParameters) => { + const [coreStart, pluginsStart] = await core.getStartServices(); + const { AngularApp } = await import('./angular'); + const deps: MonitoringPluginDependencies = { + navigation: pluginsStart.navigation, + element: params.element, + core: coreStart, + data: pluginsStart.data, + isCloud: Boolean(plugins.cloud?.isCloudEnabled), + pluginInitializerContext: this.initializerContext, + externalConfig: this.getExternalConfig(), + }; + + this.setInitialTimefilter(deps); + this.overrideAlertingEmailDefaults(deps); + + const monitoringApp = new AngularApp(deps); + const removeHistoryListener = params.history.listen(location => { + if (location.pathname === '' && location.hash === '') { + monitoringApp.applyScope(); + } + }); + + return () => { + removeHistoryListener(); + monitoringApp.destroy(); + }; + }, + }; + + core.application.register(app); + return true; + } + + public start(core: CoreStart, plugins: any) {} + + public stop() {} + + private setInitialTimefilter({ core: coreContext, data }: MonitoringPluginDependencies) { + const { timefilter } = data.query.timefilter; + const { uiSettings } = coreContext; + const refreshInterval = { value: 10000, pause: false }; + const time = { from: 'now-1h', to: 'now' }; + timefilter.setRefreshInterval(refreshInterval); + timefilter.setTime(time); + uiSettings.overrideLocalDefault( + 'timepicker:refreshIntervalDefaults', + JSON.stringify(refreshInterval) + ); + uiSettings.overrideLocalDefault('timepicker:timeDefaults', JSON.stringify(time)); + } + + private overrideAlertingEmailDefaults({ core: coreContext }: MonitoringPluginDependencies) { + const { uiSettings } = coreContext; + if (KIBANA_ALERTING_ENABLED && !uiSettings.get(MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS)) { + uiSettings.overrideLocalDefault( + MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS, + JSON.stringify({ + name: i18n.translate('xpack.monitoring.alertingEmailAddress.name', { + defaultMessage: 'Alerting email address', + }), + value: '', + description: i18n.translate('xpack.monitoring.alertingEmailAddress.description', { + defaultMessage: `The default email address to receive alerts from Stack Monitoring`, + }), + category: ['monitoring'], + }) + ); + } + } + + private getExternalConfig() { + const monitoring = this.initializerContext.config.get(); + return [ + ['minIntervalSeconds', monitoring.ui.min_interval_seconds], + ['showLicenseExpiration', monitoring.ui.show_license_expiration], + ['showCgroupMetricsElasticsearch', monitoring.ui.container.elasticsearch.enabled], + ['showCgroupMetricsLogstash', monitoring.ui.container.logstash.enabled], + ]; + } +} diff --git a/x-pack/legacy/plugins/monitoring/public/services/__tests__/breadcrumbs.js b/x-pack/plugins/monitoring/public/services/__tests__/breadcrumbs.js similarity index 96% rename from x-pack/legacy/plugins/monitoring/public/services/__tests__/breadcrumbs.js rename to x-pack/plugins/monitoring/public/services/__tests__/breadcrumbs.js index e5b2e01373340..d4493d4d39e58 100644 --- a/x-pack/legacy/plugins/monitoring/public/services/__tests__/breadcrumbs.js +++ b/x-pack/plugins/monitoring/public/services/__tests__/breadcrumbs.js @@ -5,8 +5,8 @@ */ import expect from '@kbn/expect'; -import { breadcrumbsProvider } from '../breadcrumbs_provider'; -import { MonitoringMainController } from 'plugins/monitoring/directives/main'; +import { breadcrumbsProvider } from '../breadcrumbs'; +import { MonitoringMainController } from '../../directives/main'; describe('Monitoring Breadcrumbs Service', () => { it('in Cluster Alerts', () => { diff --git a/x-pack/legacy/plugins/monitoring/public/services/__tests__/executor_provider.js b/x-pack/plugins/monitoring/public/services/__tests__/executor.js similarity index 87% rename from x-pack/legacy/plugins/monitoring/public/services/__tests__/executor_provider.js rename to x-pack/plugins/monitoring/public/services/__tests__/executor.js index 2c4d49716406c..1113f9e32bdc7 100644 --- a/x-pack/legacy/plugins/monitoring/public/services/__tests__/executor_provider.js +++ b/x-pack/plugins/monitoring/public/services/__tests__/executor.js @@ -7,14 +7,22 @@ import ngMock from 'ng_mock'; import expect from '@kbn/expect'; import sinon from 'sinon'; -import { executorProvider } from '../executor_provider'; +import { executorProvider } from '../executor'; import Bluebird from 'bluebird'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { Legacy } from '../../legacy_shims'; +import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks'; describe('$executor service', () => { let scope; let executor; let $timeout; + let timefilter; + + beforeEach(() => { + const data = dataPluginMock.createStartContract(); + Legacy._shims = { timefilter }; + timefilter = data.query.timefilter.timefilter; + }); beforeEach(ngMock.module('kibana')); diff --git a/x-pack/legacy/plugins/monitoring/public/services/breadcrumbs_provider.js b/x-pack/plugins/monitoring/public/services/breadcrumbs.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/services/breadcrumbs_provider.js rename to x-pack/plugins/monitoring/public/services/breadcrumbs.js index 7917606a5bc8e..f2867180e9c4c 100644 --- a/x-pack/legacy/plugins/monitoring/public/services/breadcrumbs_provider.js +++ b/x-pack/plugins/monitoring/public/services/breadcrumbs.js @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import chrome from 'plugins/monitoring/np_imports/ui/chrome'; +import { Legacy } from '../legacy_shims'; import { i18n } from '@kbn/i18n'; // Helper for making objects to use in a link element @@ -195,7 +195,7 @@ export function breadcrumbsProvider() { breadcrumbs = breadcrumbs.concat(getApmBreadcrumbs(mainInstance)); } - chrome.breadcrumbs.set( + Legacy.shims.breadcrumbs.set( breadcrumbs.map(b => ({ text: b.label, href: b.url, diff --git a/x-pack/legacy/plugins/monitoring/public/services/clusters.js b/x-pack/plugins/monitoring/public/services/clusters.js similarity index 77% rename from x-pack/legacy/plugins/monitoring/public/services/clusters.js rename to x-pack/plugins/monitoring/public/services/clusters.js index 40d6fa59228f8..dfa538b458054 100644 --- a/x-pack/legacy/plugins/monitoring/public/services/clusters.js +++ b/x-pack/plugins/monitoring/public/services/clusters.js @@ -4,9 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../lib/ajax_error_handler'; +import { Legacy } from '../legacy_shims'; import { STANDALONE_CLUSTER_CLUSTER_UUID } from '../../common/constants'; function formatClusters(clusters) { @@ -20,10 +19,9 @@ function formatCluster(cluster) { return cluster; } -const uiModule = uiModules.get('monitoring/clusters'); -uiModule.service('monitoringClusters', $injector => { +export function monitoringClustersProvider($injector) { return (clusterUuid, ccs, codePaths) => { - const { min, max } = timefilter.getBounds(); + const { min, max } = Legacy.shims.timefilter.getBounds(); // append clusterUuid if the parameter is given let url = '../api/monitoring/v1/clusters'; @@ -51,4 +49,4 @@ uiModule.service('monitoringClusters', $injector => { return ajaxErrorHandlers(err); }); }; -}); +} diff --git a/x-pack/legacy/plugins/monitoring/public/services/executor_provider.js b/x-pack/plugins/monitoring/public/services/executor.js similarity index 66% rename from x-pack/legacy/plugins/monitoring/public/services/executor_provider.js rename to x-pack/plugins/monitoring/public/services/executor.js index 4a0551fa5af11..7c5e9d652b64e 100644 --- a/x-pack/legacy/plugins/monitoring/public/services/executor_provider.js +++ b/x-pack/plugins/monitoring/public/services/executor.js @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { subscribeWithScope } from 'plugins/monitoring/np_imports/ui/utils'; +import { Legacy } from '../legacy_shims'; +import { subscribeWithScope } from '../angular/helpers/utils'; import { Subscription } from 'rxjs'; -export function executorProvider(Promise, $timeout) { + +export function executorProvider($timeout, $q) { const queue = []; const subscriptions = new Subscription(); let executionTimer; @@ -61,15 +62,17 @@ export function executorProvider(Promise, $timeout) { * @returns {Promise} a promise of all the services */ function run() { - const noop = () => Promise.resolve(); - return Promise.all( - queue.map(service => { - return service - .execute() - .then(service.handleResponse || noop) - .catch(service.handleError || noop); - }) - ).finally(reset); + const noop = () => $q.resolve(); + return $q + .all( + queue.map(service => { + return service + .execute() + .then(service.handleResponse || noop) + .catch(service.handleError || noop); + }) + ) + .finally(reset); } function reFetch() { @@ -78,7 +81,7 @@ export function executorProvider(Promise, $timeout) { } function killIfPaused() { - if (timefilter.getRefreshInterval().pause) { + if (Legacy.shims.timefilter.getRefreshInterval().pause) { killTimer(); } } @@ -88,6 +91,7 @@ export function executorProvider(Promise, $timeout) { * @returns {void} */ function start() { + const timefilter = Legacy.shims.timefilter; if ( (ignorePaused || timefilter.getRefreshInterval().pause === false) && timefilter.getRefreshInterval().value > 0 @@ -102,17 +106,20 @@ export function executorProvider(Promise, $timeout) { return { register, start($scope) { - subscriptions.add( - subscribeWithScope($scope, timefilter.getFetch$(), { - next: reFetch, - }) - ); - subscriptions.add( - subscribeWithScope($scope, timefilter.getRefreshIntervalUpdate$(), { - next: killIfPaused, - }) - ); - start(); + $scope.$applyAsync(() => { + const timefilter = Legacy.shims.timefilter; + subscriptions.add( + subscribeWithScope($scope, timefilter.getFetch$(), { + next: reFetch, + }) + ); + subscriptions.add( + subscribeWithScope($scope, timefilter.getRefreshIntervalUpdate$(), { + next: killIfPaused, + }) + ); + start(); + }); }, run, destroy, diff --git a/x-pack/legacy/plugins/monitoring/public/services/features.js b/x-pack/plugins/monitoring/public/services/features.js similarity index 86% rename from x-pack/legacy/plugins/monitoring/public/services/features.js rename to x-pack/plugins/monitoring/public/services/features.js index e2357ef08d7df..f98af10f8dfb4 100644 --- a/x-pack/legacy/plugins/monitoring/public/services/features.js +++ b/x-pack/plugins/monitoring/public/services/features.js @@ -5,10 +5,8 @@ */ import _ from 'lodash'; -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -const uiModule = uiModules.get('monitoring/features', []); -uiModule.service('features', function($window) { +export function featuresProvider($window) { function getData() { let returnData = {}; const monitoringData = $window.localStorage.getItem('xpack.monitoring.data'); @@ -45,4 +43,4 @@ uiModule.service('features', function($window) { isEnabled, update, }; -}); +} diff --git a/x-pack/legacy/plugins/monitoring/public/services/license.js b/x-pack/plugins/monitoring/public/services/license.js similarity index 88% rename from x-pack/legacy/plugins/monitoring/public/services/license.js rename to x-pack/plugins/monitoring/public/services/license.js index 94078b799fdf1..341309004b110 100644 --- a/x-pack/legacy/plugins/monitoring/public/services/license.js +++ b/x-pack/plugins/monitoring/public/services/license.js @@ -5,11 +5,9 @@ */ import { contains } from 'lodash'; -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; import { ML_SUPPORTED_LICENSES } from '../../common/constants'; -const uiModule = uiModules.get('monitoring/license', []); -uiModule.service('license', () => { +export function licenseProvider() { return new (class LicenseService { constructor() { // do not initialize with usable state @@ -50,4 +48,4 @@ uiModule.service('license', () => { return false; } })(); -}); +} diff --git a/x-pack/legacy/plugins/monitoring/public/services/title.js b/x-pack/plugins/monitoring/public/services/title.js similarity index 54% rename from x-pack/legacy/plugins/monitoring/public/services/title.js rename to x-pack/plugins/monitoring/public/services/title.js index 442f4fb5b4029..0715f4dc9e0b6 100644 --- a/x-pack/legacy/plugins/monitoring/public/services/title.js +++ b/x-pack/plugins/monitoring/public/services/title.js @@ -6,21 +6,20 @@ import _ from 'lodash'; import { i18n } from '@kbn/i18n'; -import { uiModules } from 'plugins/monitoring/np_imports/ui/modules'; -import { docTitle } from 'ui/doc_title'; +import { Legacy } from '../legacy_shims'; -const uiModule = uiModules.get('monitoring/title', []); -uiModule.service('title', () => { +export function titleProvider($rootScope) { return function changeTitle(cluster, suffix) { let clusterName = _.get(cluster, 'cluster_name'); clusterName = clusterName ? `- ${clusterName}` : ''; suffix = suffix ? `- ${suffix}` : ''; - docTitle.change( - i18n.translate('xpack.monitoring.stackMonitoringDocTitle', { - defaultMessage: 'Stack Monitoring {clusterName} {suffix}', - values: { clusterName, suffix }, - }), - true - ); + $rootScope.$applyAsync(() => { + Legacy.shims.docTitle.change( + i18n.translate('xpack.monitoring.stackMonitoringDocTitle', { + defaultMessage: 'Stack Monitoring {clusterName} {suffix}', + values: { clusterName, suffix }, + }) + ); + }); }; -}); +} diff --git a/x-pack/plugins/monitoring/public/types.ts b/x-pack/plugins/monitoring/public/types.ts new file mode 100644 index 0000000000000..5fcb6b50f5d83 --- /dev/null +++ b/x-pack/plugins/monitoring/public/types.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { PluginInitializerContext, CoreStart } from 'kibana/public'; +import { NavigationPublicPluginStart as NavigationStart } from '../../../../src/plugins/navigation/public'; +import { DataPublicPluginStart } from '../../../../src/plugins/data/public'; + +export { MonitoringConfig } from '../server'; + +export interface MonitoringPluginDependencies { + navigation: NavigationStart; + data: DataPublicPluginStart; + element: HTMLElement; + core: CoreStart; + isCloud: boolean; + pluginInitializerContext: PluginInitializerContext; + externalConfig: Array | Array>; +} diff --git a/x-pack/plugins/monitoring/public/url_state.ts b/x-pack/plugins/monitoring/public/url_state.ts new file mode 100644 index 0000000000000..e66d5462c2bb5 --- /dev/null +++ b/x-pack/plugins/monitoring/public/url_state.ts @@ -0,0 +1,169 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { Subscription } from 'rxjs'; +import { History } from 'history'; +import { createHashHistory } from 'history'; +import { MonitoringPluginDependencies } from './types'; + +import { + RefreshInterval, + TimeRange, + syncQueryStateWithUrl, +} from '../../../../src/plugins/data/public'; + +import { + createStateContainer, + createKbnUrlStateStorage, + StateContainer, + INullableBaseStateContainer, + IKbnUrlStateStorage, + ISyncStateRef, + syncState, +} from '../../../../src/plugins/kibana_utils/public'; + +interface Route { + params: { _g: unknown }; +} + +interface RawObject { + [key: string]: unknown; +} + +export interface MonitoringAppState { + [key: string]: unknown; + cluster_uuid?: string; + ccs?: boolean; + inSetupMode?: boolean; + refreshInterval?: RefreshInterval; + time?: TimeRange; + filters?: any[]; +} + +export interface MonitoringAppStateTransitions { + set: ( + state: MonitoringAppState + ) => ( + prop: T, + value: MonitoringAppState[T] + ) => MonitoringAppState; +} + +const GLOBAL_STATE_KEY = '_g'; +const objectEquals = (objA: any, objB: any) => JSON.stringify(objA) === JSON.stringify(objB); + +export class GlobalState { + private readonly stateSyncRef: ISyncStateRef; + private readonly stateContainer: StateContainer< + MonitoringAppState, + MonitoringAppStateTransitions + >; + private readonly stateStorage: IKbnUrlStateStorage; + private readonly stateContainerChangeSub: Subscription; + private readonly syncQueryStateWithUrlManager: { stop: () => void }; + private readonly timefilterRef: MonitoringPluginDependencies['data']['query']['timefilter']['timefilter']; + + private lastAssignedState: MonitoringAppState = {}; + private lastKnownGlobalState?: string; + + constructor( + queryService: MonitoringPluginDependencies['data']['query'], + rootScope: ng.IRootScopeService, + ngLocation: ng.ILocationService, + externalState: RawObject + ) { + this.timefilterRef = queryService.timefilter.timefilter; + + const history: History = createHashHistory(); + this.stateStorage = createKbnUrlStateStorage({ useHash: false, history }); + + const initialStateFromUrl = this.stateStorage.get(GLOBAL_STATE_KEY) as MonitoringAppState; + + this.stateContainer = createStateContainer(initialStateFromUrl, { + set: state => (prop, value) => ({ ...state, [prop]: value }), + }); + + this.stateSyncRef = syncState({ + storageKey: GLOBAL_STATE_KEY, + stateContainer: this.stateContainer as INullableBaseStateContainer, + stateStorage: this.stateStorage, + }); + + this.stateContainerChangeSub = this.stateContainer.state$.subscribe(() => { + this.lastAssignedState = this.getState(); + if (!this.stateContainer.get() && this.lastKnownGlobalState) { + rootScope.$applyAsync(() => + ngLocation.search(`${GLOBAL_STATE_KEY}=${this.lastKnownGlobalState}`).replace() + ); + } + this.syncExternalState(externalState); + }); + + this.syncQueryStateWithUrlManager = syncQueryStateWithUrl(queryService, this.stateStorage); + this.stateSyncRef.start(); + this.startHashSync(rootScope, ngLocation); + this.lastAssignedState = this.getState(); + + rootScope.$on('$destroy', () => this.destroy()); + } + + private syncExternalState(externalState: { [key: string]: unknown }) { + const currentState = this.stateContainer.get(); + for (const key in currentState) { + if ( + ({ save: 1, time: 1, refreshInterval: 1, filters: 1 } as { [key: string]: number })[key] + ) { + continue; + } + if (currentState[key] !== externalState[key]) { + externalState[key] = currentState[key]; + } + } + } + + private startHashSync(rootScope: ng.IRootScopeService, ngLocation: ng.ILocationService) { + rootScope.$on( + '$routeChangeStart', + (_: { preventDefault: () => void }, newState: Route, oldState: Route) => { + const currentGlobalState = oldState?.params?._g; + const nextGlobalState = newState?.params?._g; + if (!nextGlobalState && currentGlobalState && typeof currentGlobalState === 'string') { + newState.params._g = currentGlobalState; + ngLocation.search(`${GLOBAL_STATE_KEY}=${currentGlobalState}`).replace(); + } + this.lastKnownGlobalState = (nextGlobalState || currentGlobalState) as string; + } + ); + } + + public setState(state?: { [key: string]: unknown }) { + const currentAppState = this.getState(); + const newAppState = { ...currentAppState, ...state }; + if (state && objectEquals(newAppState, currentAppState)) { + return; + } + const newState = { + ...newAppState, + refreshInterval: this.timefilterRef.getRefreshInterval(), + time: this.timefilterRef.getTime(), + }; + this.lastAssignedState = newState; + this.stateContainer.set(newState); + } + + public getState(): MonitoringAppState { + const currentState = { ...this.lastAssignedState, ...this.stateContainer.get() }; + delete currentState.filters; + const { refreshInterval: _nullA, time: _nullB, ...currentAppState } = currentState; + return currentAppState || {}; + } + + public destroy() { + this.syncQueryStateWithUrlManager.stop(); + this.stateContainerChangeSub.unsubscribe(); + this.stateSyncRef.stop(); + } +} diff --git a/x-pack/legacy/plugins/monitoring/public/views/__tests__/base_controller.js b/x-pack/plugins/monitoring/public/views/__tests__/base_controller.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/views/__tests__/base_controller.js rename to x-pack/plugins/monitoring/public/views/__tests__/base_controller.js index 6c3c73a35601c..4f7180b138aa5 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/__tests__/base_controller.js +++ b/x-pack/plugins/monitoring/public/views/__tests__/base_controller.js @@ -7,8 +7,9 @@ import { spy, stub } from 'sinon'; import expect from '@kbn/expect'; import { MonitoringViewBaseController } from '../'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { Legacy } from '../../legacy_shims'; import { PromiseWithCancel, Status } from '../../../common/cancel_promise'; +import { dataPluginMock } from '../../../../../../src/plugins/data/public/mocks'; /* * Mostly copied from base_table_controller test, with modifications @@ -21,9 +22,13 @@ describe('MonitoringViewBaseController', function() { let titleService; let executorService; let configService; + let timefilter; const httpCall = ms => new Promise(resolve => setTimeout(() => resolve(), ms)); before(() => { + const data = dataPluginMock.createStartContract(); + Legacy._shims = { timefilter }; + timefilter = data.query.timefilter.timefilter; titleService = spy(); executorService = { register: spy(), diff --git a/x-pack/legacy/plugins/monitoring/public/views/__tests__/base_table_controller.js b/x-pack/plugins/monitoring/public/views/__tests__/base_table_controller.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/__tests__/base_table_controller.js rename to x-pack/plugins/monitoring/public/views/__tests__/base_table_controller.js diff --git a/x-pack/legacy/plugins/monitoring/public/views/access_denied/index.html b/x-pack/plugins/monitoring/public/views/access_denied/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/access_denied/index.html rename to x-pack/plugins/monitoring/public/views/access_denied/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/access_denied/index.js b/x-pack/plugins/monitoring/public/views/access_denied/index.js similarity index 89% rename from x-pack/legacy/plugins/monitoring/public/views/access_denied/index.js rename to x-pack/plugins/monitoring/public/views/access_denied/index.js index a0cfc79f001ca..856e59702963a 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/access_denied/index.js +++ b/x-pack/plugins/monitoring/public/views/access_denied/index.js @@ -5,8 +5,8 @@ */ import { noop } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import uiChrome from 'plugins/monitoring/np_imports/ui/chrome'; +import { uiRoutes } from '../../angular/helpers/routes'; +import { Legacy } from '../../legacy_shims'; import template from './index.html'; const tryPrivilege = ($http, kbnUrl) => { @@ -40,7 +40,7 @@ uiRoutes.when('/access-denied', { // The template's "Back to Kibana" button click handler this.goToKibana = () => { - $window.location.href = uiChrome.getBasePath() + kbnBaseUrl; + $window.location.href = Legacy.shims.getBasePath() + kbnBaseUrl; }; // keep trying to load data in the background diff --git a/x-pack/legacy/plugins/monitoring/public/views/alerts/index.html b/x-pack/plugins/monitoring/public/views/alerts/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/alerts/index.html rename to x-pack/plugins/monitoring/public/views/alerts/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/alerts/index.js b/x-pack/plugins/monitoring/public/views/alerts/index.js similarity index 77% rename from x-pack/legacy/plugins/monitoring/public/views/alerts/index.js rename to x-pack/plugins/monitoring/public/views/alerts/index.js index 62cc985887e9f..2e7a34c0aef29 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/alerts/index.js +++ b/x-pack/plugins/monitoring/public/views/alerts/index.js @@ -8,12 +8,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { render } from 'react-dom'; import { find, get } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; +import { uiRoutes } from '../../angular/helpers/routes'; import template from './index.html'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { I18nContext } from 'ui/i18n'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { routeInitProvider } from '../../lib/route_init'; +import { ajaxErrorHandlersProvider } from '../../lib/ajax_error_handler'; +import { Legacy } from '../../legacy_shims'; import { Alerts } from '../../components/alerts'; import { MonitoringViewBaseEuiTableController } from '../base_eui_table_controller'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -28,7 +27,7 @@ function getPageData($injector) { ? `../api/monitoring/v1/alert_status` : `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/legacy_alerts`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); const data = { timeRange: { min: timeBounds.min.toISOString(), @@ -103,22 +102,20 @@ uiRoutes.when('/alerts', { ); render( - - - - - {app} - - - - - - - - , + + + + {app} + + + + + + + , document.getElementById('monitoringAlertsApp') ); }; diff --git a/x-pack/legacy/plugins/monitoring/public/views/all.js b/x-pack/plugins/monitoring/public/views/all.js similarity index 98% rename from x-pack/legacy/plugins/monitoring/public/views/all.js rename to x-pack/plugins/monitoring/public/views/all.js index ded378b050c2d..51dcce751863c 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/all.js +++ b/x-pack/plugins/monitoring/public/views/all.js @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import './loading'; import './no_data'; import './access_denied'; import './alerts'; diff --git a/x-pack/legacy/plugins/monitoring/public/views/apm/instance/index.html b/x-pack/plugins/monitoring/public/views/apm/instance/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/apm/instance/index.html rename to x-pack/plugins/monitoring/public/views/apm/instance/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/apm/instance/index.js b/x-pack/plugins/monitoring/public/views/apm/instance/index.js similarity index 83% rename from x-pack/legacy/plugins/monitoring/public/views/apm/instance/index.js rename to x-pack/plugins/monitoring/public/views/apm/instance/index.js index 4d0f858d28117..982857ab5aea4 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/apm/instance/index.js +++ b/x-pack/plugins/monitoring/public/views/apm/instance/index.js @@ -13,12 +13,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { find, get } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; import { MonitoringViewBaseController } from '../../base_controller'; import { ApmServerInstance } from '../../../components/apm/instance'; -import { I18nContext } from 'ui/i18n'; import { CODE_PATH_APM } from '../../../../common/constants'; uiRoutes.when('/apm/instances/:uuid', { @@ -64,14 +63,12 @@ uiRoutes.when('/apm/instances/:uuid', { renderReact(data) { const component = ( - - - + ); super.renderReact(component); } diff --git a/x-pack/legacy/plugins/monitoring/public/views/apm/instances/index.html b/x-pack/plugins/monitoring/public/views/apm/instances/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/apm/instances/index.html rename to x-pack/plugins/monitoring/public/views/apm/instances/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/apm/instances/index.js b/x-pack/plugins/monitoring/public/views/apm/instances/index.js similarity index 70% rename from x-pack/legacy/plugins/monitoring/public/views/apm/instances/index.js rename to x-pack/plugins/monitoring/public/views/apm/instances/index.js index 317879063b6e5..8cd0b03e89e04 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/apm/instances/index.js +++ b/x-pack/plugins/monitoring/public/views/apm/instances/index.js @@ -7,12 +7,11 @@ import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; import { ApmServerInstances } from '../../../components/apm/instances'; import { MonitoringViewBaseEuiTableController } from '../..'; -import { I18nContext } from 'ui/i18n'; import { SetupModeRenderer } from '../../../components/renderers'; import { APM_SYSTEM_ID, CODE_PATH_APM } from '../../../../common/constants'; @@ -62,28 +61,26 @@ uiRoutes.when('/apm/instances', { const { pagination, sorting, onTableChange } = this; const component = ( - - ( - - {flyoutComponent} - - {bottomBarComponent} - - )} - /> - + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> ); super.renderReact(component); } diff --git a/x-pack/legacy/plugins/monitoring/public/views/apm/overview/index.html b/x-pack/plugins/monitoring/public/views/apm/overview/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/apm/overview/index.html rename to x-pack/plugins/monitoring/public/views/apm/overview/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/apm/overview/index.js b/x-pack/plugins/monitoring/public/views/apm/overview/index.js similarity index 81% rename from x-pack/legacy/plugins/monitoring/public/views/apm/overview/index.js rename to x-pack/plugins/monitoring/public/views/apm/overview/index.js index e6562f428d2a0..1fdd441e62e22 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/apm/overview/index.js +++ b/x-pack/plugins/monitoring/public/views/apm/overview/index.js @@ -6,12 +6,11 @@ import React from 'react'; import { find } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; import { MonitoringViewBaseController } from '../../base_controller'; import { ApmOverview } from '../../../components/apm/overview'; -import { I18nContext } from 'ui/i18n'; import { CODE_PATH_APM } from '../../../../common/constants'; uiRoutes.when('/apm', { @@ -48,11 +47,7 @@ uiRoutes.when('/apm', { } renderReact(data) { - const component = ( - - - - ); + const component = ; super.renderReact(component); } }, diff --git a/x-pack/legacy/plugins/monitoring/public/views/base_controller.js b/x-pack/plugins/monitoring/public/views/base_controller.js similarity index 77% rename from x-pack/legacy/plugins/monitoring/public/views/base_controller.js rename to x-pack/plugins/monitoring/public/views/base_controller.js index 25b4d97177a98..e5e59f2f8e826 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/base_controller.js +++ b/x-pack/plugins/monitoring/public/views/base_controller.js @@ -8,9 +8,8 @@ import React from 'react'; import moment from 'moment'; import { render, unmountComponentAtNode } from 'react-dom'; import { getPageData } from '../lib/get_page_data'; -import { PageLoading } from 'plugins/monitoring/components'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { I18nContext } from 'ui/i18n'; +import { PageLoading } from '../components'; +import { Legacy } from '../legacy_shims'; import { PromiseWithCancel } from '../../common/cancel_promise'; import { updateSetupModeData, getSetupModeState } from '../lib/setup_mode'; @@ -113,18 +112,6 @@ export class MonitoringViewBaseController { const { enableTimeFilter = true, enableAutoRefresh = true } = options; - if (enableTimeFilter === false) { - timefilter.disableTimeRangeSelector(); - } else { - timefilter.enableTimeRangeSelector(); - } - - if (enableAutoRefresh === false) { - timefilter.disableAutoRefreshSelector(); - } else { - timefilter.enableAutoRefreshSelector(); - } - this.updateData = () => { if (this.updateDataPromise) { // Do not sent another request if one is inflight @@ -146,7 +133,46 @@ export class MonitoringViewBaseController { }); }); }; - fetchDataImmediately && this.updateData(); + + $scope.$applyAsync(() => { + const timefilter = Legacy.shims.timefilter; + + if (enableTimeFilter === false) { + timefilter.disableTimeRangeSelector(); + } else { + timefilter.enableTimeRangeSelector(); + } + + if (enableAutoRefresh === false) { + timefilter.disableAutoRefreshSelector(); + } else { + timefilter.enableAutoRefreshSelector(); + } + + // needed for chart pages + this.onBrush = ({ xaxis }) => { + removePopstateHandler(); + const { to, from } = xaxis; + const timezone = config.get('dateFormat:tz'); + const offset = getOffsetInMS(timezone); + timefilter.setTime({ + from: moment(from - offset), + to: moment(to - offset), + mode: 'absolute', + }); + $executor.cancel(); + $executor.run(); + ++zoomInLevel; + clearTimeout(deferTimer); + /* + Needed to defer 'popstate' event, so it does not fire immediately after it's added. + 10ms is to make sure the event is not added with the same code digest + */ + deferTimer = setTimeout(() => addPopstateHandler(), 10); + }; + + fetchDataImmediately && this.updateData(); + }); $executor.register({ execute: () => this.updateData(), @@ -155,35 +181,14 @@ export class MonitoringViewBaseController { $scope.$on('$destroy', () => { clearTimeout(deferTimer); removePopstateHandler(); - if (this.reactNodeId) { + const targetElement = document.getElementById(this.reactNodeId); + if (targetElement) { // WIP https://github.com/elastic/x-pack-kibana/issues/5198 - unmountComponentAtNode(document.getElementById(this.reactNodeId)); + unmountComponentAtNode(targetElement); } $executor.destroy(); }); - // needed for chart pages - this.onBrush = ({ xaxis }) => { - removePopstateHandler(); - const { to, from } = xaxis; - const timezone = config.get('dateFormat:tz'); - const offset = getOffsetInMS(timezone); - timefilter.setTime({ - from: moment(from - offset), - to: moment(to - offset), - mode: 'absolute', - }); - $executor.cancel(); - $executor.run(); - ++zoomInLevel; - clearTimeout(deferTimer); - /* - Needed to defer 'popstate' event, so it does not fire immediately after it's added. - 10ms is to make sure the event is not added with the same code digest - */ - deferTimer = setTimeout(() => addPopstateHandler(), 10); - }; - this.setTitle = title => titleService($scope.cluster, title); } @@ -193,16 +198,11 @@ export class MonitoringViewBaseController { console.warn(`"#${this.reactNodeId}" element has not been added to the DOM yet`); return; } - if (this._isDataInitialized === false) { - render( - - - , - renderElement - ); - } else { - render(component, renderElement); - } + const I18nContext = Legacy.shims.I18nContext; + const wrappedComponent = ( + {!this._isDataInitialized ? : component} + ); + render(wrappedComponent, renderElement); } getPaginationRouteOptions() { diff --git a/x-pack/legacy/plugins/monitoring/public/views/base_eui_table_controller.js b/x-pack/plugins/monitoring/public/views/base_eui_table_controller.js similarity index 97% rename from x-pack/legacy/plugins/monitoring/public/views/base_eui_table_controller.js rename to x-pack/plugins/monitoring/public/views/base_eui_table_controller.js index 0460adaeecd10..ac5ba45af8614 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/base_eui_table_controller.js +++ b/x-pack/plugins/monitoring/public/views/base_eui_table_controller.js @@ -5,7 +5,7 @@ */ import { MonitoringViewBaseController } from './'; -import { euiTableStorageGetter, euiTableStorageSetter } from 'plugins/monitoring/components/table'; +import { euiTableStorageGetter, euiTableStorageSetter } from '../components/table'; import { EUI_SORT_ASCENDING } from '../../common/constants'; const PAGE_SIZE_OPTIONS = [5, 10, 20, 50]; diff --git a/x-pack/legacy/plugins/monitoring/public/views/base_table_controller.js b/x-pack/plugins/monitoring/public/views/base_table_controller.js similarity index 95% rename from x-pack/legacy/plugins/monitoring/public/views/base_table_controller.js rename to x-pack/plugins/monitoring/public/views/base_table_controller.js index 6ae486eae96fc..2275608c473dd 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/base_table_controller.js +++ b/x-pack/plugins/monitoring/public/views/base_table_controller.js @@ -5,7 +5,7 @@ */ import { MonitoringViewBaseController } from './'; -import { tableStorageGetter, tableStorageSetter } from 'plugins/monitoring/components/table'; +import { tableStorageGetter, tableStorageSetter } from '../components/table'; /** * Class to manage common instantiation behaviors in a view controller diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/beat/get_page_data.js b/x-pack/plugins/monitoring/public/views/beats/beat/get_page_data.js similarity index 82% rename from x-pack/legacy/plugins/monitoring/public/views/beats/beat/get_page_data.js rename to x-pack/plugins/monitoring/public/views/beats/beat/get_page_data.js index 7e77e93d52fe8..7c9c459218529 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/beats/beat/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/beats/beat/get_page_data.js @@ -4,15 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { Legacy } from '../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); const $route = $injector.get('$route'); const globalState = $injector.get('globalState'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats/beat/${$route.current.params.beatUuid}`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/beat/index.html b/x-pack/plugins/monitoring/public/views/beats/beat/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/beats/beat/index.html rename to x-pack/plugins/monitoring/public/views/beats/beat/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/beat/index.js b/x-pack/plugins/monitoring/public/views/beats/beat/index.js similarity index 92% rename from x-pack/legacy/plugins/monitoring/public/views/beats/beat/index.js rename to x-pack/plugins/monitoring/public/views/beats/beat/index.js index b3fad1b4cc3cb..9d5f9b4d562a6 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/beats/beat/index.js +++ b/x-pack/plugins/monitoring/public/views/beats/beat/index.js @@ -6,8 +6,8 @@ import { find } from 'lodash'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/listing/get_page_data.js b/x-pack/plugins/monitoring/public/views/beats/listing/get_page_data.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/views/beats/listing/get_page_data.js rename to x-pack/plugins/monitoring/public/views/beats/listing/get_page_data.js index 1838011dee652..77942303afcc2 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/beats/listing/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/beats/listing/get_page_data.js @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { Legacy } from '../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats/beats`; return $http diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/listing/index.html b/x-pack/plugins/monitoring/public/views/beats/listing/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/beats/listing/index.html rename to x-pack/plugins/monitoring/public/views/beats/listing/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/listing/index.js b/x-pack/plugins/monitoring/public/views/beats/listing/index.js similarity index 66% rename from x-pack/legacy/plugins/monitoring/public/views/beats/listing/index.js rename to x-pack/plugins/monitoring/public/views/beats/listing/index.js index 48848007c9c27..7d011089fdd7d 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/beats/listing/index.js +++ b/x-pack/plugins/monitoring/public/views/beats/listing/index.js @@ -6,13 +6,12 @@ import { find } from 'lodash'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseEuiTableController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; import React, { Fragment } from 'react'; -import { I18nContext } from 'ui/i18n'; import { Listing } from '../../../components/beats/listing/listing'; import { SetupModeRenderer } from '../../../components/renderers'; import { CODE_PATH_BEATS, BEATS_SYSTEM_ID } from '../../../../common/constants'; @@ -62,31 +61,29 @@ uiRoutes.when('/beats/beats', { renderComponent() { const { sorting, pagination, onTableChange } = this.scope.beats; this.renderReact( - - ( - - {flyoutComponent} - - {bottomBarComponent} - - )} - /> - + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> ); } }, diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/overview/get_page_data.js b/x-pack/plugins/monitoring/public/views/beats/overview/get_page_data.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/views/beats/overview/get_page_data.js rename to x-pack/plugins/monitoring/public/views/beats/overview/get_page_data.js index a3b120b277b94..e5d576961b797 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/beats/overview/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/beats/overview/get_page_data.js @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { Legacy } from '../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/beats`; return $http diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/overview/index.html b/x-pack/plugins/monitoring/public/views/beats/overview/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/beats/overview/index.html rename to x-pack/plugins/monitoring/public/views/beats/overview/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/beats/overview/index.js b/x-pack/plugins/monitoring/public/views/beats/overview/index.js similarity index 91% rename from x-pack/legacy/plugins/monitoring/public/views/beats/overview/index.js rename to x-pack/plugins/monitoring/public/views/beats/overview/index.js index aea62d5c7f78f..0eb39ef372263 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/beats/overview/index.js +++ b/x-pack/plugins/monitoring/public/views/beats/overview/index.js @@ -6,8 +6,8 @@ import { find } from 'lodash'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; diff --git a/x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.html b/x-pack/plugins/monitoring/public/views/cluster/listing/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.html rename to x-pack/plugins/monitoring/public/views/cluster/listing/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.js b/x-pack/plugins/monitoring/public/views/cluster/listing/index.js similarity index 75% rename from x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.js rename to x-pack/plugins/monitoring/public/views/cluster/listing/index.js index 958226514b146..42be4f02f5c94 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/cluster/listing/index.js +++ b/x-pack/plugins/monitoring/public/views/cluster/listing/index.js @@ -5,10 +5,9 @@ */ import React from 'react'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseEuiTableController } from '../../'; -import { I18nContext } from 'ui/i18n'; import template from './index.html'; import { Listing } from '../../../components/cluster/listing'; import { CODE_PATH_ALL } from '../../../../common/constants'; @@ -33,7 +32,7 @@ uiRoutes } if (clusters.length === 1) { // Bypass the cluster listing if there is just 1 cluster - kbnUrl.changePath('/overview'); + kbnUrl.redirect('/overview'); return Promise.reject(); } return clusters; @@ -63,21 +62,19 @@ uiRoutes () => this.data, data => { this.renderReact( - - - + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/cluster/overview/index.html b/x-pack/plugins/monitoring/public/views/cluster/overview/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/cluster/overview/index.html rename to x-pack/plugins/monitoring/public/views/cluster/overview/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/cluster/overview/index.js b/x-pack/plugins/monitoring/public/views/cluster/overview/index.js similarity index 68% rename from x-pack/legacy/plugins/monitoring/public/views/cluster/overview/index.js rename to x-pack/plugins/monitoring/public/views/cluster/overview/index.js index e1777b8ed7b49..3f6fb77f02288 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/cluster/overview/index.js +++ b/x-pack/plugins/monitoring/public/views/cluster/overview/index.js @@ -5,14 +5,13 @@ */ import React, { Fragment } from 'react'; import { isEmpty } from 'lodash'; -import chrome from 'ui/chrome'; +import { Legacy } from '../../../legacy_shims'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; import { MonitoringViewBaseController } from '../../'; -import { Overview } from 'plugins/monitoring/components/cluster/overview'; -import { I18nContext } from 'ui/i18n'; +import { Overview } from '../../../components/cluster/overview'; import { SetupModeRenderer } from '../../../components/renderers'; import { CODE_PATH_ALL, @@ -70,31 +69,29 @@ uiRoutes.when('/overview', { return; } - let emailAddress = chrome.getInjected('monitoringLegacyEmailAddress') || ''; + let emailAddress = Legacy.shims.getInjected('monitoringLegacyEmailAddress') || ''; if (KIBANA_ALERTING_ENABLED) { emailAddress = config.get(MONITORING_CONFIG_ALERTING_EMAIL_ADDRESS) || emailAddress; } this.renderReact( - - ( - - {flyoutComponent} - - {bottomBarComponent} - - )} - /> - + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/get_page_data.js b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/get_page_data.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/get_page_data.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/ccr/get_page_data.js index 83dd24209dfe3..d4a86b00a7505 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/get_page_data.js @@ -4,13 +4,13 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { Legacy } from '../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/elasticsearch/ccr`; return $http diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/ccr/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/index.js similarity index 83% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/ccr/index.js index cf51347842f4a..88d3a3614243f 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/index.js @@ -6,13 +6,12 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; +import { uiRoutes } from '../../../angular/helpers/routes'; import { getPageData } from './get_page_data'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; import { Ccr } from '../../../components/elasticsearch/ccr'; import { MonitoringViewBaseController } from '../../base_controller'; -import { I18nContext } from 'ui/i18n'; import { CODE_PATH_ELASTICSEARCH } from '../../../../common/constants'; uiRoutes.when('/elasticsearch/ccr', { @@ -45,11 +44,7 @@ uiRoutes.when('/elasticsearch/ccr', { ); this.renderReact = ({ data }) => { - super.renderReact( - - - - ); + super.renderReact(); }; } }, diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/shard/get_page_data.js b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/get_page_data.js similarity index 82% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/shard/get_page_data.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/get_page_data.js index 22ca094d28b07..20f39edbb6a75 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/shard/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/get_page_data.js @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../../lib/ajax_error_handler'; +import { Legacy } from '../../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); const $route = $injector.get('$route'); const globalState = $injector.get('globalState'); - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/elasticsearch/ccr/${$route.current.params.index}/shard/${$route.current.params.shardId}`; return $http diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js similarity index 86% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js index ff35f7f743f66..260422d322a2d 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ccr/shard/index.js @@ -7,13 +7,12 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; +import { uiRoutes } from '../../../../angular/helpers/routes'; import { getPageData } from './get_page_data'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { routeInitProvider } from '../../../../lib/route_init'; import template from './index.html'; import { MonitoringViewBaseController } from '../../../base_controller'; import { CcrShard } from '../../../../components/elasticsearch/ccr_shard'; -import { I18nContext } from 'ui/i18n'; import { CODE_PATH_ELASTICSEARCH } from '../../../../../common/constants'; uiRoutes.when('/elasticsearch/ccr/:index/shard/:shardId', { @@ -54,11 +53,7 @@ uiRoutes.when('/elasticsearch/ccr/:index/shard/:shardId', { ); this.renderReact = props => { - super.renderReact( - - - - ); + super.renderReact(); }; } }, diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js similarity index 79% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js index 4fc439b4e0123..9fbaf6c00725d 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/index/advanced/index.js @@ -9,13 +9,12 @@ */ import React from 'react'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../../angular/helpers/routes'; +import { ajaxErrorHandlersProvider } from '../../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../../lib/route_init'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { Legacy } from '../../../../legacy_shims'; import { AdvancedIndex } from '../../../../components/elasticsearch/index/advanced'; -import { I18nContext } from 'ui/i18n'; import { MonitoringViewBaseController } from '../../../base_controller'; import { CODE_PATH_ELASTICSEARCH } from '../../../../../common/constants'; @@ -24,7 +23,7 @@ function getPageData($injector) { const $route = $injector.get('$route'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/elasticsearch/indices/${$route.current.params.index}`; const $http = $injector.get('$http'); - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { @@ -78,14 +77,12 @@ uiRoutes.when('/elasticsearch/indices/:index/advanced', { () => this.data, data => { this.renderReact( - - - + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/index/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/index/index.js index bbeef8294a897..d2f49d2280e15 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/index/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/index/index.js @@ -9,12 +9,11 @@ */ import React from 'react'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { I18nContext } from 'ui/i18n'; +import { Legacy } from '../../../legacy_shims'; import { labels } from '../../../components/elasticsearch/shard_allocation/lib/labels'; import { indicesByNodes } from '../../../components/elasticsearch/shard_allocation/transformers/indices_by_nodes'; import { Index } from '../../../components/elasticsearch/index/index'; @@ -26,7 +25,7 @@ function getPageData($injector) { const $route = $injector.get('$route'); const globalState = $injector.get('globalState'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/elasticsearch/indices/${$route.current.params.index}`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { @@ -96,17 +95,15 @@ uiRoutes.when('/elasticsearch/indices/:index', { } this.renderReact( - - - + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/indices/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/indices/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/indices/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/indices/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.js index f1d96557b0c1c..ee177c3e8ed04 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/indices/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/indices/index.js @@ -7,12 +7,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseEuiTableController } from '../../'; import { ElasticsearchIndices } from '../../../components'; import template from './index.html'; -import { I18nContext } from 'ui/i18n'; import { CODE_PATH_ELASTICSEARCH } from '../../../../common/constants'; uiRoutes.when('/elasticsearch/indices', { @@ -71,17 +70,15 @@ uiRoutes.when('/elasticsearch/indices', { this.renderReact = ({ clusterStatus, indices }) => { super.renderReact( - - - + ); }; } diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ml_jobs/get_page_data.js b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/get_page_data.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ml_jobs/get_page_data.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/get_page_data.js index 1943b580f7a75..0b50a04d53036 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ml_jobs/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/get_page_data.js @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { Legacy } from '../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/elasticsearch/ml_jobs`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { ccs: globalState.ccs, diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js similarity index 92% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js index 5e66a4147ab70..d1dd81223ad5e 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/ml_jobs/index.js @@ -6,8 +6,8 @@ import { find } from 'lodash'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseEuiTableController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js similarity index 78% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js index 2bbdf604d00ce..5c45509fce37c 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/node/advanced/index.js @@ -9,12 +9,11 @@ */ import React from 'react'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../../angular/helpers/routes'; +import { ajaxErrorHandlersProvider } from '../../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../../lib/route_init'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { I18nContext } from 'ui/i18n'; +import { Legacy } from '../../../../legacy_shims'; import { AdvancedNode } from '../../../../components/elasticsearch/node/advanced'; import { MonitoringViewBaseController } from '../../../base_controller'; import { CODE_PATH_ELASTICSEARCH } from '../../../../../common/constants'; @@ -23,7 +22,7 @@ function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); const $route = $injector.get('$route'); - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/elasticsearch/nodes/${$route.current.params.node}`; return $http @@ -79,14 +78,12 @@ uiRoutes.when('/elasticsearch/nodes/:node/advanced', { ); this.renderReact( - - - + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/get_page_data.js b/x-pack/plugins/monitoring/public/views/elasticsearch/node/get_page_data.js similarity index 84% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/get_page_data.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/node/get_page_data.js index 0d9e0b25eacd0..6aaa8aa452f68 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/node/get_page_data.js @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { Legacy } from '../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); @@ -14,7 +14,7 @@ export function getPageData($injector) { const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/elasticsearch/nodes/${$route.current.params.node}`; const features = $injector.get('features'); const showSystemIndices = features.isEnabled('showSystemIndices', false); - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/node/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.js similarity index 84% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/node/index.js index fa76222d78e2d..c34be490d1711 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/node/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/node/index.js @@ -10,12 +10,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { partial } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { getPageData } from './get_page_data'; import template from './index.html'; import { Node } from '../../../components/elasticsearch/node/node'; -import { I18nContext } from 'ui/i18n'; import { labels } from '../../../components/elasticsearch/shard_allocation/lib/labels'; import { nodesByIndices } from '../../../components/elasticsearch/shard_allocation/transformers/nodes_by_indices'; import { MonitoringViewBaseController } from '../../base_controller'; @@ -79,17 +78,15 @@ uiRoutes.when('/elasticsearch/nodes/:node', { $scope.labels = labels.node; this.renderReact( - - - + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/nodes/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/nodes/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/nodes/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.js similarity index 74% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/nodes/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.js index a9a6774d4c883..db4aaca15c00e 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/nodes/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/nodes/index.js @@ -7,13 +7,12 @@ import React, { Fragment } from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { Legacy } from '../../../legacy_shims'; import template from './index.html'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseEuiTableController } from '../../'; import { ElasticsearchNodes } from '../../../components'; -import { I18nContext } from 'ui/i18n'; import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; import { SetupModeRenderer } from '../../../components/renderers'; import { ELASTICSEARCH_SYSTEM_ID, CODE_PATH_ELASTICSEARCH } from '../../../../common/constants'; @@ -42,7 +41,7 @@ uiRoutes.when('/elasticsearch/nodes', { _api; // to fix eslint const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); const getNodes = (clusterUuid = globalState.cluster_uuid) => $http.post(`../api/monitoring/v1/clusters/${clusterUuid}/elasticsearch/nodes`, { @@ -91,27 +90,25 @@ uiRoutes.when('/elasticsearch/nodes', { }; super.renderReact( - - ( - - {flyoutComponent} - - {bottomBarComponent} - - )} - /> - + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> ); }; } diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/overview/controller.js b/x-pack/plugins/monitoring/public/views/elasticsearch/overview/controller.js similarity index 83% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/overview/controller.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/overview/controller.js index 9f59b4d632222..7cdd7dfae0af0 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/overview/controller.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/overview/controller.js @@ -7,8 +7,7 @@ import React from 'react'; import { find } from 'lodash'; import { MonitoringViewBaseController } from '../../'; -import { ElasticsearchOverview } from 'plugins/monitoring/components'; -import { I18nContext } from 'ui/i18n'; +import { ElasticsearchOverview } from '../../../components'; export class ElasticsearchOverviewController extends MonitoringViewBaseController { constructor($injector, $scope) { @@ -78,19 +77,17 @@ export class ElasticsearchOverviewController extends MonitoringViewBaseControlle const { clusterStatus, metrics, shardActivity, logs } = data; const shardActivityData = shardActivity && this.filterShardActivityData(shardActivity); // no filter on data = null const component = ( - - - + ); super.renderReact(component); diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/overview/index.html b/x-pack/plugins/monitoring/public/views/elasticsearch/overview/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/overview/index.html rename to x-pack/plugins/monitoring/public/views/elasticsearch/overview/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/overview/index.js b/x-pack/plugins/monitoring/public/views/elasticsearch/overview/index.js similarity index 84% rename from x-pack/legacy/plugins/monitoring/public/views/elasticsearch/overview/index.js rename to x-pack/plugins/monitoring/public/views/elasticsearch/overview/index.js index 475c0fc494857..1c27a4d004abe 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/elasticsearch/overview/index.js +++ b/x-pack/plugins/monitoring/public/views/elasticsearch/overview/index.js @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; import { ElasticsearchOverviewController } from './controller'; import { CODE_PATH_ELASTICSEARCH } from '../../../../common/constants'; diff --git a/x-pack/legacy/plugins/monitoring/public/views/index.js b/x-pack/plugins/monitoring/public/views/index.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/index.js rename to x-pack/plugins/monitoring/public/views/index.js diff --git a/x-pack/legacy/plugins/monitoring/public/views/kibana/instance/index.html b/x-pack/plugins/monitoring/public/views/kibana/instance/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/kibana/instance/index.html rename to x-pack/plugins/monitoring/public/views/kibana/instance/index.html diff --git a/x-pack/plugins/monitoring/public/views/kibana/instance/index.js b/x-pack/plugins/monitoring/public/views/kibana/instance/index.js new file mode 100644 index 0000000000000..b743b4e49f096 --- /dev/null +++ b/x-pack/plugins/monitoring/public/views/kibana/instance/index.js @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/* + * Kibana Instance + */ +import React from 'react'; +import { get } from 'lodash'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../lib/route_init'; +import template from './index.html'; +import { Legacy } from '../../../legacy_shims'; +import { + EuiPage, + EuiPageBody, + EuiPageContent, + EuiSpacer, + EuiFlexGrid, + EuiFlexItem, + EuiPanel, +} from '@elastic/eui'; +import { MonitoringTimeseriesContainer } from '../../../components/chart'; +import { DetailStatus } from '../../../components/kibana/detail_status'; +import { MonitoringViewBaseController } from '../../base_controller'; +import { CODE_PATH_KIBANA } from '../../../../common/constants'; + +function getPageData($injector) { + const $http = $injector.get('$http'); + const globalState = $injector.get('globalState'); + const $route = $injector.get('$route'); + const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/kibana/${$route.current.params.uuid}`; + const timeBounds = Legacy.shims.timefilter.getBounds(); + + return $http + .post(url, { + ccs: globalState.ccs, + timeRange: { + min: timeBounds.min.toISOString(), + max: timeBounds.max.toISOString(), + }, + }) + .then(response => response.data) + .catch(err => { + const Private = $injector.get('Private'); + const ajaxErrorHandlers = Private(ajaxErrorHandlersProvider); + return ajaxErrorHandlers(err); + }); +} + +uiRoutes.when('/kibana/instances/:uuid', { + template, + resolve: { + clusters(Private) { + const routeInit = Private(routeInitProvider); + return routeInit({ codePaths: [CODE_PATH_KIBANA] }); + }, + pageData: getPageData, + }, + controllerAs: 'monitoringKibanaInstanceApp', + controller: class extends MonitoringViewBaseController { + constructor($injector, $scope) { + super({ + title: `Kibana - ${get($scope.pageData, 'kibanaSummary.name')}`, + defaultData: {}, + getPageData, + reactNodeId: 'monitoringKibanaInstanceApp', + $scope, + $injector, + }); + + $scope.$watch( + () => this.data, + data => { + if (!data || !data.metrics) { + return; + } + + this.setTitle(`Kibana - ${get(data, 'kibanaSummary.name')}`); + + this.renderReact( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } + ); + } + }, +}); diff --git a/x-pack/legacy/plugins/monitoring/public/views/kibana/instances/get_page_data.js b/x-pack/plugins/monitoring/public/views/kibana/instances/get_page_data.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/views/kibana/instances/get_page_data.js rename to x-pack/plugins/monitoring/public/views/kibana/instances/get_page_data.js index 4f8d7fa20d332..9f78bd07ecbf8 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/kibana/instances/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/kibana/instances/get_page_data.js @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { Legacy } from '../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/kibana/instances`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { diff --git a/x-pack/legacy/plugins/monitoring/public/views/kibana/instances/index.html b/x-pack/plugins/monitoring/public/views/kibana/instances/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/kibana/instances/index.html rename to x-pack/plugins/monitoring/public/views/kibana/instances/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/kibana/instances/index.js b/x-pack/plugins/monitoring/public/views/kibana/instances/index.js similarity index 56% rename from x-pack/legacy/plugins/monitoring/public/views/kibana/instances/index.js rename to x-pack/plugins/monitoring/public/views/kibana/instances/index.js index 51a7e033bd0d6..d179928ded693 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/kibana/instances/index.js +++ b/x-pack/plugins/monitoring/public/views/kibana/instances/index.js @@ -5,14 +5,13 @@ */ import React, { Fragment } from 'react'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseEuiTableController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; -import { KibanaInstances } from 'plugins/monitoring/components/kibana/instances'; +import { KibanaInstances } from '../../../components/kibana/instances'; import { SetupModeRenderer } from '../../../components/renderers'; -import { I18nContext } from 'ui/i18n'; import { KIBANA_SYSTEM_ID, CODE_PATH_KIBANA } from '../../../../common/constants'; uiRoutes.when('/kibana/instances', { @@ -40,31 +39,29 @@ uiRoutes.when('/kibana/instances', { const renderReact = () => { this.renderReact( - - ( - - {flyoutComponent} - - {bottomBarComponent} - - )} - /> - + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> ); }; diff --git a/x-pack/legacy/plugins/monitoring/public/views/kibana/overview/index.html b/x-pack/plugins/monitoring/public/views/kibana/overview/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/kibana/overview/index.html rename to x-pack/plugins/monitoring/public/views/kibana/overview/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/kibana/overview/index.js b/x-pack/plugins/monitoring/public/views/kibana/overview/index.js similarity index 58% rename from x-pack/legacy/plugins/monitoring/public/views/kibana/overview/index.js rename to x-pack/plugins/monitoring/public/views/kibana/overview/index.js index 0705e3b7f270b..b0be4f7862a91 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/kibana/overview/index.js +++ b/x-pack/plugins/monitoring/public/views/kibana/overview/index.js @@ -8,12 +8,12 @@ * Kibana Overview */ import React from 'react'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; +import { uiRoutes } from '../../../angular/helpers/routes'; import { MonitoringTimeseriesContainer } from '../../../components/chart'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { Legacy } from '../../../legacy_shims'; import { EuiPage, EuiPageBody, @@ -24,7 +24,6 @@ import { EuiFlexItem, } from '@elastic/eui'; import { ClusterStatus } from '../../../components/kibana/cluster_status'; -import { I18nContext } from 'ui/i18n'; import { MonitoringViewBaseController } from '../../base_controller'; import { CODE_PATH_KIBANA } from '../../../../common/constants'; @@ -32,7 +31,7 @@ function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/kibana`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { @@ -79,34 +78,32 @@ uiRoutes.when('/kibana', { } this.renderReact( - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/license/controller.js b/x-pack/plugins/monitoring/public/views/license/controller.js similarity index 71% rename from x-pack/legacy/plugins/monitoring/public/views/license/controller.js rename to x-pack/plugins/monitoring/public/views/license/controller.js index ce6e9c8fb74cd..1d6a179db98c4 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/license/controller.js +++ b/x-pack/plugins/monitoring/public/views/license/controller.js @@ -8,19 +8,17 @@ import { get, find } from 'lodash'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; -import chrome from 'plugins/monitoring/np_imports/ui/chrome'; +import { Legacy } from '../../legacy_shims'; import { formatDateTimeLocal } from '../../../common/formatting'; -import { MANAGEMENT_BASE_PATH } from 'plugins/xpack_main/components'; -import { License } from 'plugins/monitoring/components'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { I18nContext } from 'ui/i18n'; +import { BASE_PATH as MANAGEMENT_BASE_PATH } from '../../../../../plugins/license_management/common/constants'; +import { License } from '../../components'; const REACT_NODE_ID = 'licenseReact'; export class LicenseViewController { constructor($injector, $scope) { - timefilter.disableTimeRangeSelector(); - timefilter.disableAutoRefreshSelector(); + Legacy.shims.timefilter.disableTimeRangeSelector(); + Legacy.shims.timefilter.disableAutoRefreshSelector(); $scope.$on('$destroy', () => { unmountComponentAtNode(document.getElementById(REACT_NODE_ID)); @@ -47,14 +45,14 @@ export class LicenseViewController { this.isExpired = Date.now() > get(cluster, 'license.expiry_date_in_millis'); this.isPrimaryCluster = cluster.isPrimary; - const basePath = chrome.getBasePath(); + const basePath = Legacy.shims.getBasePath(); this.uploadLicensePath = basePath + '/app/kibana#' + MANAGEMENT_BASE_PATH + 'upload_license'; this.renderReact($scope); } renderReact($scope) { - const injector = chrome.dangerouslyGetActiveInjector(); + const injector = Legacy.shims.getAngularInjector(); const timezone = injector.get('config').get('dateFormat:tz'); $scope.$evalAsync(() => { const { isPrimaryCluster, license, isExpired, uploadLicensePath } = this; @@ -65,16 +63,14 @@ export class LicenseViewController { // Mount the React component to the template render( - - - , + , document.getElementById(REACT_NODE_ID) ); }); diff --git a/x-pack/legacy/plugins/monitoring/public/views/license/index.html b/x-pack/plugins/monitoring/public/views/license/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/license/index.html rename to x-pack/plugins/monitoring/public/views/license/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/license/index.js b/x-pack/plugins/monitoring/public/views/license/index.js similarity index 83% rename from x-pack/legacy/plugins/monitoring/public/views/license/index.js rename to x-pack/plugins/monitoring/public/views/license/index.js index e0796c85d8f85..46e93a8f01f45 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/license/index.js +++ b/x-pack/plugins/monitoring/public/views/license/index.js @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../angular/helpers/routes'; +import { routeInitProvider } from '../../lib/route_init'; import template from './index.html'; import { LicenseViewController } from './controller'; import { CODE_PATH_LICENSE } from '../../../common/constants'; diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/advanced/index.html b/x-pack/plugins/monitoring/public/views/logstash/node/advanced/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/node/advanced/index.html rename to x-pack/plugins/monitoring/public/views/logstash/node/advanced/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/advanced/index.js b/x-pack/plugins/monitoring/public/views/logstash/node/advanced/index.js similarity index 65% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/node/advanced/index.js rename to x-pack/plugins/monitoring/public/views/logstash/node/advanced/index.js index 29cf4839eff94..4099a99f122f2 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/advanced/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/node/advanced/index.js @@ -9,13 +9,13 @@ */ import React from 'react'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../../angular/helpers/routes'; +import { ajaxErrorHandlersProvider } from '../../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../../lib/route_init'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { Legacy } from '../../../../legacy_shims'; import { MonitoringViewBaseController } from '../../../base_controller'; -import { DetailStatus } from 'plugins/monitoring/components/logstash/detail_status'; +import { DetailStatus } from '../../../../components/logstash/detail_status'; import { EuiPage, EuiPageBody, @@ -26,7 +26,6 @@ import { EuiFlexItem, } from '@elastic/eui'; import { MonitoringTimeseriesContainer } from '../../../../components/chart'; -import { I18nContext } from 'ui/i18n'; import { CODE_PATH_LOGSTASH } from '../../../../../common/constants'; function getPageData($injector) { @@ -34,7 +33,7 @@ function getPageData($injector) { const globalState = $injector.get('globalState'); const $route = $injector.get('$route'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/logstash/node/${$route.current.params.uuid}`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { @@ -97,31 +96,29 @@ uiRoutes.when('/logstash/node/:uuid/advanced', { ]; this.renderReact( - - - - - - - - - - {metricsToShow.map((metric, index) => ( - - - - - ))} - - - - - + + + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/index.html b/x-pack/plugins/monitoring/public/views/logstash/node/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/node/index.html rename to x-pack/plugins/monitoring/public/views/logstash/node/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/index.js b/x-pack/plugins/monitoring/public/views/logstash/node/index.js similarity index 65% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/node/index.js rename to x-pack/plugins/monitoring/public/views/logstash/node/index.js index f1777d1e46ef0..141761d8cc11a 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/node/index.js @@ -9,12 +9,12 @@ */ import React from 'react'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { DetailStatus } from 'plugins/monitoring/components/logstash/detail_status'; +import { Legacy } from '../../../legacy_shims'; +import { DetailStatus } from '../../../components/logstash/detail_status'; import { EuiPage, EuiPageBody, @@ -25,7 +25,6 @@ import { EuiFlexItem, } from '@elastic/eui'; import { MonitoringTimeseriesContainer } from '../../../components/chart'; -import { I18nContext } from 'ui/i18n'; import { MonitoringViewBaseController } from '../../base_controller'; import { CODE_PATH_LOGSTASH } from '../../../../common/constants'; @@ -34,7 +33,7 @@ function getPageData($injector) { const $route = $injector.get('$route'); const globalState = $injector.get('globalState'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/logstash/node/${$route.current.params.uuid}`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { @@ -98,31 +97,29 @@ uiRoutes.when('/logstash/node/:uuid', { ]; this.renderReact( - - - - - - - - - - {metricsToShow.map((metric, index) => ( - - - - - ))} - - - - - + + + + + + + + + {metricsToShow.map((metric, index) => ( + + + + + ))} + + + + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/pipelines/index.html b/x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/node/pipelines/index.html rename to x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/pipelines/index.js b/x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.js similarity index 74% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/node/pipelines/index.js rename to x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.js index 017988b70bdd4..442e8533c18f6 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/logstash/node/pipelines/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/node/pipelines/index.js @@ -10,14 +10,13 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { isPipelineMonitoringSupportedInVersion } from 'plugins/monitoring/lib/logstash/pipelines'; +import { uiRoutes } from '../../../../angular/helpers/routes'; +import { ajaxErrorHandlersProvider } from '../../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../../lib/route_init'; +import { isPipelineMonitoringSupportedInVersion } from '../../../../lib/logstash/pipelines'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { Legacy } from '../../../../legacy_shims'; import { MonitoringViewBaseEuiTableController } from '../../../'; -import { I18nContext } from 'ui/i18n'; import { PipelineListing } from '../../../../components/logstash/pipeline_listing/pipeline_listing'; import { DetailStatus } from '../../../../components/logstash/detail_status'; import { CODE_PATH_LOGSTASH } from '../../../../../common/constants'; @@ -31,7 +30,7 @@ const getPageData = ($injector, _api = undefined, routeOptions = {}) => { const logstashUuid = $route.current.params.uuid; const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/logstash/node/${logstashUuid}/pipelines`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { @@ -107,23 +106,21 @@ uiRoutes.when('/logstash/node/:uuid/pipelines', { }; this.renderReact( - - - + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/nodes/get_page_data.js b/x-pack/plugins/monitoring/public/views/logstash/nodes/get_page_data.js similarity index 80% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/nodes/get_page_data.js rename to x-pack/plugins/monitoring/public/views/logstash/nodes/get_page_data.js index d476f6ba5143e..1d5d6007814f4 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/logstash/nodes/get_page_data.js +++ b/x-pack/plugins/monitoring/public/views/logstash/nodes/get_page_data.js @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { Legacy } from '../../../legacy_shims'; export function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/logstash/nodes`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/nodes/index.html b/x-pack/plugins/monitoring/public/views/logstash/nodes/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/nodes/index.html rename to x-pack/plugins/monitoring/public/views/logstash/nodes/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/nodes/index.js b/x-pack/plugins/monitoring/public/views/logstash/nodes/index.js similarity index 57% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/nodes/index.js rename to x-pack/plugins/monitoring/public/views/logstash/nodes/index.js index 30f851b2a7534..49b2a20f11ea2 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/logstash/nodes/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/nodes/index.js @@ -4,12 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ import React, { Fragment } from 'react'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { routeInitProvider } from '../../../lib/route_init'; import { MonitoringViewBaseEuiTableController } from '../../'; import { getPageData } from './get_page_data'; import template from './index.html'; -import { I18nContext } from 'ui/i18n'; import { Listing } from '../../../components/logstash/listing'; import { SetupModeRenderer } from '../../../components/renderers'; import { CODE_PATH_LOGSTASH, LOGSTASH_SYSTEM_ID } from '../../../../common/constants'; @@ -41,28 +40,26 @@ uiRoutes.when('/logstash/nodes', { () => this.data, data => { this.renderReact( - - ( - - {flyoutComponent} - - {bottomBarComponent} - - )} - /> - + ( + + {flyoutComponent} + + {bottomBarComponent} + + )} + /> ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/overview/index.html b/x-pack/plugins/monitoring/public/views/logstash/overview/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/overview/index.html rename to x-pack/plugins/monitoring/public/views/logstash/overview/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/overview/index.js b/x-pack/plugins/monitoring/public/views/logstash/overview/index.js similarity index 73% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/overview/index.js rename to x-pack/plugins/monitoring/public/views/logstash/overview/index.js index f41f54555952e..05b1747f4cfff 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/logstash/overview/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/overview/index.js @@ -8,12 +8,11 @@ * Logstash Overview */ import React from 'react'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../lib/route_init'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { I18nContext } from 'ui/i18n'; +import { Legacy } from '../../../legacy_shims'; import { Overview } from '../../../components/logstash/overview'; import { MonitoringViewBaseController } from '../../base_controller'; import { CODE_PATH_LOGSTASH } from '../../../../common/constants'; @@ -22,7 +21,7 @@ function getPageData($injector) { const $http = $injector.get('$http'); const globalState = $injector.get('globalState'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/logstash`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { @@ -63,14 +62,12 @@ uiRoutes.when('/logstash', { () => this.data, data => { this.renderReact( - - - + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/pipeline/index.html b/x-pack/plugins/monitoring/public/views/logstash/pipeline/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/pipeline/index.html rename to x-pack/plugins/monitoring/public/views/logstash/pipeline/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/pipeline/index.js b/x-pack/plugins/monitoring/public/views/logstash/pipeline/index.js similarity index 77% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/pipeline/index.js rename to x-pack/plugins/monitoring/public/views/logstash/pipeline/index.js index 11cb8516847c8..0dd24d68540ce 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/logstash/pipeline/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/pipeline/index.js @@ -8,21 +8,20 @@ * Logstash Node Pipeline View */ import React from 'react'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; +import { uiRoutes } from '../../../angular/helpers/routes'; import moment from 'moment'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../lib/route_init'; import { CALCULATE_DURATION_SINCE, CODE_PATH_LOGSTASH } from '../../../../common/constants'; import { formatTimestampToDuration } from '../../../../common/format_timestamp_to_duration'; import template from './index.html'; import { i18n } from '@kbn/i18n'; -import { List } from 'plugins/monitoring/components/logstash/pipeline_viewer/models/list'; -import { PipelineState } from 'plugins/monitoring/components/logstash/pipeline_viewer/models/pipeline_state'; -import { PipelineViewer } from 'plugins/monitoring/components/logstash/pipeline_viewer'; -import { Pipeline } from 'plugins/monitoring/components/logstash/pipeline_viewer/models/pipeline'; -import { vertexFactory } from 'plugins/monitoring/components/logstash/pipeline_viewer/models/graph/vertex_factory'; +import { List } from '../../../components/logstash/pipeline_viewer/models/list'; +import { PipelineState } from '../../../components/logstash/pipeline_viewer/models/pipeline_state'; +import { PipelineViewer } from '../../../components/logstash/pipeline_viewer'; +import { Pipeline } from '../../../components/logstash/pipeline_viewer/models/pipeline'; +import { vertexFactory } from '../../../components/logstash/pipeline_viewer/models/graph/vertex_factory'; import { MonitoringViewBaseController } from '../../base_controller'; -import { I18nContext } from 'ui/i18n'; import { EuiPageBody, EuiPage, EuiPageContent } from '@elastic/eui'; let previousPipelineHash = undefined; @@ -146,22 +145,20 @@ uiRoutes.when('/logstash/pipelines/:id/:hash?', { this.pipelineState = new PipelineState(data.pipeline); this.detailVertex = data.vertex ? vertexFactory(null, data.vertex) : null; this.renderReact( - - - - - - - - - + + + + + + + ); } ); diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/pipelines/index.html b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/pipelines/index.html rename to x-pack/plugins/monitoring/public/views/logstash/pipelines/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/logstash/pipelines/index.js b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js similarity index 75% rename from x-pack/legacy/plugins/monitoring/public/views/logstash/pipelines/index.js rename to x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js index 75a18000c14dd..4ddaba1e0a7c9 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/logstash/pipelines/index.js +++ b/x-pack/plugins/monitoring/public/views/logstash/pipelines/index.js @@ -7,13 +7,12 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { find } from 'lodash'; -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; -import { ajaxErrorHandlersProvider } from 'plugins/monitoring/lib/ajax_error_handler'; -import { routeInitProvider } from 'plugins/monitoring/lib/route_init'; -import { isPipelineMonitoringSupportedInVersion } from 'plugins/monitoring/lib/logstash/pipelines'; +import { uiRoutes } from '../../../angular/helpers/routes'; +import { ajaxErrorHandlersProvider } from '../../../lib/ajax_error_handler'; +import { routeInitProvider } from '../../../lib/route_init'; +import { isPipelineMonitoringSupportedInVersion } from '../../../lib/logstash/pipelines'; import template from './index.html'; -import { timefilter } from 'plugins/monitoring/np_imports/ui/timefilter'; -import { I18nContext } from 'ui/i18n'; +import { Legacy } from '../../../legacy_shims'; import { PipelineListing } from '../../../components/logstash/pipeline_listing/pipeline_listing'; import { MonitoringViewBaseEuiTableController } from '../..'; import { CODE_PATH_LOGSTASH } from '../../../../common/constants'; @@ -29,7 +28,7 @@ const getPageData = ($injector, _api = undefined, routeOptions = {}) => { const Private = $injector.get('Private'); const url = `../api/monitoring/v1/clusters/${globalState.cluster_uuid}/logstash/pipelines`; - const timeBounds = timefilter.getBounds(); + const timeBounds = Legacy.shims.timefilter.getBounds(); return $http .post(url, { @@ -103,21 +102,19 @@ uiRoutes.when('/logstash/pipelines', { }; super.renderReact( - - this.onBrush({ xaxis })} - stats={pageData.clusterStatus} - data={pageData.pipelines} - {...this.getPaginationTableProps(pagination)} - upgradeMessage={upgradeMessage} - dateFormat={config.get('dateFormat')} - angular={{ - kbnUrl, - scope: $scope, - }} - /> - + this.onBrush({ xaxis })} + stats={pageData.clusterStatus} + data={pageData.pipelines} + {...this.getPaginationTableProps(pagination)} + upgradeMessage={upgradeMessage} + dateFormat={config.get('dateFormat')} + angular={{ + kbnUrl, + scope: $scope, + }} + /> ); }; diff --git a/x-pack/legacy/plugins/monitoring/public/views/no_data/__tests__/model_updater.test.js b/x-pack/plugins/monitoring/public/views/no_data/__tests__/model_updater.test.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/no_data/__tests__/model_updater.test.js rename to x-pack/plugins/monitoring/public/views/no_data/__tests__/model_updater.test.js diff --git a/x-pack/legacy/plugins/monitoring/public/views/no_data/controller.js b/x-pack/plugins/monitoring/public/views/no_data/controller.js similarity index 87% rename from x-pack/legacy/plugins/monitoring/public/views/no_data/controller.js rename to x-pack/plugins/monitoring/public/views/no_data/controller.js index a914aa0155e90..14c30da2ce999 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/no_data/controller.js +++ b/x-pack/plugins/monitoring/public/views/no_data/controller.js @@ -10,17 +10,17 @@ import { NodeSettingsChecker, Enabler, startChecks, -} from 'plugins/monitoring/lib/elasticsearch_settings'; +} from '../../lib/elasticsearch_settings'; import { ModelUpdater } from './model_updater'; -import { NoData } from 'plugins/monitoring/components'; -import { I18nContext } from 'ui/i18n'; +import { NoData } from '../../components'; import { CODE_PATH_LICENSE } from '../../../common/constants'; import { MonitoringViewBaseController } from '../base_controller'; import { i18n } from '@kbn/i18n'; -import { npSetup } from 'ui/new_platform'; +import { Legacy } from '../../legacy_shims'; export class NoDataController extends MonitoringViewBaseController { constructor($injector, $scope) { + window.injectorThree = $injector; const monitoringClusters = $injector.get('monitoringClusters'); const kbnUrl = $injector.get('kbnUrl'); const $http = $injector.get('$http'); @@ -99,18 +99,13 @@ export class NoDataController extends MonitoringViewBaseController { render(enabler) { const props = this; - const { cloud } = npSetup.plugins; - const isCloudEnabled = !!(cloud && cloud.isCloudEnabled); - this.renderReact( - - - + ); } } diff --git a/x-pack/legacy/plugins/monitoring/public/views/no_data/index.html b/x-pack/plugins/monitoring/public/views/no_data/index.html similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/no_data/index.html rename to x-pack/plugins/monitoring/public/views/no_data/index.html diff --git a/x-pack/legacy/plugins/monitoring/public/views/no_data/index.js b/x-pack/plugins/monitoring/public/views/no_data/index.js similarity index 63% rename from x-pack/legacy/plugins/monitoring/public/views/no_data/index.js rename to x-pack/plugins/monitoring/public/views/no_data/index.js index edade513e5ab2..9876739dfcbbe 100644 --- a/x-pack/legacy/plugins/monitoring/public/views/no_data/index.js +++ b/x-pack/plugins/monitoring/public/views/no_data/index.js @@ -4,13 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import uiRoutes from 'plugins/monitoring/np_imports/ui/routes'; +import { uiRoutes } from '../../angular/helpers/routes'; import template from './index.html'; import { NoDataController } from './controller'; -uiRoutes - .when('/no-data', { - template, - controller: NoDataController, - }) - .otherwise({ redirectTo: '/home' }); +uiRoutes.when('/no-data', { + template, + controller: NoDataController, +}); diff --git a/x-pack/legacy/plugins/monitoring/public/views/no_data/model_updater.js b/x-pack/plugins/monitoring/public/views/no_data/model_updater.js similarity index 100% rename from x-pack/legacy/plugins/monitoring/public/views/no_data/model_updater.js rename to x-pack/plugins/monitoring/public/views/no_data/model_updater.js diff --git a/x-pack/plugins/monitoring/server/index.ts b/x-pack/plugins/monitoring/server/index.ts index a992037fc6087..60f04c535ebf1 100644 --- a/x-pack/plugins/monitoring/server/index.ts +++ b/x-pack/plugins/monitoring/server/index.ts @@ -10,8 +10,14 @@ import { Plugin } from './plugin'; import { configSchema } from './config'; import { deprecations } from './deprecations'; +export { MonitoringConfig } from './config'; export const plugin = (initContext: PluginInitializerContext) => new Plugin(initContext); export const config: PluginConfigDescriptor> = { schema: configSchema, deprecations, + exposeToBrowser: { + enabled: true, + ui: true, + kibana: true, + }, }; diff --git a/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts b/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts index 90187b7853185..3df2b015aa034 100644 --- a/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts +++ b/x-pack/plugins/spaces/server/usage_collection/spaces_usage_collector.ts @@ -8,7 +8,7 @@ import { CallAPIOptions } from 'src/core/server'; import { take } from 'rxjs/operators'; import { UsageCollectionSetup } from 'src/plugins/usage_collection/server'; import { Observable } from 'rxjs'; -import { KIBANA_STATS_TYPE_MONITORING } from '../../../../legacy/plugins/monitoring/common/constants'; +import { KIBANA_STATS_TYPE_MONITORING } from '../../../monitoring/common/constants'; import { KIBANA_SPACES_STATS_TYPE } from '../../common/constants'; import { PluginsSetup } from '../plugin'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index bf257d66a59bc..4cd152f2d297d 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -11921,7 +11921,6 @@ "xpack.monitoring.metrics.logstashInstance.systemLoad.last5MinutesDescription": "過去 5 分間の平均負荷です。", "xpack.monitoring.metrics.logstashInstance.systemLoad.last5MinutesLabel": "5m", "xpack.monitoring.monitoringDescription": "Elastic Stack のリアルタイムのヘルスとパフォーマンスをトラッキングします。", - "xpack.monitoring.monitoringTitle": "Monitoring", "xpack.monitoring.noData.blurbs.changesNeededDescription": "監視を実行するには、次の手順に従います", "xpack.monitoring.noData.blurbs.changesNeededTitle": "調整が必要です", "xpack.monitoring.noData.blurbs.cloudDeploymentDescription": "次の場所に戻ってください: ", @@ -12001,7 +12000,6 @@ "xpack.monitoring.summaryStatus.statusDescription": "ステータス", "xpack.monitoring.summaryStatus.statusIconLabel": "ステータス: {status}", "xpack.monitoring.summaryStatus.statusIconTitle": "ステータス: {statusIcon}", - "xpack.monitoring.uiExportsDescription": "Elastic Stack の監視です", "xpack.painlessLab.apiReferenceButtonLabel": "API リファレンス", "xpack.painlessLab.context.defaultLabel": "スクリプト結果は文字列に変換されます", "xpack.painlessLab.context.filterLabel": "フィルターのスクリプトクエリのコンテキストを使用する", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 323ddfda32d70..619ea0646eb44 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -11925,7 +11925,6 @@ "xpack.monitoring.metrics.logstashInstance.systemLoad.last5MinutesDescription": "过去 5 分钟的负载平均值。", "xpack.monitoring.metrics.logstashInstance.systemLoad.last5MinutesLabel": "5 分钟", "xpack.monitoring.monitoringDescription": "跟踪 Elastic Stack 的实时运行状况和性能。", - "xpack.monitoring.monitoringTitle": "Monitoring", "xpack.monitoring.noData.blurbs.changesNeededDescription": "要运行 Monitoring,请执行以下步骤", "xpack.monitoring.noData.blurbs.changesNeededTitle": "您需要做些调整", "xpack.monitoring.noData.blurbs.cloudDeploymentDescription": "请返回到您的 ", @@ -12005,7 +12004,6 @@ "xpack.monitoring.summaryStatus.statusDescription": "状态", "xpack.monitoring.summaryStatus.statusIconLabel": "状态:{status}", "xpack.monitoring.summaryStatus.statusIconTitle": "状态:{statusIcon}", - "xpack.monitoring.uiExportsDescription": "Elastic Stack 的 Monitoring 组件", "xpack.painlessLab.apiReferenceButtonLabel": "API 参考", "xpack.painlessLab.context.defaultLabel": "脚本结果将转换成字符串", "xpack.painlessLab.context.filterLabel": "使用筛选脚本查询的上下文", From 16ba937bae63c9925b80285ad076325ee1a63569 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Thu, 30 Apr 2020 13:08:50 -0700 Subject: [PATCH 04/10] [APM] Client new platform migration (#64046) * migrate files from legacy path to new plugin path * update file paths to reflect migrated files * move minimal legacy client files back to legacy path in order to run kibana * Completes the full cutover to the new kibana platform removing all shims and legacy adapters. * Adds APM to ignored list for casing check. * - moves public/utils/pickKeys.ts to common/utils/pick_keys.ts - exposes getTraceUrl as a plugin static export of apm/public and updates import in infra - fixes FeaturesPluginSetup import in apm/public app - renames get_apm_index_pattern_titles -> get_apm_index_pattern_title - getApmIndexPatternTitle is now a synchronous getter function - removes unused comments and xpack.apm.apmForESDescription i18n translations * Moves automatic index pattern saved object creation from plugin start to when the Home screen first renders * removed unnecessary legacy css imports * fixed ci issues by: - moving readOnly badge, and help extension setup to occure only when apm app is mounted - registering saved object types - also moved createStaticIndexPattern from a react useEffect on the APM home screen to when the app is mounted --- src/cli/cluster/cluster_manager.ts | 4 +- src/dev/precommit_hook/casing_check_config.js | 6 +- src/dev/run_check_lockfile_symlinks.js | 4 +- src/dev/storybook/aliases.ts | 2 +- src/dev/typescript/projects.ts | 2 +- x-pack/index.js | 2 - x-pack/legacy/plugins/apm/.prettierrc | 4 - .../apm/e2e/cypress/integration/snapshots.js | 10 - x-pack/legacy/plugins/apm/index.ts | 166 ---- x-pack/legacy/plugins/apm/mappings.json | 933 ------------------ x-pack/legacy/plugins/apm/public/index.scss | 16 - x-pack/legacy/plugins/apm/public/index.tsx | 36 - .../apm/public/legacy_register_feature.ts | 24 - .../getConfigFromInjectedMetadata.ts | 24 - .../plugins/apm/public/new-platform/index.tsx | 13 - .../apm/public/new-platform/plugin.tsx | 203 ---- .../apm/public/style/global_overrides.css | 34 - .../plugins/apm/public/templates/index.html | 1 - .../{legacy => }/plugins/apm/CONTRIBUTING.md | 0 .../apm/common/apm_saved_object_constants.ts | 2 +- .../apm/common/utils/pick_keys.ts} | 0 .../plugins/apm/dev_docs/github_commands.md | 0 .../plugins/apm/dev_docs/typescript.md | 4 +- .../plugins/apm/dev_docs/vscode_setup.md | 6 +- .../{legacy => }/plugins/apm/e2e/.gitignore | 0 x-pack/{legacy => }/plugins/apm/e2e/README.md | 6 +- .../plugins/apm/e2e/ci/Dockerfile | 0 .../plugins/apm/e2e/ci/entrypoint.sh | 4 +- .../plugins/apm/e2e/ci/kibana.e2e.yml | 0 .../plugins/apm/e2e/ci/prepare-kibana.sh | 2 +- .../{legacy => }/plugins/apm/e2e/cypress.json | 0 .../apm/e2e/cypress/fixtures/example.json | 0 .../apm/e2e/cypress/integration/apm.feature | 0 .../apm/e2e/cypress/integration/helpers.ts | 0 .../apm/e2e/cypress/integration/snapshots.js | 16 + .../plugins/apm/e2e/cypress/plugins/index.js | 0 .../apm/e2e/cypress/support/commands.js | 0 .../plugins/apm/e2e/cypress/support/index.ts | 0 .../cypress/support/step_definitions/apm.ts | 0 .../apm/e2e/cypress/typings/index.d.ts | 0 .../plugins/apm/e2e/cypress/webpack.config.js | 0 .../plugins/apm/e2e/ingest-data/replay.js | 0 .../{legacy => }/plugins/apm/e2e/package.json | 0 .../{legacy => }/plugins/apm/e2e/run-e2e.sh | 2 +- .../plugins/apm/e2e/tsconfig.json | 0 x-pack/{legacy => }/plugins/apm/e2e/yarn.lock | 0 x-pack/plugins/apm/kibana.json | 24 +- .../plugins/apm/public/application/index.tsx | 123 +++ .../__test__/APMIndicesPermission.test.tsx | 0 .../app/APMIndicesPermission/index.tsx | 0 .../DetailView/ErrorTabs.tsx | 2 +- .../DetailView/ExceptionStacktrace.test.tsx | 0 .../DetailView/ExceptionStacktrace.tsx | 2 +- .../__snapshots__/index.test.tsx.snap | 0 .../DetailView/index.test.tsx | 0 .../ErrorGroupDetails/DetailView/index.tsx | 4 +- .../ErrorGroupDetails/Distribution/index.tsx | 0 .../app/ErrorGroupDetails/index.tsx | 4 +- .../List/__test__/List.test.tsx | 0 .../__test__/__snapshots__/List.test.tsx.snap | 0 .../List/__test__/props.json | 0 .../app/ErrorGroupOverview/List/index.tsx | 4 +- .../app/ErrorGroupOverview/index.tsx | 4 +- .../public/components/app/Home/Home.test.tsx | 0 .../app/Home/__snapshots__/Home.test.tsx.snap | 2 - .../apm/public/components/app/Home/index.tsx | 0 .../app/Main/ProvideBreadcrumbs.tsx | 0 .../app/Main/ScrollToTopOnPathChange.tsx | 0 .../app/Main/UpdateBreadcrumbs.test.tsx | 0 .../components/app/Main/UpdateBreadcrumbs.tsx | 0 .../UpdateBreadcrumbs.test.tsx.snap | 0 .../Main/__test__/ProvideBreadcrumbs.test.tsx | 0 .../app/Main/route_config/index.tsx | 4 +- .../route_handlers/agent_configuration.tsx | 0 .../app/Main/route_config/route_names.tsx | 0 .../AlertingFlyout/index.tsx | 4 +- .../AlertIntegrations/index.tsx | 2 +- .../app/ServiceDetails/ServiceDetailTabs.tsx | 5 +- .../TransactionSelect.tsx | 0 .../MachineLearningFlyout/index.tsx | 2 +- .../MachineLearningFlyout/view.tsx | 0 .../ServiceIntegrations/WatcherFlyout.tsx | 71 +- .../createErrorGroupWatch.test.ts.snap | 0 .../__test__/createErrorGroupWatch.test.ts | 0 .../__test__/esResponse.ts | 0 .../createErrorGroupWatch.ts | 2 +- .../ServiceIntegrations/index.tsx | 0 .../components/app/ServiceDetails/index.tsx | 0 .../components/app/ServiceMap/BetaBadge.tsx | 0 .../components/app/ServiceMap/Controls.tsx | 0 .../app/ServiceMap/Cytoscape.stories.tsx | 0 .../components/app/ServiceMap/Cytoscape.tsx | 2 +- .../app/ServiceMap/EmptyBanner.test.tsx | 0 .../components/app/ServiceMap/EmptyBanner.tsx | 0 .../app/ServiceMap/LoadingOverlay.tsx | 0 .../app/ServiceMap/Popover/Buttons.tsx | 0 .../app/ServiceMap/Popover/Contents.tsx | 2 +- .../app/ServiceMap/Popover/Info.tsx | 2 +- .../ServiceMap/Popover/Popover.stories.tsx | 0 .../Popover/ServiceMetricFetcher.tsx | 2 +- .../ServiceMap/Popover/ServiceMetricList.tsx | 2 +- .../app/ServiceMap/Popover/index.tsx | 2 +- .../cytoscape-layout-test-response.json | 0 .../app/ServiceMap/cytoscapeOptions.ts | 2 +- .../public/components/app/ServiceMap/icons.ts | 4 +- .../components/app/ServiceMap/icons/aws.svg | 0 .../app/ServiceMap/icons/cassandra.svg | 0 .../components/app/ServiceMap/icons/dark.svg | 0 .../app/ServiceMap/icons/database.svg | 0 .../app/ServiceMap/icons/default.svg | 0 .../app/ServiceMap/icons/documents.svg | 0 .../app/ServiceMap/icons/dot-net.svg | 0 .../app/ServiceMap/icons/elasticsearch.svg | 0 .../components/app/ServiceMap/icons/globe.svg | 0 .../components/app/ServiceMap/icons/go.svg | 0 .../app/ServiceMap/icons/graphql.svg | 0 .../components/app/ServiceMap/icons/grpc.svg | 0 .../app/ServiceMap/icons/handlebars.svg | 0 .../components/app/ServiceMap/icons/java.svg | 0 .../components/app/ServiceMap/icons/kafka.svg | 0 .../app/ServiceMap/icons/mongodb.svg | 0 .../components/app/ServiceMap/icons/mysql.svg | 0 .../app/ServiceMap/icons/nodejs.svg | 0 .../components/app/ServiceMap/icons/php.svg | 0 .../app/ServiceMap/icons/postgresql.svg | 0 .../app/ServiceMap/icons/python.svg | 0 .../components/app/ServiceMap/icons/redis.svg | 0 .../components/app/ServiceMap/icons/ruby.svg | 0 .../components/app/ServiceMap/icons/rumjs.svg | 0 .../app/ServiceMap/icons/websocket.svg | 0 .../components/app/ServiceMap/index.test.tsx | 2 +- .../components/app/ServiceMap/index.tsx | 4 +- .../app/ServiceMap/useRefDimensions.ts | 0 .../components/app/ServiceMetrics/index.tsx | 2 +- .../app/ServiceNodeMetrics/index.test.tsx | 0 .../app/ServiceNodeMetrics/index.tsx | 2 +- .../app/ServiceNodeOverview/index.tsx | 6 +- .../app/ServiceOverview/NoServicesMessage.tsx | 0 .../ServiceList/__test__/List.test.js | 0 .../__test__/__snapshots__/List.test.js.snap | 0 .../ServiceList/__test__/props.json | 0 .../app/ServiceOverview/ServiceList/index.tsx | 4 +- .../__test__/NoServicesMessage.test.tsx | 0 .../__test__/ServiceOverview.test.tsx | 0 .../NoServicesMessage.test.tsx.snap | 0 .../ServiceOverview.test.tsx.snap | 0 .../components/app/ServiceOverview/index.tsx | 6 +- .../ServicePage/FormRowSelect.tsx | 0 .../ServicePage/ServicePage.tsx | 4 +- .../SettingsPage/SettingFormRow.tsx | 6 +- .../SettingsPage/SettingsPage.tsx | 10 +- .../SettingsPage/saveConfig.ts | 4 +- .../index.stories.tsx | 2 +- .../AgentConfigurationCreateEdit/index.tsx | 2 +- .../List/ConfirmDeleteModal.tsx | 4 +- .../AgentConfigurations/List/index.tsx | 4 +- .../Settings/AgentConfigurations/index.tsx | 2 +- .../app/Settings/ApmIndices/index.test.tsx | 0 .../app/Settings/ApmIndices/index.tsx | 0 .../CustomLink/CreateCustomLinkButton.tsx | 0 .../CustomLinkFlyout/DeleteButton.tsx | 0 .../CustomLinkFlyout/Documentation.tsx | 0 .../CustomLinkFlyout/FiltersSection.tsx | 2 +- .../CustomLinkFlyout/FlyoutFooter.tsx | 0 .../CustomLinkFlyout/LinkPreview.test.tsx | 0 .../CustomLinkFlyout/LinkPreview.tsx | 4 +- .../CustomLinkFlyout/LinkSection.tsx | 2 +- .../CustomLinkFlyout/helper.test.ts | 2 +- .../CustomLink/CustomLinkFlyout/helper.ts | 6 +- .../CustomLink/CustomLinkFlyout/index.tsx | 2 +- .../CustomLinkFlyout/saveCustomLink.ts | 2 +- .../CustomLink/CustomLinkTable.tsx | 2 +- .../CustomizeUI/CustomLink/EmptyPrompt.tsx | 0 .../Settings/CustomizeUI/CustomLink/Title.tsx | 0 .../CustomizeUI/CustomLink/index.test.tsx | 2 +- .../Settings/CustomizeUI/CustomLink/index.tsx | 2 +- .../app/Settings/CustomizeUI/index.tsx | 0 .../public/components/app/Settings/index.tsx | 0 .../app/TraceLink/__test__/TraceLink.test.tsx | 0 .../public/components/app/TraceLink/index.tsx | 4 +- .../app/TraceOverview/TraceList.tsx | 2 +- .../components/app/TraceOverview/index.tsx | 4 +- .../__test__/distribution.test.ts | 2 +- .../TransactionDetails/Distribution/index.tsx | 4 +- .../WaterfallWithSummmary/ErrorCount.tsx | 0 .../MaybeViewTraceLink.tsx | 2 +- .../WaterfallWithSummmary/PercentOfParent.tsx | 0 .../WaterfallWithSummmary/TransactionTabs.tsx | 2 +- .../Marks/__test__/get_agent_marks.test.ts | 2 +- .../Marks/__test__/get_error_marks.test.ts | 0 .../Marks/get_agent_marks.ts | 2 +- .../Marks/get_error_marks.ts | 2 +- .../WaterfallContainer/Marks/index.ts | 0 .../WaterfallContainer/ServiceLegends.tsx | 0 .../Waterfall/FlyoutTopLevelProperties.tsx | 4 +- .../Waterfall/ResponsiveFlyout.tsx | 0 .../Waterfall/SpanFlyout/DatabaseContext.tsx | 2 +- .../Waterfall/SpanFlyout/HttpContext.tsx | 2 +- .../SpanFlyout/StickySpanProperties.tsx | 8 +- .../SpanFlyout/TruncateHeightSection.tsx | 0 .../Waterfall/SpanFlyout/index.tsx | 4 +- .../Waterfall/SyncBadge.stories.tsx | 0 .../Waterfall/SyncBadge.tsx | 0 .../TransactionFlyout/DroppedSpansWarning.tsx | 2 +- .../Waterfall/TransactionFlyout/index.tsx | 2 +- .../Waterfall/WaterfallFlyout.tsx | 0 .../Waterfall/WaterfallItem.tsx | 4 +- .../WaterfallContainer/Waterfall/index.tsx | 0 .../waterfall_helpers.test.ts.snap | 0 .../mock_responses/spans.json | 0 .../mock_responses/transaction.json | 0 .../waterfall_helpers.test.ts | 6 +- .../waterfall_helpers/waterfall_helpers.ts | 8 +- .../WaterfallContainer.stories.tsx | 2 +- .../WaterfallContainer/index.tsx | 0 .../waterfallContainer.stories.data.ts | 0 .../__tests__/ErrorCount.test.tsx | 0 .../WaterfallWithSummmary/index.tsx | 2 +- .../app/TransactionDetails/index.tsx | 4 +- .../app/TransactionOverview/List/index.tsx | 4 +- .../__jest__/TransactionOverview.test.tsx | 0 .../app/TransactionOverview/index.tsx | 4 +- .../app/TransactionOverview/useRedirect.ts | 0 .../components/shared/ApmHeader/index.tsx | 0 .../DatePicker/__test__/DatePicker.test.tsx | 0 .../components/shared/DatePicker/index.tsx | 0 .../public/components/shared/EmptyMessage.tsx | 0 .../shared/EnvironmentBadge/index.tsx | 0 .../shared/EnvironmentFilter/index.tsx | 2 +- .../ErrorRateAlertTrigger/index.stories.tsx | 0 .../shared/ErrorRateAlertTrigger/index.tsx | 4 +- .../components/shared/ErrorStatePrompt.tsx | 0 .../public/components/shared/EuiTabLink.tsx | 0 .../shared/HeightRetainer/index.tsx | 0 .../ImpactBar/__test__/ImpactBar.test.js | 0 .../__snapshots__/ImpactBar.test.js.snap | 0 .../components/shared/ImpactBar/index.tsx | 0 .../shared/KeyValueTable/FormattedValue.tsx | 2 +- .../__test__/KeyValueTable.test.tsx | 0 .../components/shared/KeyValueTable/index.tsx | 0 .../shared/KueryBar/Typeahead/ClickOutside.js | 1 + .../shared/KueryBar/Typeahead/Suggestion.js | 0 .../shared/KueryBar/Typeahead/Suggestions.js | 0 .../shared/KueryBar/Typeahead/index.js | 0 .../shared/KueryBar/get_bool_filter.ts | 4 +- .../components/shared/KueryBar/index.tsx | 2 +- .../LicensePrompt/LicensePrompt.stories.tsx | 0 .../components/shared/LicensePrompt/index.tsx | 0 .../Links/DiscoverLinks/DiscoverErrorLink.tsx | 4 +- .../Links/DiscoverLinks/DiscoverLink.tsx | 2 +- .../Links/DiscoverLinks/DiscoverSpanLink.tsx | 4 +- .../DiscoverLinks/DiscoverTransactionLink.tsx | 4 +- .../__test__/DiscoverErrorButton.test.tsx | 2 +- .../__test__/DiscoverErrorLink.test.tsx | 2 +- .../DiscoverLinks.integration.test.tsx | 6 +- .../DiscoverTransactionButton.test.tsx | 2 +- .../__test__/DiscoverTransactionLink.test.tsx | 2 +- .../DiscoverErrorButton.test.tsx.snap | 0 .../DiscoverErrorLink.test.tsx.snap | 0 .../DiscoverTransactionButton.test.tsx.snap | 0 .../DiscoverTransactionLink.test.tsx.snap | 0 .../__test__/mockTransaction.json | 0 .../shared/Links/ElasticDocsLink.tsx | 0 .../shared/Links/InfraLink.test.tsx | 0 .../components/shared/Links/InfraLink.tsx | 2 +- .../shared/Links/KibanaLink.test.tsx | 0 .../components/shared/Links/KibanaLink.tsx | 0 .../MachineLearningLinks/MLJobLink.test.tsx | 0 .../Links/MachineLearningLinks/MLJobLink.tsx | 2 +- .../MachineLearningLinks/MLLink.test.tsx | 0 .../Links/MachineLearningLinks/MLLink.tsx | 0 .../shared/Links/SetupInstructionsLink.tsx | 0 .../shared/Links/apm/APMLink.test.tsx | 0 .../components/shared/Links/apm/APMLink.tsx | 0 .../shared/Links/apm/ErrorDetailLink.tsx | 0 .../shared/Links/apm/ErrorOverviewLink.tsx | 2 +- .../shared/Links/apm/ExternalLinks.test.ts | 0 .../shared/Links/apm/ExternalLinks.ts | 0 .../components/shared/Links/apm/HomeLink.tsx | 0 .../shared/Links/apm/MetricOverviewLink.tsx | 2 +- .../shared/Links/apm/ServiceMapLink.tsx | 0 .../apm/ServiceNodeMetricOverviewLink.tsx | 2 +- .../Links/apm/ServiceNodeOverviewLink.tsx | 2 +- .../shared/Links/apm/ServiceOverviewLink.tsx | 2 +- .../shared/Links/apm/SettingsLink.tsx | 0 .../shared/Links/apm/TraceOverviewLink.tsx | 2 +- .../Links/apm/TransactionDetailLink.tsx | 2 +- .../Links/apm/TransactionOverviewLink.tsx | 2 +- .../Links/apm/agentConfigurationLinks.tsx | 2 +- .../components/shared/Links/rison_helpers.ts | 0 .../shared/Links/url_helpers.test.tsx | 0 .../components/shared/Links/url_helpers.ts | 4 +- .../components/shared/LoadingStatePrompt.tsx | 0 .../LocalUIFilters/Filter/FilterBadgeList.tsx | 0 .../Filter/FilterTitleButton.tsx | 0 .../shared/LocalUIFilters/Filter/index.tsx | 0 .../TransactionTypeFilter/index.tsx | 0 .../shared/LocalUIFilters/index.tsx | 4 +- .../__test__/ManagedTable.test.js | 0 .../__snapshots__/ManagedTable.test.js.snap | 0 .../components/shared/ManagedTable/index.tsx | 0 .../__test__/ErrorMetadata.test.tsx | 2 +- .../MetadataTable/ErrorMetadata/index.tsx | 2 +- .../MetadataTable/ErrorMetadata/sections.ts | 0 .../shared/MetadataTable/Section.tsx | 0 .../__test__/SpanMetadata.test.tsx | 2 +- .../MetadataTable/SpanMetadata/index.tsx | 2 +- .../MetadataTable/SpanMetadata/sections.ts | 0 .../__test__/TransactionMetadata.test.tsx | 2 +- .../TransactionMetadata/index.tsx | 2 +- .../TransactionMetadata/sections.ts | 0 .../__test__/MetadataTable.test.tsx | 0 .../MetadataTable/__test__/Section.test.tsx | 0 .../MetadataTable/__test__/helper.test.ts | 2 +- .../components/shared/MetadataTable/helper.ts | 6 +- .../components/shared/MetadataTable/index.tsx | 0 .../shared/MetadataTable/sections.ts | 0 .../shared/SelectWithPlaceholder/index.tsx | 0 .../PopoverExpression/index.tsx | 0 .../shared/ServiceAlertTrigger/index.tsx | 0 .../Stacktrace/CauseStacktrace.test.tsx | 0 .../shared/Stacktrace/CauseStacktrace.tsx | 2 +- .../components/shared/Stacktrace/Context.tsx | 2 +- .../shared/Stacktrace/FrameHeading.tsx | 2 +- .../Stacktrace/LibraryStacktrace.test.tsx | 0 .../shared/Stacktrace/LibraryStacktrace.tsx | 2 +- .../shared/Stacktrace/Stackframe.tsx | 2 +- .../shared/Stacktrace/Variables.tsx | 2 +- .../Stacktrace/__test__/Stackframe.test.tsx | 2 +- .../__snapshots__/Stackframe.test.tsx.snap | 0 .../__test__/__snapshots__/index.test.ts.snap | 0 .../shared/Stacktrace/__test__/index.test.ts | 2 +- .../Stacktrace/__test__/stacktraces.json | 0 .../components/shared/Stacktrace/index.tsx | 2 +- .../StickyProperties/StickyProperties.test.js | 5 +- .../StickyProperties.test.js.snap | 0 .../shared/StickyProperties/index.tsx | 0 .../shared/Summary/DurationSummaryItem.tsx | 0 .../Summary/ErrorCountSummaryItemBadge.tsx | 0 .../__test__/HttpInfoSummaryItem.test.tsx | 0 .../Summary/HttpInfoSummaryItem/index.tsx | 0 .../__test__/HttpStatusBadge.test.tsx | 0 .../shared/Summary/HttpStatusBadge/index.tsx | 0 .../Summary/HttpStatusBadge/statusCodes.ts | 0 .../Summary/TransactionResultSummaryItem.tsx | 0 .../Summary/TransactionSummary.test.tsx | 0 .../shared/Summary/TransactionSummary.tsx | 4 +- .../Summary/UserAgentSummaryItem.test.tsx | 0 .../shared/Summary/UserAgentSummaryItem.tsx | 2 +- .../Summary/__fixtures__/transactions.ts | 2 +- .../ErrorCountSummaryItemBadge.test.tsx | 0 .../components/shared/Summary/index.tsx | 2 +- .../TimestampTooltip/__test__/index.test.tsx | 0 .../shared/TimestampTooltip/index.tsx | 0 .../CustomLink/CustomLinkPopover.test.tsx | 4 +- .../CustomLink/CustomLinkPopover.tsx | 4 +- .../CustomLink/CustomLinkSection.test.tsx | 4 +- .../CustomLink/CustomLinkSection.tsx | 4 +- .../CustomLink/ManageCustomLink.test.tsx | 0 .../CustomLink/ManageCustomLink.tsx | 0 .../CustomLink/index.test.tsx | 4 +- .../CustomLink/index.tsx | 6 +- .../TransactionActionMenu.tsx | 6 +- .../__test__/TransactionActionMenu.test.tsx | 4 +- .../TransactionActionMenu.test.tsx.snap | 0 .../__test__/mockData.ts | 0 .../__test__/sections.test.ts | 2 +- .../shared/TransactionActionMenu/sections.ts | 2 +- .../TransactionBreakdownGraph/index.tsx | 11 +- .../TransactionBreakdownHeader.tsx | 0 .../TransactionBreakdownKpiList.tsx | 5 +- .../shared/TransactionBreakdown/index.tsx | 2 +- .../index.stories.tsx | 0 .../TransactionDurationAlertTrigger/index.tsx | 4 +- .../charts/CustomPlot/AnnotationsPlot.tsx | 4 +- .../charts/CustomPlot/InteractivePlot.js | 0 .../shared/charts/CustomPlot/Legends.js | 0 .../charts/CustomPlot/SelectionMarker.js | 0 .../shared/charts/CustomPlot/StaticPlot.js | 0 .../shared/charts/CustomPlot/StatusText.js | 0 .../shared/charts/CustomPlot/VoronoiPlot.js | 0 .../charts/CustomPlot/getEmptySeries.ts | 0 .../CustomPlot/getTimezoneOffsetInMs.test.ts | 0 .../CustomPlot/getTimezoneOffsetInMs.ts | 0 .../shared/charts/CustomPlot/index.js | 0 .../charts/CustomPlot/plotUtils.test.ts | 5 +- .../shared/charts/CustomPlot/plotUtils.tsx | 5 +- .../charts/CustomPlot/test/CustomPlot.test.js | 0 .../__snapshots__/CustomPlot.test.js.snap | 0 .../CustomPlot/test/responseWithData.json | 0 .../shared/charts/Histogram/SingleRect.js | 0 .../Histogram/__test__/Histogram.test.js | 0 .../__snapshots__/Histogram.test.js.snap | 0 .../charts/Histogram/__test__/response.json | 0 .../shared/charts/Histogram/index.js | 0 .../components/shared/charts/Legend/index.tsx | 0 .../shared/charts/MetricsChart/index.tsx | 6 +- .../shared/charts/Timeline/LastTickValue.tsx | 0 .../charts/Timeline/Marker/AgentMarker.tsx | 0 .../charts/Timeline/Marker/ErrorMarker.tsx | 2 +- .../Marker/__test__/AgentMarker.test.tsx | 0 .../Marker/__test__/ErrorMarker.test.tsx | 0 .../Timeline/Marker/__test__/Marker.test.tsx | 0 .../__snapshots__/AgentMarker.test.tsx.snap | 0 .../__snapshots__/ErrorMarker.test.tsx.snap | 0 .../__snapshots__/Marker.test.tsx.snap | 0 .../shared/charts/Timeline/Marker/index.tsx | 0 .../shared/charts/Timeline/Timeline.test.tsx | 0 .../shared/charts/Timeline/TimelineAxis.tsx | 0 .../shared/charts/Timeline/VerticalLines.tsx | 0 .../__snapshots__/Timeline.test.tsx.snap | 0 .../shared/charts/Timeline/index.tsx | 0 .../shared/charts/Timeline/plotUtils.ts | 0 .../components/shared/charts/Tooltip/index.js | 0 .../BrowserLineChart.test.tsx | 0 .../TransactionCharts/BrowserLineChart.tsx | 0 .../ChoroplethMap/ChoroplethToolTip.tsx | 0 .../TransactionCharts/ChoroplethMap/index.tsx | 0 .../DurationByCountryMap/index.tsx | 0 .../TransactionLineChart/index.tsx | 2 +- .../shared/charts/TransactionCharts/index.tsx | 9 +- .../charts/helper/__test__/timezone.test.ts | 0 .../shared/charts/helper/timezone.ts | 0 .../Delayed/index.test.tsx | 0 .../useDelayedVisibility/Delayed/index.ts | 0 .../useDelayedVisibility/index.test.tsx | 0 .../shared/useDelayedVisibility/index.ts | 0 .../ApmPluginContext/MockApmPluginContext.tsx | 3 +- .../public/context/ApmPluginContext/index.tsx | 3 +- .../apm/public/context/ChartsSyncContext.tsx | 0 .../InvalidLicenseNotification.tsx | 0 .../public/context/LicenseContext/index.tsx | 2 +- .../context/LoadingIndicatorContext.tsx | 0 .../apm/public/context/LocationContext.tsx | 0 .../public/context/MatchedRouteContext.tsx | 0 .../MockUrlParamsContextProvider.tsx | 0 .../__tests__/UrlParamsContext.test.tsx | 0 .../context/UrlParamsContext/constants.ts | 0 .../context/UrlParamsContext/helpers.ts | 2 +- .../public/context/UrlParamsContext/index.tsx | 6 +- .../UrlParamsContext/resolveUrlParams.ts | 4 +- .../public/context/UrlParamsContext/types.ts | 4 +- .../apm/public}/featureCatalogueEntry.ts | 2 +- .../plugins/apm/public/hooks/useAgentName.ts | 0 .../apm/public/hooks/useApmPluginContext.ts | 0 .../hooks/useAvgDurationByBrowser.test.ts | 0 .../public/hooks/useAvgDurationByBrowser.ts | 6 +- .../public/hooks/useAvgDurationByCountry.ts | 0 .../plugins/apm/public/hooks/useCallApi.ts | 0 .../apm/public/hooks/useChartsSync.tsx | 0 .../apm/public/hooks/useComponentId.tsx | 0 .../apm/public/hooks/useDeepObjectIdentity.ts | 0 .../public/hooks/useDynamicIndexPattern.ts | 2 +- .../hooks/useFetcher.integration.test.tsx | 0 .../apm/public/hooks/useFetcher.test.tsx | 0 .../plugins/apm/public/hooks/useFetcher.tsx | 2 +- .../plugins/apm/public/hooks/useKibanaUrl.ts | 0 .../plugins/apm/public/hooks/useLicense.ts | 0 .../apm/public/hooks/useLoadingIndicator.ts | 0 .../apm/public/hooks/useLocalUIFilters.ts | 8 +- .../plugins/apm/public/hooks/useLocation.tsx | 0 .../apm/public/hooks/useMatchedRoutes.tsx | 0 .../public/hooks/useServiceMetricCharts.ts | 2 +- .../hooks/useServiceTransactionTypes.tsx | 0 .../public/hooks/useTransactionBreakdown.ts | 0 .../apm/public/hooks/useTransactionCharts.ts | 0 .../hooks/useTransactionDistribution.ts | 2 +- .../apm/public/hooks/useTransactionList.ts | 2 +- .../plugins/apm/public/hooks/useUrlParams.tsx | 0 .../plugins/apm/public/hooks/useWaterfall.ts | 0 .../{legacy => }/plugins/apm/public/icon.svg | 0 .../apm-ml-anomaly-detection-example.png | Bin x-pack/plugins/apm/public/index.ts | 25 + x-pack/plugins/apm/public/plugin.ts | 133 +++ .../__tests__/chartSelectors.test.ts | 0 .../__tests__/mockData/anomalyData.ts | 0 .../apm/public/selectors/chartSelectors.ts | 6 +- .../services/__test__/SessionStorageMock.ts | 0 .../public/services/__test__/callApi.test.ts | 0 .../services/__test__/callApmApi.test.ts | 0 .../apm/public/services/rest/callApi.ts | 0 .../public/services/rest/createCallApmApi.ts | 4 +- .../apm/public/services/rest/index_pattern.ts | 6 + .../plugins/apm/public/services/rest/ml.ts | 6 +- .../apm/public/services/rest/watcher.ts | 0 .../apm/public}/setHelpExtension.ts | 0 .../plugins/apm/public/style/variables.ts | 0 .../apm/public}/toggleAppLinkInNav.ts | 2 +- .../apm/public}/updateBadge.ts | 1 - .../utils/__test__/flattenObject.test.ts | 0 .../plugins/apm/public/utils/flattenObject.ts | 2 +- .../formatters/__test__/datetime.test.ts | 0 .../formatters/__test__/duration.test.ts | 0 .../formatters/__test__/formatters.test.ts | 0 .../utils/formatters/__test__/size.test.ts | 0 .../apm/public/utils/formatters/datetime.ts | 0 .../apm/public/utils/formatters/duration.ts | 4 +- .../apm/public/utils/formatters/formatters.ts | 0 .../apm/public/utils/formatters/index.ts | 0 .../apm/public/utils/formatters/size.ts | 2 +- .../public/utils/getRangeFromTimeSeries.ts | 2 +- .../plugins/apm/public/utils/history.ts | 0 .../apm/public/utils/httpStatusCodeToColor.ts | 0 .../public/utils/isValidCoordinateValue.ts | 2 +- .../plugins/apm/public/utils/testHelpers.tsx | 6 +- x-pack/{legacy => }/plugins/apm/readme.md | 8 +- .../plugins/apm/scripts/.gitignore | 0 .../setup-custom-kibana-user-role.ts | 0 .../plugins/apm/scripts/optimize-tsconfig.js | 0 .../apm/scripts/optimize-tsconfig/optimize.js | 0 .../apm/scripts/optimize-tsconfig/paths.js | 0 .../scripts/optimize-tsconfig/tsconfig.json | 3 +- .../scripts/optimize-tsconfig/unoptimize.js | 0 .../plugins/apm/scripts/package.json | 0 .../apm/scripts/setup-kibana-security.js | 0 .../plugins/apm/scripts/storybook.js | 0 .../apm/scripts/unoptimize-tsconfig.js | 0 .../apm/scripts/upload-telemetry-data.js | 0 .../download-telemetry-template.ts | 0 .../generate-sample-documents.ts | 2 +- .../scripts/upload-telemetry-data/index.ts | 2 +- x-pack/plugins/apm/server/feature.ts | 72 ++ x-pack/plugins/apm/server/index.ts | 2 +- .../lib/errors/distribution/queries.test.ts | 2 +- .../apm/server/lib/errors/queries.test.ts | 2 +- .../apm/server/lib/helpers/es_client.ts | 2 +- .../server/lib/helpers/setup_request.test.ts | 13 - .../get_apm_index_pattern_title.ts | 10 + .../apm/server/lib/metrics/queries.test.ts | 2 +- .../server/lib/service_nodes/queries.test.ts | 2 +- .../lib/services/annotations/index.test.ts | 2 +- .../apm/server/lib/services/queries.test.ts | 2 +- .../agent_configuration/queries.test.ts | 2 +- .../create_or_update_custom_link.test.ts | 2 +- .../custom_link/get_transaction.test.ts | 2 +- .../custom_link/list_custom_links.test.ts | 2 +- .../apm/server/lib/traces/queries.test.ts | 2 +- .../lib/transaction_groups/queries.test.ts | 2 +- .../server/lib/transactions/queries.test.ts | 2 +- .../local_ui_filters/queries.test.ts | 2 +- .../apm/server/lib/ui_filters/queries.test.ts | 2 +- x-pack/plugins/apm/server/plugin.ts | 40 +- .../server/routes/create_api/index.test.ts | 4 +- .../apm/server/routes/create_api/index.ts | 3 +- .../apm/server/routes/create_apm_api.ts | 4 +- .../apm/server/routes/index_pattern.ts | 8 + x-pack/plugins/apm/server/routes/typings.ts | 7 +- .../apm/server/saved_objects/apm_indices.ts | 34 + .../apm/server/saved_objects/apm_telemetry.ts | 921 +++++++++++++++++ .../plugins/apm/server/saved_objects/index.ts | 8 + x-pack/plugins/apm/typings/common.d.ts | 8 +- .../log_entry_actions_menu.tsx | 2 +- .../lib/adapters/framework/adapter_types.ts | 4 +- .../siem/scripts/optimize_tsconfig/README.md | 2 +- .../calculate_timeseries_interval.ts | 2 +- .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - .../kuery_bar/typeahead/suggestion.js | 3 +- .../kuery_bar/typeahead/suggestions.js | 3 +- x-pack/tsconfig.json | 2 +- 560 files changed, 1748 insertions(+), 1902 deletions(-) delete mode 100644 x-pack/legacy/plugins/apm/.prettierrc delete mode 100644 x-pack/legacy/plugins/apm/e2e/cypress/integration/snapshots.js delete mode 100644 x-pack/legacy/plugins/apm/index.ts delete mode 100644 x-pack/legacy/plugins/apm/mappings.json delete mode 100644 x-pack/legacy/plugins/apm/public/index.scss delete mode 100644 x-pack/legacy/plugins/apm/public/index.tsx delete mode 100644 x-pack/legacy/plugins/apm/public/legacy_register_feature.ts delete mode 100644 x-pack/legacy/plugins/apm/public/new-platform/getConfigFromInjectedMetadata.ts delete mode 100644 x-pack/legacy/plugins/apm/public/new-platform/index.tsx delete mode 100644 x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx delete mode 100644 x-pack/legacy/plugins/apm/public/style/global_overrides.css delete mode 100644 x-pack/legacy/plugins/apm/public/templates/index.html rename x-pack/{legacy => }/plugins/apm/CONTRIBUTING.md (100%) rename x-pack/{legacy/plugins/apm/public/utils/pickKeys.ts => plugins/apm/common/utils/pick_keys.ts} (100%) rename x-pack/{legacy => }/plugins/apm/dev_docs/github_commands.md (100%) rename x-pack/{legacy => }/plugins/apm/dev_docs/typescript.md (83%) rename x-pack/{legacy => }/plugins/apm/dev_docs/vscode_setup.md (83%) rename x-pack/{legacy => }/plugins/apm/e2e/.gitignore (100%) rename x-pack/{legacy => }/plugins/apm/e2e/README.md (84%) rename x-pack/{legacy => }/plugins/apm/e2e/ci/Dockerfile (100%) rename x-pack/{legacy => }/plugins/apm/e2e/ci/entrypoint.sh (90%) rename x-pack/{legacy => }/plugins/apm/e2e/ci/kibana.e2e.yml (100%) rename x-pack/{legacy => }/plugins/apm/e2e/ci/prepare-kibana.sh (95%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress.json (100%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress/fixtures/example.json (100%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress/integration/apm.feature (100%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress/integration/helpers.ts (100%) create mode 100644 x-pack/plugins/apm/e2e/cypress/integration/snapshots.js rename x-pack/{legacy => }/plugins/apm/e2e/cypress/plugins/index.js (100%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress/support/commands.js (100%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress/support/index.ts (100%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress/support/step_definitions/apm.ts (100%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress/typings/index.d.ts (100%) rename x-pack/{legacy => }/plugins/apm/e2e/cypress/webpack.config.js (100%) rename x-pack/{legacy => }/plugins/apm/e2e/ingest-data/replay.js (100%) rename x-pack/{legacy => }/plugins/apm/e2e/package.json (100%) rename x-pack/{legacy => }/plugins/apm/e2e/run-e2e.sh (98%) rename x-pack/{legacy => }/plugins/apm/e2e/tsconfig.json (100%) rename x-pack/{legacy => }/plugins/apm/e2e/yarn.lock (100%) create mode 100644 x-pack/plugins/apm/public/application/index.tsx rename x-pack/{legacy => }/plugins/apm/public/components/app/APMIndicesPermission/__test__/APMIndicesPermission.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/APMIndicesPermission/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ErrorTabs.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/__snapshots__/index.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/props.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Home/Home.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Home/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/__snapshots__/UpdateBreadcrumbs.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/route_config/index.tsx (98%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Main/route_config/route_names.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/AlertingFlyout/index.tsx (82%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/TransactionSelect.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/__snapshots__/createErrorGroupWatch.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/esResponse.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts (98%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceDetails/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Controls.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx (98%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/EmptyBanner.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/LoadingOverlay.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Popover/Buttons.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Popover/Info.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/Popover/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/cytoscape-layout-test-response.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts (98%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons.ts (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/aws.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/cassandra.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/dark.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/database.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/default.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/documents.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/elasticsearch.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/globe.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/go.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/graphql.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/grpc.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/handlebars.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/java.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/kafka.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/mongodb.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/mysql.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/nodejs.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/php.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/postgresql.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/python.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/redis.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/ruby.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/rumjs.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/icons/websocket.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/index.test.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/index.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceMetrics/index.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx (98%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/NoServicesMessage.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/List.test.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/__snapshots__/List.test.js.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/props.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/ServiceList/index.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/__test__/NoServicesMessage.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/NoServicesMessage.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/ServiceOverview/index.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/FormRowSelect.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/ServicePage.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingsPage.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/saveConfig.ts (90%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.stories.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/List/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/AgentConfigurations/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateCustomLinkButton.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/Documentation.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx (98%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts (91%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkTable.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/EmptyPrompt.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx (99%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/Settings/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TraceLink/index.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TraceOverview/TraceList.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TraceOverview/index.tsx (91%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/Distribution/__test__/distribution.test.ts (92%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/ErrorCount.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/MaybeViewTraceLink.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/TransactionTabs.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_agent_marks.test.ts (92%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_error_marks.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks.ts (87%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_error_marks.ts (89%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/index.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/ServiceLegends.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/FlyoutTopLevelProperties.tsx (90%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/ResponsiveFlyout.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/HttpContext.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/StickySpanProperties.tsx (86%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/TruncateHeightSection.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/DroppedSpansWarning.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallFlyout.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/spans.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/transaction.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts (98%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/__tests__/ErrorCount.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionDetails/index.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionOverview/List/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionOverview/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/app/TransactionOverview/useRedirect.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ApmHeader/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/DatePicker/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/EmptyMessage.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/EnvironmentBadge/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.stories.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ErrorStatePrompt.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/EuiTabLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/HeightRetainer/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ImpactBar/__test__/ImpactBar.test.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ImpactBar/__test__/__snapshots__/ImpactBar.test.js.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ImpactBar/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KeyValueTable/FormattedValue.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KeyValueTable/__test__/KeyValueTable.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KeyValueTable/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KueryBar/Typeahead/ClickOutside.js (95%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestion.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestions.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts (92%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/KueryBar/index.tsx (98%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/LicensePrompt/LicensePrompt.stories.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/LicensePrompt/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverErrorLink.tsx (85%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverSpanLink.tsx (79%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverTransactionLink.tsx (85%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorButton.test.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorLink.test.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionButton.test.tsx (90%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionLink.test.tsx (88%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorButton.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorLink.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionButton.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionLink.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/mockTransaction.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/InfraLink.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/InfraLink.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/KibanaLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx (88%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/APMLink.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/APMLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/ErrorDetailLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/ExternalLinks.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/ExternalLinks.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/HomeLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/ServiceMapLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/ServiceOverviewLink.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/SettingsLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/TraceOverviewLink.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/TransactionOverviewLink.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx (87%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/rison_helpers.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/url_helpers.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Links/url_helpers.ts (87%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/LoadingStatePrompt.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterBadgeList.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterTitleButton.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/LocalUIFilters/TransactionTypeFilter/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/LocalUIFilters/index.tsx (91%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ManagedTable/__test__/ManagedTable.test.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ManagedTable/__test__/__snapshots__/ManagedTable.test.js.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ManagedTable/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx (87%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/Section.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx (88%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx (87%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/__test__/Section.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/__test__/helper.test.ts (96%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/helper.ts (85%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/MetadataTable/sections.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/SelectWithPlaceholder/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ServiceAlertTrigger/PopoverExpression/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/Context.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/FrameHeading.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/Stackframe.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/Variables.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/__test__/Stackframe.test.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/index.test.ts.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/__test__/index.test.ts (97%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/__test__/stacktraces.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Stacktrace/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/StickyProperties/StickyProperties.test.js (95%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/StickyProperties/__snapshots__/StickyProperties.test.js.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/StickyProperties/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/DurationSummaryItem.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/ErrorCountSummaryItemBadge.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/__test__/HttpInfoSummaryItem.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/HttpStatusBadge/__test__/HttpStatusBadge.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/HttpStatusBadge/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/HttpStatusBadge/statusCodes.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/TransactionResultSummaryItem.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/TransactionSummary.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/TransactionSummary.tsx (91%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.tsx (90%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/__fixtures__/transactions.ts (92%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/__test__/ErrorCountSummaryItemBadge.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/Summary/index.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TimestampTooltip/__test__/index.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TimestampTooltip/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx (91%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx (90%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx (85%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx (86%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx (98%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/__test__/__snapshots__/TransactionActionMenu.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/__test__/mockData.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/__test__/sections.test.ts (98%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionActionMenu/sections.ts (98%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx (81%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownHeader.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx (95%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.stories.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/InteractivePlot.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/SelectionMarker.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/StatusText.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/getEmptySeries.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/index.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts (94%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/test/CustomPlot.test.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/CustomPlot/test/responseWithData.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Histogram/SingleRect.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Histogram/__test__/Histogram.test.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Histogram/__test__/__snapshots__/Histogram.test.js.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Histogram/__test__/response.json (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Histogram/index.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Legend/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/MetricsChart/index.tsx (90%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/LastTickValue.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/AgentMarker.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.tsx (97%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/AgentMarker.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/ErrorMarker.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/Marker.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/AgentMarker.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/ErrorMarker.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/Marker.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Marker/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/Timeline.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/TimelineAxis.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/VerticalLines.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/__snapshots__/Timeline.test.tsx.snap (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Timeline/plotUtils.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/Tooltip/index.js (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/ChoroplethToolTip.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/TransactionCharts/DurationByCountryMap/index.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/TransactionCharts/TransactionLineChart/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx (96%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/helper/__test__/timezone.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/charts/helper/timezone.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/components/shared/useDelayedVisibility/index.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx (93%) rename x-pack/{legacy => }/plugins/apm/public/context/ApmPluginContext/index.tsx (87%) rename x-pack/{legacy => }/plugins/apm/public/context/ChartsSyncContext.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/context/LicenseContext/index.tsx (94%) rename x-pack/{legacy => }/plugins/apm/public/context/LoadingIndicatorContext.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/context/LocationContext.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/context/MatchedRouteContext.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/context/UrlParamsContext/MockUrlParamsContextProvider.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/context/UrlParamsContext/constants.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/context/UrlParamsContext/helpers.ts (97%) rename x-pack/{legacy => }/plugins/apm/public/context/UrlParamsContext/index.tsx (92%) rename x-pack/{legacy => }/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts (93%) rename x-pack/{legacy => }/plugins/apm/public/context/UrlParamsContext/types.ts (83%) rename x-pack/{legacy/plugins/apm/public/new-platform => plugins/apm/public}/featureCatalogueEntry.ts (88%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useAgentName.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useApmPluginContext.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useAvgDurationByBrowser.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useAvgDurationByBrowser.ts (83%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useAvgDurationByCountry.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useCallApi.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useChartsSync.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useComponentId.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useDeepObjectIdentity.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useDynamicIndexPattern.ts (89%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useFetcher.integration.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useFetcher.test.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useFetcher.tsx (98%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useKibanaUrl.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useLicense.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useLoadingIndicator.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useLocalUIFilters.ts (88%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useLocation.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useMatchedRoutes.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useServiceMetricCharts.ts (91%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useServiceTransactionTypes.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useTransactionBreakdown.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useTransactionCharts.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useTransactionDistribution.ts (93%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useTransactionList.ts (94%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useUrlParams.tsx (100%) rename x-pack/{legacy => }/plugins/apm/public/hooks/useWaterfall.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/icon.svg (100%) rename x-pack/{legacy => }/plugins/apm/public/images/apm-ml-anomaly-detection-example.png (100%) create mode 100644 x-pack/plugins/apm/public/index.ts create mode 100644 x-pack/plugins/apm/public/plugin.ts rename x-pack/{legacy => }/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/selectors/__tests__/mockData/anomalyData.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/selectors/chartSelectors.ts (94%) rename x-pack/{legacy => }/plugins/apm/public/services/__test__/SessionStorageMock.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/services/__test__/callApi.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/services/__test__/callApmApi.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/services/rest/callApi.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/services/rest/createCallApmApi.ts (89%) rename x-pack/{legacy => }/plugins/apm/public/services/rest/index_pattern.ts (76%) rename x-pack/{legacy => }/plugins/apm/public/services/rest/ml.ts (91%) rename x-pack/{legacy => }/plugins/apm/public/services/rest/watcher.ts (100%) rename x-pack/{legacy/plugins/apm/public/new-platform => plugins/apm/public}/setHelpExtension.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/style/variables.ts (100%) rename x-pack/{legacy/plugins/apm/public/new-platform => plugins/apm/public}/toggleAppLinkInNav.ts (91%) rename x-pack/{legacy/plugins/apm/public/new-platform => plugins/apm/public}/updateBadge.ts (99%) rename x-pack/{legacy => }/plugins/apm/public/utils/__test__/flattenObject.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/flattenObject.ts (94%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/__test__/datetime.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/__test__/duration.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/__test__/formatters.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/__test__/size.test.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/datetime.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/duration.ts (96%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/formatters.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/index.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/formatters/size.ts (95%) rename x-pack/{legacy => }/plugins/apm/public/utils/getRangeFromTimeSeries.ts (88%) rename x-pack/{legacy => }/plugins/apm/public/utils/history.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/httpStatusCodeToColor.ts (100%) rename x-pack/{legacy => }/plugins/apm/public/utils/isValidCoordinateValue.ts (84%) rename x-pack/{legacy => }/plugins/apm/public/utils/testHelpers.tsx (96%) rename x-pack/{legacy => }/plugins/apm/readme.md (92%) rename x-pack/{legacy => }/plugins/apm/scripts/.gitignore (100%) rename x-pack/{legacy => }/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts (100%) rename x-pack/{legacy => }/plugins/apm/scripts/optimize-tsconfig.js (100%) rename x-pack/{legacy => }/plugins/apm/scripts/optimize-tsconfig/optimize.js (100%) rename x-pack/{legacy => }/plugins/apm/scripts/optimize-tsconfig/paths.js (100%) rename x-pack/{legacy => }/plugins/apm/scripts/optimize-tsconfig/tsconfig.json (60%) rename x-pack/{legacy => }/plugins/apm/scripts/optimize-tsconfig/unoptimize.js (100%) rename x-pack/{legacy => }/plugins/apm/scripts/package.json (100%) rename x-pack/{legacy => }/plugins/apm/scripts/setup-kibana-security.js (100%) rename x-pack/{legacy => }/plugins/apm/scripts/storybook.js (100%) rename x-pack/{legacy => }/plugins/apm/scripts/unoptimize-tsconfig.js (100%) rename x-pack/{legacy => }/plugins/apm/scripts/upload-telemetry-data.js (100%) rename x-pack/{legacy => }/plugins/apm/scripts/upload-telemetry-data/download-telemetry-template.ts (100%) rename x-pack/{legacy => }/plugins/apm/scripts/upload-telemetry-data/generate-sample-documents.ts (97%) rename x-pack/{legacy => }/plugins/apm/scripts/upload-telemetry-data/index.ts (98%) create mode 100644 x-pack/plugins/apm/server/feature.ts create mode 100644 x-pack/plugins/apm/server/lib/index_pattern/get_apm_index_pattern_title.ts create mode 100644 x-pack/plugins/apm/server/saved_objects/apm_indices.ts create mode 100644 x-pack/plugins/apm/server/saved_objects/apm_telemetry.ts create mode 100644 x-pack/plugins/apm/server/saved_objects/index.ts diff --git a/src/cli/cluster/cluster_manager.ts b/src/cli/cluster/cluster_manager.ts index f16ba61234a95..97dec3eead303 100644 --- a/src/cli/cluster/cluster_manager.ts +++ b/src/cli/cluster/cluster_manager.ts @@ -266,8 +266,8 @@ export class ClusterManager { fromRoot('src/legacy/server/sass/__tmp__'), fromRoot('x-pack/legacy/plugins/reporting/.chromium'), fromRoot('x-pack/plugins/siem/cypress'), - fromRoot('x-pack/legacy/plugins/apm/e2e'), - fromRoot('x-pack/legacy/plugins/apm/scripts'), + fromRoot('x-pack/plugins/apm/e2e'), + fromRoot('x-pack/plugins/apm/scripts'), fromRoot('x-pack/legacy/plugins/canvas/canvas_plugin_src'), // prevents server from restarting twice for Canvas plugin changes, 'plugins/java_languageserver', ]; diff --git a/src/dev/precommit_hook/casing_check_config.js b/src/dev/precommit_hook/casing_check_config.js index 14e25ab863dbc..8630221b3e94f 100644 --- a/src/dev/precommit_hook/casing_check_config.js +++ b/src/dev/precommit_hook/casing_check_config.js @@ -35,7 +35,6 @@ export const IGNORE_FILE_GLOBS = [ '**/Gruntfile.js', 'tasks/config/**/*', '**/{Dockerfile,docker-compose.yml}', - 'x-pack/legacy/plugins/apm/**/*', 'x-pack/legacy/plugins/canvas/tasks/**/*', 'x-pack/legacy/plugins/canvas/canvas_plugin_src/**/*', 'x-pack/plugins/monitoring/public/lib/jquery_flot/**/*', @@ -59,6 +58,11 @@ export const IGNORE_FILE_GLOBS = [ // filename required by api-extractor 'api-documenter.json', + + // TODO fix file names in APM to remove these + 'x-pack/plugins/apm/public/**/*', + 'x-pack/plugins/apm/scripts/**/*', + 'x-pack/plugins/apm/e2e/**/*', ]; /** diff --git a/src/dev/run_check_lockfile_symlinks.js b/src/dev/run_check_lockfile_symlinks.js index 6c6fc54638ee8..b912ea9ddb87e 100644 --- a/src/dev/run_check_lockfile_symlinks.js +++ b/src/dev/run_check_lockfile_symlinks.js @@ -35,9 +35,9 @@ const IGNORE_FILE_GLOBS = [ // fixtures aren't used in production, ignore them '**/*fixtures*/**/*', // cypress isn't used in production, ignore it - 'x-pack/legacy/plugins/apm/e2e/*', + 'x-pack/plugins/apm/e2e/*', // apm scripts aren't used in production, ignore them - 'x-pack/legacy/plugins/apm/scripts/*', + 'x-pack/plugins/apm/scripts/*', ]; run(async ({ log }) => { diff --git a/src/dev/storybook/aliases.ts b/src/dev/storybook/aliases.ts index 43114b2edccfc..4dc930dae3e25 100644 --- a/src/dev/storybook/aliases.ts +++ b/src/dev/storybook/aliases.ts @@ -18,7 +18,7 @@ */ export const storybookAliases = { - apm: 'x-pack/legacy/plugins/apm/scripts/storybook.js', + apm: 'x-pack/plugins/apm/scripts/storybook.js', canvas: 'x-pack/legacy/plugins/canvas/scripts/storybook_new.js', codeeditor: 'src/plugins/kibana_react/public/code_editor/scripts/storybook.ts', drilldowns: 'x-pack/plugins/drilldowns/scripts/storybook.js', diff --git a/src/dev/typescript/projects.ts b/src/dev/typescript/projects.ts index 01d8a30b598c1..a13f61af60173 100644 --- a/src/dev/typescript/projects.ts +++ b/src/dev/typescript/projects.ts @@ -30,7 +30,7 @@ export const PROJECTS = [ new Project(resolve(REPO_ROOT, 'x-pack/plugins/siem/cypress/tsconfig.json'), { name: 'siem/cypress', }), - new Project(resolve(REPO_ROOT, 'x-pack/legacy/plugins/apm/e2e/tsconfig.json'), { + new Project(resolve(REPO_ROOT, 'x-pack/plugins/apm/e2e/tsconfig.json'), { name: 'apm/cypress', disableTypeCheck: true, }), diff --git a/x-pack/index.js b/x-pack/index.js index cfadddac3994a..89cbb03f084eb 100644 --- a/x-pack/index.js +++ b/x-pack/index.js @@ -10,7 +10,6 @@ import { reporting } from './legacy/plugins/reporting'; import { security } from './legacy/plugins/security'; import { dashboardMode } from './legacy/plugins/dashboard_mode'; import { beats } from './legacy/plugins/beats_management'; -import { apm } from './legacy/plugins/apm'; import { maps } from './legacy/plugins/maps'; import { spaces } from './legacy/plugins/spaces'; import { canvas } from './legacy/plugins/canvas'; @@ -28,7 +27,6 @@ module.exports = function(kibana) { security(kibana), dashboardMode(kibana), beats(kibana), - apm(kibana), maps(kibana), canvas(kibana), infra(kibana), diff --git a/x-pack/legacy/plugins/apm/.prettierrc b/x-pack/legacy/plugins/apm/.prettierrc deleted file mode 100644 index 650cb880f6f5a..0000000000000 --- a/x-pack/legacy/plugins/apm/.prettierrc +++ /dev/null @@ -1,4 +0,0 @@ -{ - "singleQuote": true, - "semi": true -} diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/legacy/plugins/apm/e2e/cypress/integration/snapshots.js deleted file mode 100644 index 968c2675a62e7..0000000000000 --- a/x-pack/legacy/plugins/apm/e2e/cypress/integration/snapshots.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - "APM": { - "Transaction duration charts": { - "1": "500 ms", - "2": "250 ms", - "3": "0 ms" - } - }, - "__version": "4.2.0" -} diff --git a/x-pack/legacy/plugins/apm/index.ts b/x-pack/legacy/plugins/apm/index.ts deleted file mode 100644 index d2383acd45eba..0000000000000 --- a/x-pack/legacy/plugins/apm/index.ts +++ /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 { i18n } from '@kbn/i18n'; -import { Server } from 'hapi'; -import { resolve } from 'path'; -import { APMPluginContract } from '../../../plugins/apm/server'; -import { LegacyPluginInitializer } from '../../../../src/legacy/types'; -import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; -import mappings from './mappings.json'; - -export const apm: LegacyPluginInitializer = kibana => { - return new kibana.Plugin({ - require: [ - 'kibana', - 'elasticsearch', - 'xpack_main', - 'apm_oss', - 'task_manager' - ], - id: 'apm', - configPrefix: 'xpack.apm', - publicDir: resolve(__dirname, 'public'), - uiExports: { - app: { - title: 'APM', - description: i18n.translate('xpack.apm.apmForESDescription', { - defaultMessage: 'APM for the Elastic Stack' - }), - main: 'plugins/apm/index', - icon: 'plugins/apm/icon.svg', - euiIconType: 'apmApp', - order: 8100, - category: DEFAULT_APP_CATEGORIES.observability - }, - styleSheetPaths: resolve(__dirname, 'public/index.scss'), - home: ['plugins/apm/legacy_register_feature'], - - // TODO: get proper types - injectDefaultVars(server: Server) { - const config = server.config(); - return { - apmUiEnabled: config.get('xpack.apm.ui.enabled'), - // TODO: rename to apm_oss.indexPatternTitle in 7.0 (breaking change) - apmIndexPatternTitle: config.get('apm_oss.indexPattern'), - apmServiceMapEnabled: config.get('xpack.apm.serviceMapEnabled') - }; - }, - savedObjectSchemas: { - 'apm-services-telemetry': { - isNamespaceAgnostic: true - }, - 'apm-indices': { - isNamespaceAgnostic: true - } - }, - mappings - }, - - // TODO: get proper types - config(Joi: any) { - return Joi.object({ - // display menu item - ui: Joi.object({ - enabled: Joi.boolean().default(true), - transactionGroupBucketSize: Joi.number().default(100), - maxTraceItems: Joi.number().default(1000) - }).default(), - - // enable plugin - enabled: Joi.boolean().default(true), - - // index patterns - autocreateApmIndexPattern: Joi.boolean().default(true), - - // service map - serviceMapEnabled: Joi.boolean().default(true), - serviceMapFingerprintBucketSize: Joi.number().default(100), - serviceMapTraceIdBucketSize: Joi.number().default(65), - serviceMapFingerprintGlobalBucketSize: Joi.number().default(1000), - serviceMapTraceIdGlobalBucketSize: Joi.number().default(6), - serviceMapMaxTracesPerRequest: Joi.number().default(50), - - // telemetry - telemetryCollectionEnabled: Joi.boolean().default(true) - }).default(); - }, - - // TODO: get proper types - init(server: Server) { - server.plugins.xpack_main.registerFeature({ - id: 'apm', - name: i18n.translate('xpack.apm.featureRegistry.apmFeatureName', { - defaultMessage: 'APM' - }), - order: 900, - icon: 'apmApp', - navLinkId: 'apm', - app: ['apm', 'kibana'], - catalogue: ['apm'], - // see x-pack/plugins/features/common/feature_kibana_privileges.ts - privileges: { - all: { - app: ['apm', 'kibana'], - api: [ - 'apm', - 'apm_write', - 'actions-read', - 'actions-all', - 'alerting-read', - 'alerting-all' - ], - catalogue: ['apm'], - savedObject: { - all: ['alert', 'action', 'action_task_params'], - read: [] - }, - ui: [ - 'show', - 'save', - 'alerting:show', - 'actions:show', - 'alerting:save', - 'actions:save', - 'alerting:delete', - 'actions:delete' - ] - }, - read: { - app: ['apm', 'kibana'], - api: [ - 'apm', - 'actions-read', - 'actions-all', - 'alerting-read', - 'alerting-all' - ], - catalogue: ['apm'], - savedObject: { - all: ['alert', 'action', 'action_task_params'], - read: [] - }, - ui: [ - 'show', - 'alerting:show', - 'actions:show', - 'alerting:save', - 'actions:save', - 'alerting:delete', - 'actions:delete' - ] - } - } - }); - const apmPlugin = server.newPlatform.setup.plugins - .apm as APMPluginContract; - - apmPlugin.registerLegacyAPI({ - server - }); - } - }); -}; diff --git a/x-pack/legacy/plugins/apm/mappings.json b/x-pack/legacy/plugins/apm/mappings.json deleted file mode 100644 index 6ca9f13792085..0000000000000 --- a/x-pack/legacy/plugins/apm/mappings.json +++ /dev/null @@ -1,933 +0,0 @@ -{ - "apm-telemetry": { - "properties": { - "agents": { - "properties": { - "dotnet": { - "properties": { - "agent": { - "properties": { - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "language": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "runtime": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - } - } - } - } - }, - "go": { - "properties": { - "agent": { - "properties": { - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "language": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "runtime": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - } - } - } - } - }, - "java": { - "properties": { - "agent": { - "properties": { - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "language": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "runtime": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - } - } - } - } - }, - "js-base": { - "properties": { - "agent": { - "properties": { - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "language": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "runtime": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - } - } - } - } - }, - "nodejs": { - "properties": { - "agent": { - "properties": { - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "language": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "runtime": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - } - } - } - } - }, - "python": { - "properties": { - "agent": { - "properties": { - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "language": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "runtime": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - } - } - } - } - }, - "ruby": { - "properties": { - "agent": { - "properties": { - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "language": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "runtime": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - } - } - } - } - }, - "rum-js": { - "properties": { - "agent": { - "properties": { - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "service": { - "properties": { - "framework": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "language": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - }, - "runtime": { - "properties": { - "composite": { - "type": "keyword", - "ignore_above": 1024 - }, - "name": { - "type": "keyword", - "ignore_above": 1024 - }, - "version": { - "type": "keyword", - "ignore_above": 1024 - } - } - } - } - } - } - } - } - }, - "counts": { - "properties": { - "agent_configuration": { - "properties": { - "all": { - "type": "long" - } - } - }, - "error": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "max_error_groups_per_service": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "max_transaction_groups_per_service": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "metric": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "onboarding": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "services": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "sourcemap": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "span": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - }, - "traces": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "transaction": { - "properties": { - "1d": { - "type": "long" - }, - "all": { - "type": "long" - } - } - } - } - }, - "cardinality": { - "properties": { - "user_agent": { - "properties": { - "original": { - "properties": { - "all_agents": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "rum": { - "properties": { - "1d": { - "type": "long" - } - } - } - } - } - } - }, - "transaction": { - "properties": { - "name": { - "properties": { - "all_agents": { - "properties": { - "1d": { - "type": "long" - } - } - }, - "rum": { - "properties": { - "1d": { - "type": "long" - } - } - } - } - } - } - } - } - }, - "has_any_services": { - "type": "boolean" - }, - "indices": { - "properties": { - "all": { - "properties": { - "total": { - "properties": { - "docs": { - "properties": { - "count": { - "type": "long" - } - } - }, - "store": { - "properties": { - "size_in_bytes": { - "type": "long" - } - } - } - } - } - } - }, - "shards": { - "properties": { - "total": { - "type": "long" - } - } - } - } - }, - "integrations": { - "properties": { - "ml": { - "properties": { - "all_jobs_count": { - "type": "long" - } - } - } - } - }, - "retainment": { - "properties": { - "error": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "metric": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "onboarding": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "span": { - "properties": { - "ms": { - "type": "long" - } - } - }, - "transaction": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "services_per_agent": { - "properties": { - "dotnet": { - "type": "long", - "null_value": 0 - }, - "go": { - "type": "long", - "null_value": 0 - }, - "java": { - "type": "long", - "null_value": 0 - }, - "js-base": { - "type": "long", - "null_value": 0 - }, - "nodejs": { - "type": "long", - "null_value": 0 - }, - "python": { - "type": "long", - "null_value": 0 - }, - "ruby": { - "type": "long", - "null_value": 0 - }, - "rum-js": { - "type": "long", - "null_value": 0 - } - } - }, - "tasks": { - "properties": { - "agent_configuration": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "agents": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "cardinality": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "groupings": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "indices_stats": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "integrations": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "processor_events": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "services": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - }, - "versions": { - "properties": { - "took": { - "properties": { - "ms": { - "type": "long" - } - } - } - } - } - } - }, - "version": { - "properties": { - "apm_server": { - "properties": { - "major": { - "type": "long" - }, - "minor": { - "type": "long" - }, - "patch": { - "type": "long" - } - } - } - } - } - } - }, - "apm-indices": { - "properties": { - "apm_oss.sourcemapIndices": { - "type": "keyword" - }, - "apm_oss.errorIndices": { - "type": "keyword" - }, - "apm_oss.onboardingIndices": { - "type": "keyword" - }, - "apm_oss.spanIndices": { - "type": "keyword" - }, - "apm_oss.transactionIndices": { - "type": "keyword" - }, - "apm_oss.metricsIndices": { - "type": "keyword" - } - } - } -} diff --git a/x-pack/legacy/plugins/apm/public/index.scss b/x-pack/legacy/plugins/apm/public/index.scss deleted file mode 100644 index 04a070c304d6f..0000000000000 --- a/x-pack/legacy/plugins/apm/public/index.scss +++ /dev/null @@ -1,16 +0,0 @@ -// Import the EUI global scope so we can use EUI constants -@import 'src/legacy/ui/public/styles/_styling_constants'; - -/* APM plugin styles */ - -// Prefix all styles with "apm" to avoid conflicts. -// Examples -// apmChart -// apmChart__legend -// apmChart__legend--small -// apmChart__legend-isLoading - -.apmReactRoot { - overflow-x: auto; - height: 100%; -} diff --git a/x-pack/legacy/plugins/apm/public/index.tsx b/x-pack/legacy/plugins/apm/public/index.tsx deleted file mode 100644 index 59b2fedaafba6..0000000000000 --- a/x-pack/legacy/plugins/apm/public/index.tsx +++ /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 { npSetup, npStart } from 'ui/new_platform'; -import 'react-vis/dist/style.css'; -import { PluginInitializerContext } from 'kibana/public'; -import 'ui/autoload/all'; -import chrome from 'ui/chrome'; -import { plugin } from './new-platform'; -import { REACT_APP_ROOT_ID } from './new-platform/plugin'; -import './style/global_overrides.css'; -import template from './templates/index.html'; - -// This will be moved to core.application.register when the new platform -// migration is complete. -// @ts-ignore -chrome.setRootTemplate(template); - -const checkForRoot = () => { - return new Promise(resolve => { - const ready = !!document.getElementById(REACT_APP_ROOT_ID); - if (ready) { - resolve(); - } else { - setTimeout(() => resolve(checkForRoot()), 10); - } - }); -}; -checkForRoot().then(() => { - 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/legacy_register_feature.ts b/x-pack/legacy/plugins/apm/public/legacy_register_feature.ts deleted file mode 100644 index f12865399054e..0000000000000 --- a/x-pack/legacy/plugins/apm/public/legacy_register_feature.ts +++ /dev/null @@ -1,24 +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 { npSetup } from 'ui/new_platform'; -import { featureCatalogueEntry } from './new-platform/featureCatalogueEntry'; - -const { - core, - plugins: { home } -} = npSetup; -const apmUiEnabled = core.injectedMetadata.getInjectedVar( - 'apmUiEnabled' -) as boolean; - -if (apmUiEnabled) { - home.featureCatalogue.register(featureCatalogueEntry); -} - -home.environment.update({ - apmUi: apmUiEnabled -}); diff --git a/x-pack/legacy/plugins/apm/public/new-platform/getConfigFromInjectedMetadata.ts b/x-pack/legacy/plugins/apm/public/new-platform/getConfigFromInjectedMetadata.ts deleted file mode 100644 index 6dc77f7733b2d..0000000000000 --- a/x-pack/legacy/plugins/apm/public/new-platform/getConfigFromInjectedMetadata.ts +++ /dev/null @@ -1,24 +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 { npStart } from 'ui/new_platform'; -import { ConfigSchema } from './plugin'; - -const { core } = npStart; - -export function getConfigFromInjectedMetadata(): ConfigSchema { - const { - apmIndexPatternTitle, - apmServiceMapEnabled, - apmUiEnabled - } = core.injectedMetadata.getInjectedVars(); - - return { - indexPatternTitle: `${apmIndexPatternTitle}`, - serviceMapEnabled: !!apmServiceMapEnabled, - ui: { enabled: !!apmUiEnabled } - }; -} diff --git a/x-pack/legacy/plugins/apm/public/new-platform/index.tsx b/x-pack/legacy/plugins/apm/public/new-platform/index.tsx deleted file mode 100644 index 0674dc48316f4..0000000000000 --- a/x-pack/legacy/plugins/apm/public/new-platform/index.tsx +++ /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 { PluginInitializer } from '../../../../../../src/core/public'; -import { ApmPlugin, ApmPluginSetup, ApmPluginStart } from './plugin'; - -export const plugin: PluginInitializer< - ApmPluginSetup, - ApmPluginStart -> = pluginInitializerContext => new ApmPlugin(pluginInitializerContext); diff --git a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx b/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx deleted file mode 100644 index 80a45ba66c4fa..0000000000000 --- a/x-pack/legacy/plugins/apm/public/new-platform/plugin.tsx +++ /dev/null @@ -1,203 +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 { ApmRoute } from '@elastic/apm-rum-react'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import ReactDOM from 'react-dom'; -import { Route, Router, Switch } from 'react-router-dom'; -import styled from 'styled-components'; -import { - CoreSetup, - CoreStart, - Plugin, - PluginInitializerContext -} from '../../../../../../src/core/public'; -import { DataPublicPluginSetup } from '../../../../../../src/plugins/data/public'; -import { HomePublicPluginSetup } from '../../../../../../src/plugins/home/public'; -import { KibanaContextProvider } from '../../../../../../src/plugins/kibana_react/public'; -import { PluginSetupContract as AlertingPluginPublicSetup } from '../../../../../plugins/alerting/public'; -import { AlertType } from '../../../../../plugins/apm/common/alert_types'; -import { LicensingPluginSetup } from '../../../../../plugins/licensing/public'; -import { - AlertsContextProvider, - TriggersAndActionsUIPublicPluginSetup -} from '../../../../../plugins/triggers_actions_ui/public'; -import { APMIndicesPermission } from '../components/app/APMIndicesPermission'; -import { routes } from '../components/app/Main/route_config'; -import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; -import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; -import { ErrorRateAlertTrigger } from '../components/shared/ErrorRateAlertTrigger'; -import { TransactionDurationAlertTrigger } from '../components/shared/TransactionDurationAlertTrigger'; -import { ApmPluginContext } from '../context/ApmPluginContext'; -import { LicenseProvider } from '../context/LicenseContext'; -import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext'; -import { LocationProvider } from '../context/LocationContext'; -import { MatchedRouteProvider } from '../context/MatchedRouteContext'; -import { UrlParamsProvider } from '../context/UrlParamsContext'; -import { createCallApmApi } from '../services/rest/createCallApmApi'; -import { createStaticIndexPattern } from '../services/rest/index_pattern'; -import { px, unit, units } from '../style/variables'; -import { history } from '../utils/history'; -import { featureCatalogueEntry } from './featureCatalogueEntry'; -import { getConfigFromInjectedMetadata } from './getConfigFromInjectedMetadata'; -import { setHelpExtension } from './setHelpExtension'; -import { toggleAppLinkInNav } from './toggleAppLinkInNav'; -import { setReadonlyBadge } from './updateBadge'; - -export const REACT_APP_ROOT_ID = 'react-apm-root'; - -const MainContainer = styled.div` - min-width: ${px(unit * 50)}; - padding: ${px(units.plus)}; - height: 100%; -`; - -const App = () => { - return ( - - - - - - {routes.map((route, i) => ( - - ))} - - - - ); -}; - -export type ApmPluginSetup = void; -export type ApmPluginStart = void; - -export interface ApmPluginSetupDeps { - alerting?: AlertingPluginPublicSetup; - data: DataPublicPluginSetup; - home: HomePublicPluginSetup; - licensing: LicensingPluginSetup; - triggers_actions_ui: TriggersAndActionsUIPublicPluginSetup; -} - -export interface ConfigSchema { - indexPatternTitle: string; - serviceMapEnabled: boolean; - ui: { - enabled: boolean; - }; -} - -export class ApmPlugin - 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. - private readonly initializerContext: PluginInitializerContext - ) {} - - // 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) { - const i18nCore = core.i18n; - const plugins = this.setupPlugins; - createCallApmApi(core.http); - - // Once we're actually an NP plugin we'll get the config from the - // initializerContext like: - // - // const config = this.initializerContext.config.get(); - // - // Until then we use a shim to get it from legacy injectedMetadata: - const config = getConfigFromInjectedMetadata(); - - // render APM feedback link in global help menu - setHelpExtension(core); - setReadonlyBadge(core); - toggleAppLinkInNav(core, config); - - const apmPluginContextValue = { - config, - core, - plugins - }; - - plugins.triggers_actions_ui.alertTypeRegistry.register({ - id: AlertType.ErrorRate, - name: i18n.translate('xpack.apm.alertTypes.errorRate', { - defaultMessage: 'Error rate' - }), - iconClass: 'bell', - alertParamsExpression: ErrorRateAlertTrigger, - validate: () => ({ - errors: [] - }) - }); - - plugins.triggers_actions_ui.alertTypeRegistry.register({ - id: AlertType.TransactionDuration, - name: i18n.translate('xpack.apm.alertTypes.transactionDuration', { - defaultMessage: 'Transaction duration' - }), - iconClass: 'bell', - alertParamsExpression: TransactionDurationAlertTrigger, - validate: () => ({ - errors: [] - }) - }); - - ReactDOM.render( - - - - - - - - - - - - - - - - - - - - - , - document.getElementById(REACT_APP_ROOT_ID) - ); - - // create static index pattern and store as saved object. Not needed by APM UI but for legacy reasons in Discover, Dashboard etc. - createStaticIndexPattern().catch(e => { - // eslint-disable-next-line no-console - console.log('Error fetching static index pattern', e); - }); - } - - public stop() {} -} diff --git a/x-pack/legacy/plugins/apm/public/style/global_overrides.css b/x-pack/legacy/plugins/apm/public/style/global_overrides.css deleted file mode 100644 index 75b4532f7c9a1..0000000000000 --- a/x-pack/legacy/plugins/apm/public/style/global_overrides.css +++ /dev/null @@ -1,34 +0,0 @@ -/* -Hide unused secondary Kibana navigation -*/ -.kuiLocalNav { - min-height: initial; -} - -.kuiLocalNavRow.kuiLocalNavRow--secondary { - display: none; -} - -/* -Remove unnecessary space below the navigation dropdown -*/ -.kuiLocalDropdown { - margin-bottom: 0; - border-bottom: none; -} - -/* -Hide the "0-10 of 100" text in KUIPager component for all KUIControlledTable -*/ -.kuiControlledTable .kuiPagerText { - display: none; -} - -/* -Hide default dashed gridlines in EUI chart component for all APM graphs -*/ - -.rv-xy-plot__grid-lines__line { - stroke-opacity: 1; - stroke-dasharray: 1; -} diff --git a/x-pack/legacy/plugins/apm/public/templates/index.html b/x-pack/legacy/plugins/apm/public/templates/index.html deleted file mode 100644 index 78e0ade3ad624..0000000000000 --- a/x-pack/legacy/plugins/apm/public/templates/index.html +++ /dev/null @@ -1 +0,0 @@ -
diff --git a/x-pack/legacy/plugins/apm/CONTRIBUTING.md b/x-pack/plugins/apm/CONTRIBUTING.md similarity index 100% rename from x-pack/legacy/plugins/apm/CONTRIBUTING.md rename to x-pack/plugins/apm/CONTRIBUTING.md diff --git a/x-pack/plugins/apm/common/apm_saved_object_constants.ts b/x-pack/plugins/apm/common/apm_saved_object_constants.ts index 0529d90fe940a..eb16db7715fed 100644 --- a/x-pack/plugins/apm/common/apm_saved_object_constants.ts +++ b/x-pack/plugins/apm/common/apm_saved_object_constants.ts @@ -5,7 +5,7 @@ */ // the types have to match the names of the saved object mappings -// in /x-pack/legacy/plugins/apm/mappings.json +// in /x-pack/plugins/apm/mappings.json // APM indices export const APM_INDICES_SAVED_OBJECT_TYPE = 'apm-indices'; diff --git a/x-pack/legacy/plugins/apm/public/utils/pickKeys.ts b/x-pack/plugins/apm/common/utils/pick_keys.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/pickKeys.ts rename to x-pack/plugins/apm/common/utils/pick_keys.ts diff --git a/x-pack/legacy/plugins/apm/dev_docs/github_commands.md b/x-pack/plugins/apm/dev_docs/github_commands.md similarity index 100% rename from x-pack/legacy/plugins/apm/dev_docs/github_commands.md rename to x-pack/plugins/apm/dev_docs/github_commands.md diff --git a/x-pack/legacy/plugins/apm/dev_docs/typescript.md b/x-pack/plugins/apm/dev_docs/typescript.md similarity index 83% rename from x-pack/legacy/plugins/apm/dev_docs/typescript.md rename to x-pack/plugins/apm/dev_docs/typescript.md index 6858e93ec09e0..6de61b665a1b1 100644 --- a/x-pack/legacy/plugins/apm/dev_docs/typescript.md +++ b/x-pack/plugins/apm/dev_docs/typescript.md @@ -4,8 +4,8 @@ Kibana and X-Pack are very large TypeScript projects, and it comes at a cost. Ed To run the optimization: -`$ node x-pack/legacy/plugins/apm/scripts/optimize-tsconfig` +`$ node x-pack/plugins/apm/scripts/optimize-tsconfig` To undo the optimization: -`$ node x-pack/legacy/plugins/apm/scripts/unoptimize-tsconfig` +`$ node x-pack/plugins/apm/scripts/unoptimize-tsconfig` diff --git a/x-pack/legacy/plugins/apm/dev_docs/vscode_setup.md b/x-pack/plugins/apm/dev_docs/vscode_setup.md similarity index 83% rename from x-pack/legacy/plugins/apm/dev_docs/vscode_setup.md rename to x-pack/plugins/apm/dev_docs/vscode_setup.md index e1901b3855f73..1c80d1476520d 100644 --- a/x-pack/legacy/plugins/apm/dev_docs/vscode_setup.md +++ b/x-pack/plugins/apm/dev_docs/vscode_setup.md @@ -1,6 +1,6 @@ ### Visual Studio Code -When using [Visual Studio Code](https://code.visualstudio.com/) with APM it's best to set up a [multi-root workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces) and add the `x-pack/legacy/plugins/apm` directory, the `x-pack` directory, and the root of the Kibana repository to the workspace. This makes it so you can navigate and search within APM and use the wider workspace roots when you need to widen your search. +When using [Visual Studio Code](https://code.visualstudio.com/) with APM it's best to set up a [multi-root workspace](https://code.visualstudio.com/docs/editor/multi-root-workspaces) and add the `x-pack/plugins/apm` directory, the `x-pack` directory, and the root of the Kibana repository to the workspace. This makes it so you can navigate and search within APM and use the wider workspace roots when you need to widen your search. #### Using the Jest extension @@ -25,7 +25,7 @@ If you have a workspace configured as described above you should have: in your Workspace settings, and: ```json -"jest.pathToJest": "node scripts/jest.js --testPathPattern=legacy/plugins/apm", +"jest.pathToJest": "node scripts/jest.js --testPathPattern=plugins/apm", "jest.rootPath": "../../.." ``` @@ -40,7 +40,7 @@ To make the [VSCode debugger](https://vscode.readthedocs.io/en/latest/editor/deb "type": "node", "name": "APM Jest", "request": "launch", - "args": ["--runInBand", "--testPathPattern=legacy/plugins/apm"], + "args": ["--runInBand", "--testPathPattern=plugins/apm"], "cwd": "${workspaceFolder}/../../..", "console": "internalConsole", "internalConsoleOptions": "openOnSessionStart", diff --git a/x-pack/legacy/plugins/apm/e2e/.gitignore b/x-pack/plugins/apm/e2e/.gitignore similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/.gitignore rename to x-pack/plugins/apm/e2e/.gitignore diff --git a/x-pack/legacy/plugins/apm/e2e/README.md b/x-pack/plugins/apm/e2e/README.md similarity index 84% rename from x-pack/legacy/plugins/apm/e2e/README.md rename to x-pack/plugins/apm/e2e/README.md index a891d64539a3f..b630747ac2d3e 100644 --- a/x-pack/legacy/plugins/apm/e2e/README.md +++ b/x-pack/plugins/apm/e2e/README.md @@ -3,7 +3,7 @@ **Run E2E tests** ```sh -x-pack/legacy/plugins/apm/e2e/run-e2e.sh +x-pack/plugins/apm/e2e/run-e2e.sh ``` _Starts Kibana, APM Server, Elasticsearch (with sample data) and runs the tests_ @@ -16,9 +16,9 @@ The Jenkins CI uses a shell script to prepare Kibana: ```shell # Prepare and run Kibana locally -$ x-pack/legacy/plugins/apm/e2e/ci/prepare-kibana.sh +$ x-pack/plugins/apm/e2e/ci/prepare-kibana.sh # Build Docker image for Kibana -$ docker build --tag cypress --build-arg NODE_VERSION=$(cat .node-version) x-pack/legacy/plugins/apm/e2e/ci +$ docker build --tag cypress --build-arg NODE_VERSION=$(cat .node-version) x-pack/plugins/apm/e2e/ci # Run Docker image $ docker run --rm -t --user "$(id -u):$(id -g)" \ -v `pwd`:/app --network="host" \ diff --git a/x-pack/legacy/plugins/apm/e2e/ci/Dockerfile b/x-pack/plugins/apm/e2e/ci/Dockerfile similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/ci/Dockerfile rename to x-pack/plugins/apm/e2e/ci/Dockerfile diff --git a/x-pack/legacy/plugins/apm/e2e/ci/entrypoint.sh b/x-pack/plugins/apm/e2e/ci/entrypoint.sh similarity index 90% rename from x-pack/legacy/plugins/apm/e2e/ci/entrypoint.sh rename to x-pack/plugins/apm/e2e/ci/entrypoint.sh index ae5155d966e58..3349aa74dadb9 100755 --- a/x-pack/legacy/plugins/apm/e2e/ci/entrypoint.sh +++ b/x-pack/plugins/apm/e2e/ci/entrypoint.sh @@ -21,9 +21,9 @@ npm config set cache ${HOME} # --exclude=packages/ \ # --exclude=built_assets --exclude=target \ # --exclude=data /app ${HOME}/ -#cd ${HOME}/app/x-pack/legacy/plugins/apm/e2e/cypress +#cd ${HOME}/app/x-pack/plugins/apm/e2e/cypress -cd /app/x-pack/legacy/plugins/apm/e2e +cd /app/x-pack/plugins/apm/e2e ## Install dependencies for cypress CI=true npm install yarn install diff --git a/x-pack/legacy/plugins/apm/e2e/ci/kibana.e2e.yml b/x-pack/plugins/apm/e2e/ci/kibana.e2e.yml similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/ci/kibana.e2e.yml rename to x-pack/plugins/apm/e2e/ci/kibana.e2e.yml diff --git a/x-pack/legacy/plugins/apm/e2e/ci/prepare-kibana.sh b/x-pack/plugins/apm/e2e/ci/prepare-kibana.sh similarity index 95% rename from x-pack/legacy/plugins/apm/e2e/ci/prepare-kibana.sh rename to x-pack/plugins/apm/e2e/ci/prepare-kibana.sh index 6df17bd51e0e8..637f8fa9b4c74 100755 --- a/x-pack/legacy/plugins/apm/e2e/ci/prepare-kibana.sh +++ b/x-pack/plugins/apm/e2e/ci/prepare-kibana.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e -E2E_DIR="x-pack/legacy/plugins/apm/e2e" +E2E_DIR="x-pack/plugins/apm/e2e" echo "1/3 Install dependencies ..." # shellcheck disable=SC1091 diff --git a/x-pack/legacy/plugins/apm/e2e/cypress.json b/x-pack/plugins/apm/e2e/cypress.json similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress.json rename to x-pack/plugins/apm/e2e/cypress.json diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/fixtures/example.json b/x-pack/plugins/apm/e2e/cypress/fixtures/example.json similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/fixtures/example.json rename to x-pack/plugins/apm/e2e/cypress/fixtures/example.json diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/integration/apm.feature b/x-pack/plugins/apm/e2e/cypress/integration/apm.feature similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/integration/apm.feature rename to x-pack/plugins/apm/e2e/cypress/integration/apm.feature diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/integration/helpers.ts b/x-pack/plugins/apm/e2e/cypress/integration/helpers.ts similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/integration/helpers.ts rename to x-pack/plugins/apm/e2e/cypress/integration/helpers.ts diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js new file mode 100644 index 0000000000000..a462f4a504145 --- /dev/null +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -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. + */ + +module.exports = { + APM: { + 'Transaction duration charts': { + '1': '500 ms', + '2': '250 ms', + '3': '0 ms' + } + }, + __version: '4.2.0' +}; diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/plugins/index.js b/x-pack/plugins/apm/e2e/cypress/plugins/index.js similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/plugins/index.js rename to x-pack/plugins/apm/e2e/cypress/plugins/index.js diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/support/commands.js b/x-pack/plugins/apm/e2e/cypress/support/commands.js similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/support/commands.js rename to x-pack/plugins/apm/e2e/cypress/support/commands.js diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/support/index.ts b/x-pack/plugins/apm/e2e/cypress/support/index.ts similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/support/index.ts rename to x-pack/plugins/apm/e2e/cypress/support/index.ts diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/support/step_definitions/apm.ts b/x-pack/plugins/apm/e2e/cypress/support/step_definitions/apm.ts similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/support/step_definitions/apm.ts rename to x-pack/plugins/apm/e2e/cypress/support/step_definitions/apm.ts diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/typings/index.d.ts b/x-pack/plugins/apm/e2e/cypress/typings/index.d.ts similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/typings/index.d.ts rename to x-pack/plugins/apm/e2e/cypress/typings/index.d.ts diff --git a/x-pack/legacy/plugins/apm/e2e/cypress/webpack.config.js b/x-pack/plugins/apm/e2e/cypress/webpack.config.js similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/cypress/webpack.config.js rename to x-pack/plugins/apm/e2e/cypress/webpack.config.js diff --git a/x-pack/legacy/plugins/apm/e2e/ingest-data/replay.js b/x-pack/plugins/apm/e2e/ingest-data/replay.js similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/ingest-data/replay.js rename to x-pack/plugins/apm/e2e/ingest-data/replay.js diff --git a/x-pack/legacy/plugins/apm/e2e/package.json b/x-pack/plugins/apm/e2e/package.json similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/package.json rename to x-pack/plugins/apm/e2e/package.json diff --git a/x-pack/legacy/plugins/apm/e2e/run-e2e.sh b/x-pack/plugins/apm/e2e/run-e2e.sh similarity index 98% rename from x-pack/legacy/plugins/apm/e2e/run-e2e.sh rename to x-pack/plugins/apm/e2e/run-e2e.sh index 7c17c14dc9601..818d45abb0e65 100755 --- a/x-pack/legacy/plugins/apm/e2e/run-e2e.sh +++ b/x-pack/plugins/apm/e2e/run-e2e.sh @@ -27,7 +27,7 @@ cd ${E2E_DIR} # Ask user to start Kibana ################################################## echo "\n${bold}To start Kibana please run the following command:${normal} -node ./scripts/kibana --no-base-path --dev --no-dev-config --config x-pack/legacy/plugins/apm/e2e/ci/kibana.e2e.yml" +node ./scripts/kibana --no-base-path --dev --no-dev-config --config x-pack/plugins/apm/e2e/ci/kibana.e2e.yml" # # Create tmp folder diff --git a/x-pack/legacy/plugins/apm/e2e/tsconfig.json b/x-pack/plugins/apm/e2e/tsconfig.json similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/tsconfig.json rename to x-pack/plugins/apm/e2e/tsconfig.json diff --git a/x-pack/legacy/plugins/apm/e2e/yarn.lock b/x-pack/plugins/apm/e2e/yarn.lock similarity index 100% rename from x-pack/legacy/plugins/apm/e2e/yarn.lock rename to x-pack/plugins/apm/e2e/yarn.lock diff --git a/x-pack/plugins/apm/kibana.json b/x-pack/plugins/apm/kibana.json index 7ffdb676c740f..1a0ad67c7b696 100644 --- a/x-pack/plugins/apm/kibana.json +++ b/x-pack/plugins/apm/kibana.json @@ -1,13 +1,23 @@ { "id": "apm", - "server": true, "version": "8.0.0", "kibanaVersion": "kibana", - "configPath": [ - "xpack", - "apm" + "requiredPlugins": [ + "features", + "apm_oss", + "data", + "home", + "licensing", + "triggers_actions_ui" + ], + "optionalPlugins": [ + "cloud", + "usageCollection", + "taskManager", + "actions", + "alerting" ], - "ui": false, - "requiredPlugins": ["apm_oss", "data", "home", "licensing"], - "optionalPlugins": ["cloud", "usageCollection", "taskManager","actions", "alerting"] + "server": true, + "ui": true, + "configPath": ["xpack", "apm"] } diff --git a/x-pack/plugins/apm/public/application/index.tsx b/x-pack/plugins/apm/public/application/index.tsx new file mode 100644 index 0000000000000..c3738329219a8 --- /dev/null +++ b/x-pack/plugins/apm/public/application/index.tsx @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ApmRoute } from '@elastic/apm-rum-react'; +import React from 'react'; +import ReactDOM from 'react-dom'; +import { Route, Router, Switch } from 'react-router-dom'; +import styled from 'styled-components'; +import { CoreStart, AppMountParameters } from '../../../../../src/core/public'; +import { ApmPluginSetupDeps } from '../plugin'; +import { ApmPluginContext } from '../context/ApmPluginContext'; +import { LicenseProvider } from '../context/LicenseContext'; +import { LoadingIndicatorProvider } from '../context/LoadingIndicatorContext'; +import { LocationProvider } from '../context/LocationContext'; +import { MatchedRouteProvider } from '../context/MatchedRouteContext'; +import { UrlParamsProvider } from '../context/UrlParamsContext'; +import { AlertsContextProvider } from '../../../triggers_actions_ui/public'; +import { KibanaContextProvider } from '../../../../../src/plugins/kibana_react/public'; +import { px, unit, units } from '../style/variables'; +import { UpdateBreadcrumbs } from '../components/app/Main/UpdateBreadcrumbs'; +import { APMIndicesPermission } from '../components/app/APMIndicesPermission'; +import { ScrollToTopOnPathChange } from '../components/app/Main/ScrollToTopOnPathChange'; +import { routes } from '../components/app/Main/route_config'; +import { history } from '../utils/history'; +import { ConfigSchema } from '..'; +import 'react-vis/dist/style.css'; + +const MainContainer = styled.div` + min-width: ${px(unit * 50)}; + padding: ${px(units.plus)}; + height: 100%; +`; + +const App = () => { + return ( + + + + + + {routes.map((route, i) => ( + + ))} + + + + ); +}; + +const ApmAppRoot = ({ + core, + deps, + routerHistory, + config +}: { + core: CoreStart; + deps: ApmPluginSetupDeps; + routerHistory: typeof history; + config: ConfigSchema; +}) => { + const i18nCore = core.i18n; + const plugins = deps; + const apmPluginContextValue = { + config, + core, + plugins + }; + return ( + + + + + + + + + + + + + + + + + + + + + + ); +}; + +/** + * This module is rendered asynchronously in the Kibana platform. + */ +export const renderApp = ( + core: CoreStart, + deps: ApmPluginSetupDeps, + { element }: AppMountParameters, + config: ConfigSchema +) => { + ReactDOM.render( + , + element + ); + return () => ReactDOM.unmountComponentAtNode(element); +}; diff --git a/x-pack/legacy/plugins/apm/public/components/app/APMIndicesPermission/__test__/APMIndicesPermission.test.tsx b/x-pack/plugins/apm/public/components/app/APMIndicesPermission/__test__/APMIndicesPermission.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/APMIndicesPermission/__test__/APMIndicesPermission.test.tsx rename to x-pack/plugins/apm/public/components/app/APMIndicesPermission/__test__/APMIndicesPermission.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/APMIndicesPermission/index.tsx b/x-pack/plugins/apm/public/components/app/APMIndicesPermission/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/APMIndicesPermission/index.tsx rename to x-pack/plugins/apm/public/components/app/APMIndicesPermission/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ErrorTabs.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ErrorTabs.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ErrorTabs.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ErrorTabs.tsx index 33774c941ffd6..5982346d97b89 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ErrorTabs.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ErrorTabs.tsx @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import { isEmpty } from 'lodash'; -import { APMError } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; +import { APMError } from '../../../../../typings/es_schemas/ui/apm_error'; export interface ErrorTab { key: 'log_stacktrace' | 'exception_stacktrace' | 'metadata'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.test.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.test.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.tsx index 75e518a278aea..faec93013886c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/ExceptionStacktrace.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { EuiTitle } from '@elastic/eui'; -import { Exception } from '../../../../../../../../plugins/apm/typings/es_schemas/raw/error_raw'; +import { Exception } from '../../../../../typings/es_schemas/raw/error_raw'; import { Stacktrace } from '../../../shared/Stacktrace'; import { CauseStacktrace } from '../../../shared/Stacktrace/CauseStacktrace'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/__snapshots__/index.test.tsx.snap b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/__snapshots__/index.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/__snapshots__/index.test.tsx.snap rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/__snapshots__/index.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.test.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.test.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.tsx index 490bf472065e3..9e2fd776e67a3 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/DetailView/index.tsx @@ -20,8 +20,8 @@ import React from 'react'; import styled from 'styled-components'; import { first } from 'lodash'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ErrorGroupAPIResponse } from '../../../../../../../../plugins/apm/server/lib/errors/get_error_group'; -import { APMError } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; +import { ErrorGroupAPIResponse } from '../../../../../server/lib/errors/get_error_group'; +import { APMError } from '../../../../../typings/es_schemas/ui/apm_error'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { px, unit, units } from '../../../../style/variables'; import { DiscoverErrorLink } from '../../../shared/Links/DiscoverLinks/DiscoverErrorLink'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/Distribution/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx index ccd720ceee075..c40c711a590be 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupDetails/index.tsx @@ -17,7 +17,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; import React, { Fragment } from 'react'; import styled from 'styled-components'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../../plugins/apm/common/i18n'; +import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n'; import { useFetcher } from '../../../hooks/useFetcher'; import { fontFamilyCode, fontSizes, px, units } from '../../../style/variables'; import { ApmHeader } from '../../shared/ApmHeader'; @@ -25,7 +25,7 @@ import { DetailView } from './DetailView'; import { ErrorDistribution } from './Distribution'; import { useLocation } from '../../../hooks/useLocation'; import { useUrlParams } from '../../../hooks/useUrlParams'; -import { useTrackPageview } from '../../../../../../../plugins/observability/public'; +import { useTrackPageview } from '../../../../../observability/public'; const Titles = styled.div` margin-bottom: ${px(units.plus)}; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/List.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap rename to x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/__snapshots__/List.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/props.json b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/props.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/props.json rename to x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/__test__/props.json diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx index 250b9a5d188d0..695d3463d3b3d 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/List/index.tsx @@ -9,9 +9,9 @@ import numeral from '@elastic/numeral'; import { i18n } from '@kbn/i18n'; import React, { useMemo } from 'react'; import styled from 'styled-components'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../../../plugins/apm/common/i18n'; +import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ErrorGroupListAPIResponse } from '../../../../../../../../plugins/apm/server/lib/errors/get_error_groups'; +import { ErrorGroupListAPIResponse } from '../../../../../server/lib/errors/get_error_groups'; import { fontFamilyCode, fontSizes, diff --git a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx rename to x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx index 8c5a4545f1043..604893952d9d6 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ErrorGroupOverview/index.tsx @@ -17,8 +17,8 @@ import { useFetcher } from '../../../hooks/useFetcher'; import { ErrorDistribution } from '../ErrorGroupDetails/Distribution'; import { ErrorGroupList } from './List'; import { useUrlParams } from '../../../hooks/useUrlParams'; -import { useTrackPageview } from '../../../../../../../plugins/observability/public'; -import { PROJECTION } from '../../../../../../../plugins/apm/common/projections/typings'; +import { useTrackPageview } from '../../../../../observability/public'; +import { PROJECTION } from '../../../../common/projections/typings'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; const ErrorGroupOverview: React.FC = () => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx b/x-pack/plugins/apm/public/components/app/Home/Home.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Home/Home.test.tsx rename to x-pack/plugins/apm/public/components/app/Home/Home.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap b/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap rename to x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap index 2b1f835a14f4a..9f461eeb5b6fc 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap +++ b/x-pack/plugins/apm/public/components/app/Home/__snapshots__/Home.test.tsx.snap @@ -5,7 +5,6 @@ exports[`Home component should render services 1`] = ` value={ Object { "config": Object { - "indexPatternTitle": "apm-*", "serviceMapEnabled": true, "ui": Object { "enabled": false, @@ -46,7 +45,6 @@ exports[`Home component should render traces 1`] = ` value={ Object { "config": Object { - "indexPatternTitle": "apm-*", "serviceMapEnabled": true, "ui": Object { "enabled": false, diff --git a/x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx b/x-pack/plugins/apm/public/components/app/Home/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Home/index.tsx rename to x-pack/plugins/apm/public/components/app/Home/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx b/x-pack/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx rename to x-pack/plugins/apm/public/components/app/Main/ProvideBreadcrumbs.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.tsx b/x-pack/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.tsx rename to x-pack/plugins/apm/public/components/app/Main/ScrollToTopOnPathChange.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx b/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx rename to x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx b/x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx rename to x-pack/plugins/apm/public/components/app/Main/UpdateBreadcrumbs.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/__snapshots__/UpdateBreadcrumbs.test.tsx.snap b/x-pack/plugins/apm/public/components/app/Main/__snapshots__/UpdateBreadcrumbs.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Main/__snapshots__/UpdateBreadcrumbs.test.tsx.snap rename to x-pack/plugins/apm/public/components/app/Main/__snapshots__/UpdateBreadcrumbs.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx b/x-pack/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx rename to x-pack/plugins/apm/public/components/app/Main/__test__/ProvideBreadcrumbs.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx rename to x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx index c87e56fe9eff6..6d1db8c5dc6d4 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Main/route_config/index.tsx @@ -7,7 +7,7 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import { Redirect, RouteComponentProps } from 'react-router-dom'; -import { SERVICE_NODE_NAME_MISSING } from '../../../../../../../../plugins/apm/common/service_nodes'; +import { SERVICE_NODE_NAME_MISSING } from '../../../../../common/service_nodes'; import { ErrorGroupDetails } from '../../ErrorGroupDetails'; import { ServiceDetails } from '../../ServiceDetails'; import { TransactionDetails } from '../../TransactionDetails'; @@ -20,7 +20,7 @@ import { ApmIndices } from '../../Settings/ApmIndices'; import { toQuery } from '../../../shared/Links/url_helpers'; import { ServiceNodeMetrics } from '../../ServiceNodeMetrics'; import { resolveUrlParams } from '../../../../context/UrlParamsContext/resolveUrlParams'; -import { UNIDENTIFIED_SERVICE_NODES_LABEL } from '../../../../../../../../plugins/apm/common/i18n'; +import { UNIDENTIFIED_SERVICE_NODES_LABEL } from '../../../../../common/i18n'; import { TraceLink } from '../../TraceLink'; import { CustomizeUI } from '../../Settings/CustomizeUI'; import { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx rename to x-pack/plugins/apm/public/components/app/Main/route_config/route_handlers/agent_configuration.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Main/route_config/route_names.tsx b/x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Main/route_config/route_names.tsx rename to x-pack/plugins/apm/public/components/app/Main/route_config/route_names.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/AlertingFlyout/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/AlertingFlyout/index.tsx similarity index 82% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/AlertingFlyout/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/AlertingFlyout/index.tsx index 7e8d057a7be6c..a1ccb04e3c42a 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/AlertingFlyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/AlertingFlyout/index.tsx @@ -4,8 +4,8 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; -import { AlertType } from '../../../../../../../../../plugins/apm/common/alert_types'; -import { AlertAdd } from '../../../../../../../../../plugins/triggers_actions_ui/public'; +import { AlertType } from '../../../../../../common/alert_types'; +import { AlertAdd } from '../../../../../../../triggers_actions_ui/public'; type AlertAddProps = React.ComponentProps; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/index.tsx index 92b325ab00d35..75c6c79bc804a 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/AlertIntegrations/index.tsx @@ -12,7 +12,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; -import { AlertType } from '../../../../../../../../plugins/apm/common/alert_types'; +import { AlertType } from '../../../../../common/alert_types'; import { AlertingFlyout } from './AlertingFlyout'; import { useApmPluginContext } from '../../../../hooks/useApmPluginContext'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx index 131bb7f65d4b3..7ab2f7bac8ae2 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceDetailTabs.tsx @@ -7,10 +7,7 @@ import { EuiTabs } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { - isJavaAgentName, - isRumAgentName -} from '../../../../../../../plugins/apm/common/agent_name'; +import { isJavaAgentName, isRumAgentName } from '../../../../common/agent_name'; import { useAgentName } from '../../../hooks/useAgentName'; import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; import { useUrlParams } from '../../../hooks/useUrlParams'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/TransactionSelect.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/TransactionSelect.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/TransactionSelect.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/TransactionSelect.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/index.tsx index cc5c62e25b491..b7480a42ba94b 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/index.tsx @@ -6,7 +6,7 @@ import { i18n } from '@kbn/i18n'; import React, { Component } from 'react'; -import { toMountPoint } from '../../../../../../../../../../src/plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../../../../../src/plugins/kibana_react/public'; import { startMLJob } from '../../../../../services/rest/ml'; import { IUrlParams } from '../../../../../context/UrlParamsContext/types'; import { MLJobLink } from '../../../../shared/Links/MachineLearningLinks/MLJobLink'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/MachineLearningFlyout/view.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx index 85254bee12e13..3bbd8a01d0549 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/WatcherFlyout.tsx @@ -30,12 +30,13 @@ import { padLeft, range } from 'lodash'; import moment from 'moment-timezone'; import React, { Component } from 'react'; import styled from 'styled-components'; -import { toMountPoint } from '../../../../../../../../../src/plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/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 { ApmPluginContext } from '../../../../context/ApmPluginContext'; +import { getApmIndexPatternTitle } from '../../../../services/rest/index_pattern'; type ScheduleKey = keyof Schedule; @@ -149,11 +150,7 @@ export class WatcherFlyout extends Component< this.setState({ slackUrl: event.target.value }); }; - public createWatch = ({ - indexPatternTitle - }: { - indexPatternTitle: string; - }) => () => { + public createWatch = () => { const { serviceName } = this.props.urlParams; const { core } = this.context; @@ -190,19 +187,21 @@ export class WatcherFlyout extends Component< unit: 'h' }; - return createErrorGroupWatch({ - http: core.http, - emails, - schedule, - serviceName, - slackUrl, - threshold: this.state.threshold, - timeRange, - apmIndexPatternTitle: indexPatternTitle - }) - .then((id: string) => { - this.props.onClose(); - this.addSuccessToast(id); + return getApmIndexPatternTitle() + .then(indexPatternTitle => { + return createErrorGroupWatch({ + http: core.http, + emails, + schedule, + serviceName, + slackUrl, + threshold: this.state.threshold, + timeRange, + apmIndexPatternTitle: indexPatternTitle + }).then((id: string) => { + this.props.onClose(); + this.addSuccessToast(id); + }); }) .catch(e => { // eslint-disable-next-line @@ -613,26 +612,20 @@ export class WatcherFlyout extends Component< - - {({ config }) => { - return ( - - {i18n.translate( - 'xpack.apm.serviceDetails.enableErrorReportsPanel.createWatchButtonLabel', - { - defaultMessage: 'Create watch' - } - )} - - ); - }} - + this.createWatch()} + fill + disabled={ + !this.state.actions.email && !this.state.actions.slack + } + > + {i18n.translate( + 'xpack.apm.serviceDetails.enableErrorReportsPanel.createWatchButtonLabel', + { + defaultMessage: 'Create watch' + } + )} + diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/__snapshots__/createErrorGroupWatch.test.ts.snap b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/__snapshots__/createErrorGroupWatch.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/__snapshots__/createErrorGroupWatch.test.ts.snap rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/__snapshots__/createErrorGroupWatch.test.ts.snap diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/createErrorGroupWatch.test.ts diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/esResponse.ts b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/esResponse.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/esResponse.ts rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/__test__/esResponse.ts diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts index 690db9fcdd8d6..d45453e24f1c9 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts +++ b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/createErrorGroupWatch.ts @@ -17,7 +17,7 @@ import { ERROR_LOG_MESSAGE, PROCESSOR_EVENT, SERVICE_NAME -} from '../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +} from '../../../../../common/elasticsearch_fieldnames'; import { createWatch } from '../../../../services/rest/watcher'; function getSlackPathUrl(slackUrl?: string) { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/ServiceIntegrations/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceDetails/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceDetails/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/BetaBadge.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Controls.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Controls.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Controls.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Cytoscape.stories.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx index 53c86f92ee557..ad77434bca9f4 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/Cytoscape.tsx @@ -19,7 +19,7 @@ import { cytoscapeOptions, nodeHeight } from './cytoscapeOptions'; -import { useUiTracker } from '../../../../../../../plugins/observability/public'; +import { useUiTracker } from '../../../../../observability/public'; export const CytoscapeContext = createContext( undefined diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.test.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/EmptyBanner.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.test.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/EmptyBanner.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/EmptyBanner.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/LoadingOverlay.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/LoadingOverlay.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/LoadingOverlay.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/LoadingOverlay.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Buttons.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Buttons.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Buttons.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Buttons.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx index 491ebdc5aad15..bc3434f277d1c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Contents.tsx @@ -12,7 +12,7 @@ import { } from '@elastic/eui'; import cytoscape from 'cytoscape'; import React from 'react'; -import { SERVICE_FRAMEWORK_NAME } from '../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +import { SERVICE_FRAMEWORK_NAME } from '../../../../../common/elasticsearch_fieldnames'; import { Buttons } from './Buttons'; import { Info } from './Info'; import { ServiceMetricFetcher } from './ServiceMetricFetcher'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Info.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Info.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Info.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Info.tsx index e1df3b474e9de..541f4f6a1e775 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Info.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Info.tsx @@ -12,7 +12,7 @@ import styled from 'styled-components'; import { SPAN_SUBTYPE, SPAN_TYPE -} from '../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +} from '../../../../../common/elasticsearch_fieldnames'; const ItemRow = styled.div` line-height: 2; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Popover/Popover.stories.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx index 697aa6a1b652b..5e6412333a2e1 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricFetcher.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { ServiceNodeMetrics } from '../../../../../../../../plugins/apm/common/service_map'; +import { ServiceNodeMetrics } from '../../../../../common/service_map'; import { useFetcher } from '../../../../hooks/useFetcher'; import { useUrlParams } from '../../../../hooks/useUrlParams'; import { ServiceMetricList } from './ServiceMetricList'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx index 056af68cc8173..3cee986261a68 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/ServiceMetricList.tsx @@ -15,7 +15,7 @@ import { i18n } from '@kbn/i18n'; import { isNumber } from 'lodash'; import React from 'react'; import styled from 'styled-components'; -import { ServiceNodeMetrics } from '../../../../../../../../plugins/apm/common/service_map'; +import { ServiceNodeMetrics } from '../../../../../common/service_map'; import { asDuration, asPercent, tpmUnit } from '../../../../utils/formatters'; function LoadingSpinner() { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/Popover/index.tsx index 102b135f3cd1f..1c9d5092bfcf5 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/Popover/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/Popover/index.tsx @@ -14,7 +14,7 @@ import React, { useRef, useState } from 'react'; -import { SERVICE_NAME } from '../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +import { SERVICE_NAME } from '../../../../../common/elasticsearch_fieldnames'; import { CytoscapeContext } from '../Cytoscape'; import { Contents } from './Contents'; import { animationOptions } from '../cytoscapeOptions'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscape-layout-test-response.json b/x-pack/plugins/apm/public/components/app/ServiceMap/cytoscape-layout-test-response.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscape-layout-test-response.json rename to x-pack/plugins/apm/public/components/app/ServiceMap/cytoscape-layout-test-response.json diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts b/x-pack/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts rename to x-pack/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts index e9942a327b69e..554f84f0ad236 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/cytoscapeOptions.ts @@ -9,7 +9,7 @@ import { CSSProperties } from 'react'; import { SERVICE_NAME, SPAN_DESTINATION_SERVICE_RESOURCE -} from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +} from '../../../../common/elasticsearch_fieldnames'; import { defaultIcon, iconForNode } from './icons'; // IE 11 does not properly load some SVGs or draw certain shapes. This causes diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts b/x-pack/plugins/apm/public/components/app/ServiceMap/icons.ts similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons.ts index 321b39dabbbd5..9fe5cbd23b07c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons.ts +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/icons.ts @@ -5,12 +5,12 @@ */ import cytoscape from 'cytoscape'; -import { isRumAgentName } from '../../../../../../../plugins/apm/common/agent_name'; +import { isRumAgentName } from '../../../../common/agent_name'; import { AGENT_NAME, SPAN_SUBTYPE, SPAN_TYPE -} from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +} from '../../../../common/elasticsearch_fieldnames'; import awsIcon from './icons/aws.svg'; import cassandraIcon from './icons/cassandra.svg'; import darkIcon from './icons/dark.svg'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/aws.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/aws.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/aws.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/aws.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/cassandra.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/cassandra.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/cassandra.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/cassandra.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dark.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/dark.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dark.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/dark.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/database.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/database.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/database.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/database.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/default.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/default.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/default.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/default.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/documents.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/documents.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/documents.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/documents.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/dot-net.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/elasticsearch.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/elasticsearch.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/elasticsearch.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/elasticsearch.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/globe.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/globe.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/globe.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/globe.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/go.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/go.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/go.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/go.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/graphql.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/graphql.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/graphql.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/graphql.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/grpc.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/grpc.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/grpc.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/grpc.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/handlebars.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/handlebars.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/handlebars.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/handlebars.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/java.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/java.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/java.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/java.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/kafka.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/kafka.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/kafka.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/kafka.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/mongodb.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/mongodb.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/mongodb.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/mongodb.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/mysql.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/mysql.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/mysql.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/mysql.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/nodejs.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/nodejs.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/nodejs.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/nodejs.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/php.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/php.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/php.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/php.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/postgresql.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/postgresql.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/postgresql.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/postgresql.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/python.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/python.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/python.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/python.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/redis.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/redis.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/redis.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/redis.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/ruby.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/ruby.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/ruby.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/ruby.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/rumjs.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/rumjs.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/rumjs.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/rumjs.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/websocket.svg b/x-pack/plugins/apm/public/components/app/ServiceMap/icons/websocket.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/icons/websocket.svg rename to x-pack/plugins/apm/public/components/app/ServiceMap/icons/websocket.svg diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.test.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/index.test.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.test.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/index.test.tsx index d93caa601f0b6..c7e25269511bf 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.test.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/index.test.tsx @@ -6,7 +6,7 @@ import { render } from '@testing-library/react'; import React, { FunctionComponent } from 'react'; -import { License } from '../../../../../../../plugins/licensing/common/license'; +import { License } from '../../../../../licensing/common/license'; import { LicenseContext } from '../../../context/LicenseContext'; import { ServiceMap } from './'; import { MockApmPluginContextWrapper } from '../../../context/ApmPluginContext/MockApmPluginContext'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceMap/index.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMap/index.tsx index 94e42f1b91160..b57f0b047c613 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMap/index.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { invalidLicenseMessage, isValidPlatinumLicense -} from '../../../../../../../plugins/apm/common/service_map'; +} from '../../../../common/service_map'; import { useFetcher } from '../../../hooks/useFetcher'; import { useLicense } from '../../../hooks/useLicense'; import { useUrlParams } from '../../../hooks/useUrlParams'; @@ -23,7 +23,7 @@ import { EmptyBanner } from './EmptyBanner'; import { Popover } from './Popover'; import { useRefDimensions } from './useRefDimensions'; import { BetaBadge } from './BetaBadge'; -import { useTrackPageview } from '../../../../../../../plugins/observability/public'; +import { useTrackPageview } from '../../../../../observability/public'; interface ServiceMapProps { serviceName?: string; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts b/x-pack/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts rename to x-pack/plugins/apm/public/components/app/ServiceMap/useRefDimensions.ts diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceMetrics/index.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceMetrics/index.tsx index 060e635e83549..0fb8c00a2b162 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceMetrics/index.tsx @@ -16,7 +16,7 @@ import { useServiceMetricCharts } from '../../../hooks/useServiceMetricCharts'; import { MetricsChart } from '../../shared/charts/MetricsChart'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { ChartsSyncContextProvider } from '../../../context/ChartsSyncContext'; -import { PROJECTION } from '../../../../../../../plugins/apm/common/projections/typings'; +import { PROJECTION } from '../../../../common/projections/typings'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; interface ServiceMetricsProps { diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx b/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx rename to x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx index 2bf26946932ea..3929c153ae419 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceNodeMetrics/index.tsx @@ -20,7 +20,7 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; -import { SERVICE_NODE_NAME_MISSING } from '../../../../../../../plugins/apm/common/service_nodes'; +import { SERVICE_NODE_NAME_MISSING } from '../../../../common/service_nodes'; import { ApmHeader } from '../../shared/ApmHeader'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { useAgentName } from '../../../hooks/useAgentName'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx index 3af1a70ef3fdc..4e57cb47691be 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceNodeOverview/index.tsx @@ -13,9 +13,9 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; -import { UNIDENTIFIED_SERVICE_NODES_LABEL } from '../../../../../../../plugins/apm/common/i18n'; -import { SERVICE_NODE_NAME_MISSING } from '../../../../../../../plugins/apm/common/service_nodes'; -import { PROJECTION } from '../../../../../../../plugins/apm/common/projections/typings'; +import { UNIDENTIFIED_SERVICE_NODES_LABEL } from '../../../../common/i18n'; +import { SERVICE_NODE_NAME_MISSING } from '../../../../common/service_nodes'; +import { PROJECTION } from '../../../../common/projections/typings'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { ManagedTable, ITableColumn } from '../../shared/ManagedTable'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/NoServicesMessage.tsx b/x-pack/plugins/apm/public/components/app/ServiceOverview/NoServicesMessage.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/NoServicesMessage.tsx rename to x-pack/plugins/apm/public/components/app/ServiceOverview/NoServicesMessage.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/List.test.js b/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/List.test.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/List.test.js rename to x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/List.test.js diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/__snapshots__/List.test.js.snap b/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/__snapshots__/List.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/__snapshots__/List.test.js.snap rename to x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/__snapshots__/List.test.js.snap diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/props.json b/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/props.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/props.json rename to x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/__test__/props.json diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/index.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/index.tsx index 1ac29c5626e3a..7e2d03ad35899 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/ServiceList/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceOverview/ServiceList/index.tsx @@ -9,8 +9,8 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import styled from 'styled-components'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ServiceListAPIResponse } from '../../../../../../../../plugins/apm/server/lib/services/get_services'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../../../plugins/apm/common/i18n'; +import { ServiceListAPIResponse } from '../../../../../server/lib/services/get_services'; +import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; import { fontSizes, truncate } from '../../../../style/variables'; import { asDecimal, convertTo } from '../../../../utils/formatters'; import { ManagedTable } from '../../../shared/ManagedTable'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/NoServicesMessage.test.tsx b/x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/NoServicesMessage.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/NoServicesMessage.test.tsx rename to x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/NoServicesMessage.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx b/x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx rename to x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/ServiceOverview.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/NoServicesMessage.test.tsx.snap b/x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/NoServicesMessage.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/NoServicesMessage.test.tsx.snap rename to x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/NoServicesMessage.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap b/x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap rename to x-pack/plugins/apm/public/components/app/ServiceOverview/__test__/__snapshots__/ServiceOverview.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx b/x-pack/plugins/apm/public/components/app/ServiceOverview/index.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx rename to x-pack/plugins/apm/public/components/app/ServiceOverview/index.tsx index 52bc414a93a23..99b169e3ec361 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/ServiceOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/ServiceOverview/index.tsx @@ -9,13 +9,13 @@ import { EuiLink } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useEffect, useMemo } from 'react'; import url from 'url'; -import { toMountPoint } from '../../../../../../../../src/plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../../../src/plugins/kibana_react/public'; import { useFetcher } from '../../../hooks/useFetcher'; import { NoServicesMessage } from './NoServicesMessage'; import { ServiceList } from './ServiceList'; import { useUrlParams } from '../../../hooks/useUrlParams'; -import { useTrackPageview } from '../../../../../../../plugins/observability/public'; -import { PROJECTION } from '../../../../../../../plugins/apm/common/projections/typings'; +import { useTrackPageview } from '../../../../../observability/public'; +import { PROJECTION } from '../../../../common/projections/typings'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/FormRowSelect.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/FormRowSelect.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/FormRowSelect.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/FormRowSelect.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/ServicePage.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/ServicePage.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/ServicePage.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/ServicePage.tsx index 43002c79aa2b4..f4b942c7f46eb 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/ServicePage.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/ServicePage/ServicePage.tsx @@ -16,11 +16,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; import { isString } from 'lodash'; import { EuiButtonEmpty } from '@elastic/eui'; -import { AgentConfigurationIntake } from '../../../../../../../../../../plugins/apm/common/agent_configuration/configuration_types'; +import { AgentConfigurationIntake } from '../../../../../../../common/agent_configuration/configuration_types'; import { omitAllOption, getOptionLabel -} from '../../../../../../../../../../plugins/apm/common/agent_configuration/all_option'; +} from '../../../../../../../common/agent_configuration/all_option'; import { useFetcher, FETCH_STATUS } from '../../../../../../hooks/useFetcher'; import { FormRowSelect } from './FormRowSelect'; import { APMLink } from '../../../../../shared/Links/apm/APMLink'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx index baab600145b81..fcd75a05b01d9 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingFormRow.tsx @@ -17,12 +17,12 @@ import { EuiIconTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { SettingDefinition } from '../../../../../../../../../../plugins/apm/common/agent_configuration/setting_definitions/types'; -import { isValid } from '../../../../../../../../../../plugins/apm/common/agent_configuration/setting_definitions'; +import { SettingDefinition } from '../../../../../../../common/agent_configuration/setting_definitions/types'; +import { isValid } from '../../../../../../../common/agent_configuration/setting_definitions'; import { amountAndUnitToString, amountAndUnitToObject -} from '../../../../../../../../../../plugins/apm/common/agent_configuration/amount_and_unit'; +} from '../../../../../../../common/agent_configuration/amount_and_unit'; import { SelectWithPlaceholder } from '../../../../../shared/SelectWithPlaceholder'; function FormRow({ diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingsPage.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingsPage.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingsPage.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingsPage.tsx index 6d76b69600333..e41bdaf0c9c09 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingsPage.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/SettingsPage.tsx @@ -23,19 +23,19 @@ import { i18n } from '@kbn/i18n'; import { EuiButtonEmpty } from '@elastic/eui'; import { EuiCallOut } from '@elastic/eui'; import { FETCH_STATUS } from '../../../../../../hooks/useFetcher'; -import { AgentName } from '../../../../../../../../../../plugins/apm/typings/es_schemas/ui/fields/agent'; +import { AgentName } from '../../../../../../../typings/es_schemas/ui/fields/agent'; import { history } from '../../../../../../utils/history'; -import { AgentConfigurationIntake } from '../../../../../../../../../../plugins/apm/common/agent_configuration/configuration_types'; +import { AgentConfigurationIntake } from '../../../../../../../common/agent_configuration/configuration_types'; import { filterByAgent, settingDefinitions, isValid -} from '../../../../../../../../../../plugins/apm/common/agent_configuration/setting_definitions'; +} from '../../../../../../../common/agent_configuration/setting_definitions'; import { saveConfig } from './saveConfig'; import { useApmPluginContext } from '../../../../../../hooks/useApmPluginContext'; -import { useUiTracker } from '../../../../../../../../../../plugins/observability/public'; +import { useUiTracker } from '../../../../../../../../observability/public'; import { SettingFormRow } from './SettingFormRow'; -import { getOptionLabel } from '../../../../../../../../../../plugins/apm/common/agent_configuration/all_option'; +import { getOptionLabel } from '../../../../../../../common/agent_configuration/all_option'; function removeEmpty(obj: T): T { return Object.fromEntries( diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/saveConfig.ts b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/saveConfig.ts similarity index 90% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/saveConfig.ts rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/saveConfig.ts index 7e3bcd68699be..5f7354bf6f713 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/saveConfig.ts +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/SettingsPage/saveConfig.ts @@ -6,11 +6,11 @@ import { i18n } from '@kbn/i18n'; import { NotificationsStart } from 'kibana/public'; -import { AgentConfigurationIntake } from '../../../../../../../../../../plugins/apm/common/agent_configuration/configuration_types'; +import { AgentConfigurationIntake } from '../../../../../../../common/agent_configuration/configuration_types'; import { getOptionLabel, omitAllOption -} from '../../../../../../../../../../plugins/apm/common/agent_configuration/all_option'; +} from '../../../../../../../common/agent_configuration/all_option'; import { callApmApi } from '../../../../../../services/rest/createCallApmApi'; export async function saveConfig({ diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.stories.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.stories.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.stories.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.stories.tsx index 531e557b6ef86..089bc58f50a88 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.stories.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.stories.tsx @@ -13,7 +13,7 @@ import { storiesOf } from '@storybook/react'; import React from 'react'; import { HttpSetup } from 'kibana/public'; -import { AgentConfiguration } from '../../../../../../../../../plugins/apm/common/agent_configuration/configuration_types'; +import { AgentConfiguration } from '../../../../../../common/agent_configuration/configuration_types'; import { FETCH_STATUS } from '../../../../../hooks/useFetcher'; import { createCallApmApi } from '../../../../../services/rest/createCallApmApi'; import { AgentConfigurationCreateEdit } from './index'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.tsx index 638e518563f8c..3a6f94b975800 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/AgentConfigurationCreateEdit/index.tsx @@ -13,7 +13,7 @@ import { history } from '../../../../../utils/history'; import { AgentConfigurationIntake, AgentConfiguration -} from '../../../../../../../../../plugins/apm/common/agent_configuration/configuration_types'; +} from '../../../../../../common/agent_configuration/configuration_types'; import { ServicePage } from './ServicePage/ServicePage'; import { SettingsPage } from './SettingsPage/SettingsPage'; import { fromQuery, toQuery } from '../../../../shared/Links/url_helpers'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx index 267aaddc93f76..6a1a472562305 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/ConfirmDeleteModal.tsx @@ -9,8 +9,8 @@ import { EuiConfirmModal, EuiOverlayMask } from '@elastic/eui'; import { NotificationsStart } from 'kibana/public'; import { i18n } from '@kbn/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { AgentConfigurationListAPIResponse } from '../../../../../../../../../plugins/apm/server/lib/settings/agent_configuration/list_configurations'; -import { getOptionLabel } from '../../../../../../../../../plugins/apm/common/agent_configuration/all_option'; +import { AgentConfigurationListAPIResponse } from '../../../../../../server/lib/settings/agent_configuration/list_configurations'; +import { getOptionLabel } from '../../../../../../common/agent_configuration/all_option'; import { callApmApi } from '../../../../../services/rest/createCallApmApi'; import { useApmPluginContext } from '../../../../../hooks/useApmPluginContext'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/List/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/List/index.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/index.tsx index 6d5f65121d8fd..9eaa7786baca0 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/List/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/List/index.tsx @@ -20,10 +20,10 @@ import { FETCH_STATUS } from '../../../../../hooks/useFetcher'; import { ITableColumn, ManagedTable } from '../../../../shared/ManagedTable'; import { LoadingStatePrompt } from '../../../../shared/LoadingStatePrompt'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { AgentConfigurationListAPIResponse } from '../../../../../../../../../plugins/apm/server/lib/settings/agent_configuration/list_configurations'; +import { AgentConfigurationListAPIResponse } from '../../../../../../server/lib/settings/agent_configuration/list_configurations'; import { TimestampTooltip } from '../../../../shared/TimestampTooltip'; import { px, units } from '../../../../../style/variables'; -import { getOptionLabel } from '../../../../../../../../../plugins/apm/common/agent_configuration/all_option'; +import { getOptionLabel } from '../../../../../../common/agent_configuration/all_option'; import { createAgentConfigurationHref, editAgentConfigurationHref diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/index.tsx rename to x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/index.tsx index 8171e339adc82..4349e542449cc 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/AgentConfigurations/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/AgentConfigurations/index.tsx @@ -17,7 +17,7 @@ import { import { isEmpty } from 'lodash'; import { useFetcher } from '../../../../hooks/useFetcher'; import { AgentConfigurationList } from './List'; -import { useTrackPageview } from '../../../../../../../../plugins/observability/public'; +import { useTrackPageview } from '../../../../../../observability/public'; import { createAgentConfigurationHref } from '../../../shared/Links/apm/agentConfigurationLinks'; export function AgentConfigurations() { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx b/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx rename to x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx rename to x-pack/plugins/apm/public/components/app/Settings/ApmIndices/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateCustomLinkButton.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateCustomLinkButton.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateCustomLinkButton.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CreateCustomLinkButton.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/DeleteButton.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/Documentation.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/Documentation.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/Documentation.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/Documentation.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx index fb8ffe6722c87..9c244e3cde411 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FiltersSection.tsx @@ -19,7 +19,7 @@ import React from 'react'; import { Filter, FilterKey -} from '../../../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +} from '../../../../../../../common/custom_link/custom_link_types'; import { DEFAULT_OPTION, FILTER_SELECT_OPTIONS, diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/FlyoutFooter.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.test.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.test.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx index 8edfb176a1af8..8fed838a48261 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkPreview.tsx @@ -17,8 +17,8 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { debounce } from 'lodash'; -import { Filter } from '../../../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; -import { Transaction } from '../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Filter } from '../../../../../../../common/custom_link/custom_link_types'; +import { Transaction } from '../../../../../../../typings/es_schemas/ui/transaction'; import { callApmApi } from '../../../../../../services/rest/createCallApmApi'; import { replaceTemplateVariables, convertFiltersToQuery } from './helper'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx index 630f7148ad408..210033888d90c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/LinkSection.tsx @@ -12,7 +12,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { CustomLink } from '../../../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +import { CustomLink } from '../../../../../../../common/custom_link/custom_link_types'; import { Documentation } from './Documentation'; interface InputField { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts index 0a63cfcff9aa5..49e381aab675d 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.test.ts @@ -7,7 +7,7 @@ import { getSelectOptions, replaceTemplateVariables } from '../CustomLinkFlyout/helper'; -import { Transaction } from '../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../../typings/es_schemas/ui/transaction'; describe('Custom link helper', () => { describe('getSelectOptions', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts similarity index 91% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts index 7bfdbf1655e0d..8c35b8fe77506 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/helper.ts @@ -6,12 +6,12 @@ import { i18n } from '@kbn/i18n'; import Mustache from 'mustache'; import { isEmpty, get } from 'lodash'; -import { FILTER_OPTIONS } from '../../../../../../../../../../plugins/apm/common/custom_link/custom_link_filter_options'; +import { FILTER_OPTIONS } from '../../../../../../../common/custom_link/custom_link_filter_options'; import { Filter, FilterKey -} from '../../../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; -import { Transaction } from '../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +} from '../../../../../../../common/custom_link/custom_link_types'; +import { Transaction } from '../../../../../../../typings/es_schemas/ui/transaction'; interface FilterSelectOption { value: 'DEFAULT' | FilterKey; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx index 0b25a0a79edd9..150147d9af405 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/index.tsx @@ -14,7 +14,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useState } from 'react'; -import { Filter } from '../../../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +import { Filter } from '../../../../../../../common/custom_link/custom_link_types'; import { useApmPluginContext } from '../../../../../../hooks/useApmPluginContext'; import { FiltersSection } from './FiltersSection'; import { FlyoutFooter } from './FlyoutFooter'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts index 9cbaf16320a6b..685b3ab022950 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkFlyout/saveCustomLink.ts @@ -9,7 +9,7 @@ import { NotificationsStart } from 'kibana/public'; import { Filter, CustomLink -} from '../../../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +} from '../../../../../../../common/custom_link/custom_link_types'; import { callApmApi } from '../../../../../../services/rest/createCallApmApi'; export async function saveCustomLink({ diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkTable.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkTable.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkTable.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkTable.tsx index 68e6ee52af0b0..d68fb757e53d1 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkTable.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/CustomLinkTable.tsx @@ -13,7 +13,7 @@ import { EuiSpacer } from '@elastic/eui'; import { isEmpty } from 'lodash'; -import { CustomLink } from '../../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +import { CustomLink } from '../../../../../../common/custom_link/custom_link_types'; import { units, px } from '../../../../../style/variables'; import { ManagedTable } from '../../../../shared/ManagedTable'; import { TimestampTooltip } from '../../../../shared/TimestampTooltip'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/EmptyPrompt.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/EmptyPrompt.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/EmptyPrompt.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/EmptyPrompt.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/Title.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx similarity index 99% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx index e5c20b260e097..32a08f5ffaf7c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.test.tsx @@ -8,7 +8,7 @@ import { fireEvent, render, wait, RenderResult } from '@testing-library/react'; import React from 'react'; import { act } from 'react-dom/test-utils'; import * as apmApi from '../../../../../services/rest/createCallApmApi'; -import { License } from '../../../../../../../../../plugins/licensing/common/license'; +import { License } from '../../../../../../../licensing/common/license'; import * as hooks from '../../../../../hooks/useFetcher'; import { LicenseContext } from '../../../../../context/LicenseContext'; import { CustomLinkOverview } from '.'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx index e9a915e0f59bc..b94ce513bc210 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx +++ b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/CustomLink/index.tsx @@ -8,7 +8,7 @@ import { EuiPanel, EuiSpacer, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { isEmpty } from 'lodash'; import React, { useEffect, useState } from 'react'; import { i18n } from '@kbn/i18n'; -import { CustomLink } from '../../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +import { CustomLink } from '../../../../../../common/custom_link/custom_link_types'; import { useLicense } from '../../../../../hooks/useLicense'; import { useFetcher, FETCH_STATUS } from '../../../../../hooks/useFetcher'; import { CustomLinkFlyout } from './CustomLinkFlyout'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx rename to x-pack/plugins/apm/public/components/app/Settings/CustomizeUI/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/Settings/index.tsx b/x-pack/plugins/apm/public/components/app/Settings/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/Settings/index.tsx rename to x-pack/plugins/apm/public/components/app/Settings/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx b/x-pack/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx rename to x-pack/plugins/apm/public/components/app/TraceLink/__test__/TraceLink.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TraceLink/index.tsx b/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/app/TraceLink/index.tsx rename to x-pack/plugins/apm/public/components/app/TraceLink/index.tsx index f0301f8917d10..04d830f4649d4 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TraceLink/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TraceLink/index.tsx @@ -9,8 +9,8 @@ import React from 'react'; import { Redirect } from 'react-router-dom'; import styled from 'styled-components'; import url from 'url'; -import { TRACE_ID } from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; -import { Transaction } from '../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { TRACE_ID } from '../../../../common/elasticsearch_fieldnames'; +import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { FETCH_STATUS, useFetcher } from '../../../hooks/useFetcher'; import { useUrlParams } from '../../../hooks/useUrlParams'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TraceOverview/TraceList.tsx b/x-pack/plugins/apm/public/components/app/TraceOverview/TraceList.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/TraceOverview/TraceList.tsx rename to x-pack/plugins/apm/public/components/app/TraceOverview/TraceList.tsx index 91f3051acf077..92d5a38cc11ca 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TraceOverview/TraceList.tsx +++ b/x-pack/plugins/apm/public/components/app/TraceOverview/TraceList.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; import styled from 'styled-components'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ITransactionGroup } from '../../../../../../../plugins/apm/server/lib/transaction_groups/transform'; +import { ITransactionGroup } from '../../../../server/lib/transaction_groups/transform'; import { fontSizes, truncate } from '../../../style/variables'; import { convertTo } from '../../../utils/formatters'; import { EmptyMessage } from '../../shared/EmptyMessage'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TraceOverview/index.tsx b/x-pack/plugins/apm/public/components/app/TraceOverview/index.tsx similarity index 91% rename from x-pack/legacy/plugins/apm/public/components/app/TraceOverview/index.tsx rename to x-pack/plugins/apm/public/components/app/TraceOverview/index.tsx index bfbad78a5c026..a7fa927f9e9b1 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TraceOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TraceOverview/index.tsx @@ -9,9 +9,9 @@ import React, { useMemo } from 'react'; import { FETCH_STATUS, useFetcher } from '../../../hooks/useFetcher'; import { TraceList } from './TraceList'; import { useUrlParams } from '../../../hooks/useUrlParams'; -import { useTrackPageview } from '../../../../../../../plugins/observability/public'; +import { useTrackPageview } from '../../../../../observability/public'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; -import { PROJECTION } from '../../../../../../../plugins/apm/common/projections/typings'; +import { PROJECTION } from '../../../../common/projections/typings'; export function TraceOverview() { const { urlParams, uiFilters } = useUrlParams(); diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/__test__/distribution.test.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/__test__/distribution.test.ts similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/__test__/distribution.test.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/__test__/distribution.test.ts index 08682fb3be842..7ad0a77505b9d 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/__test__/distribution.test.ts +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/__test__/distribution.test.ts @@ -6,7 +6,7 @@ import { getFormattedBuckets } from '../index'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { IBucket } from '../../../../../../../../../plugins/apm/server/lib/transactions/distribution/get_buckets/transform'; +import { IBucket } from '../../../../../../server/lib/transactions/distribution/get_buckets/transform'; describe('Distribution', () => { it('getFormattedBuckets', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx index e70133aabb679..b7dbfbdbd7d7e 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/Distribution/index.tsx @@ -10,9 +10,9 @@ import d3 from 'd3'; import React, { FunctionComponent, useCallback } from 'react'; import { isEmpty } from 'lodash'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TransactionDistributionAPIResponse } from '../../../../../../../../plugins/apm/server/lib/transactions/distribution'; +import { TransactionDistributionAPIResponse } from '../../../../../server/lib/transactions/distribution'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { IBucket } from '../../../../../../../../plugins/apm/server/lib/transactions/distribution/get_buckets/transform'; +import { IBucket } from '../../../../../server/lib/transactions/distribution/get_buckets/transform'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { getDurationFormatter } from '../../../../utils/formatters'; // @ts-ignore diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/ErrorCount.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/ErrorCount.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/ErrorCount.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/ErrorCount.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/MaybeViewTraceLink.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/MaybeViewTraceLink.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/MaybeViewTraceLink.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/MaybeViewTraceLink.tsx index 4e105957f5f9d..1db8e02e38692 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/MaybeViewTraceLink.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/MaybeViewTraceLink.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { EuiButton, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Transaction as ITransaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction as ITransaction } from '../../../../../typings/es_schemas/ui/transaction'; import { TransactionDetailLink } from '../../../shared/Links/apm/TransactionDetailLink'; import { IWaterfall } from './WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/PercentOfParent.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/TransactionTabs.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/TransactionTabs.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/TransactionTabs.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/TransactionTabs.tsx index 9026dd90ddceb..27e0584c696c1 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/TransactionTabs.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/TransactionTabs.tsx @@ -8,7 +8,7 @@ import { EuiSpacer, EuiTab, EuiTabs } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { Location } from 'history'; import React from 'react'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; import { history } from '../../../../utils/history'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_agent_marks.test.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_agent_marks.test.ts similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_agent_marks.test.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_agent_marks.test.ts index 030729522f35e..ae908b25cc615 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_agent_marks.test.ts +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_agent_marks.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Transaction } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { getAgentMarks } from '../get_agent_marks'; describe('getAgentMarks', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_error_marks.test.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_error_marks.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_error_marks.test.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/__test__/get_error_marks.test.ts diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks.ts similarity index 87% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks.ts index 1dcb1598662c9..2bc64e30b4f7e 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks.ts +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_agent_marks.ts @@ -5,7 +5,7 @@ */ import { sortBy } from 'lodash'; -import { Transaction } from '../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../../typings/es_schemas/ui/transaction'; import { Mark } from '.'; // Extends Mark without adding new properties to it. diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_error_marks.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_error_marks.ts similarity index 89% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_error_marks.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_error_marks.ts index a9694efcbcae7..ad54cec5c26a7 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_error_marks.ts +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/get_error_marks.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ import { isEmpty } from 'lodash'; -import { ErrorRaw } from '../../../../../../../../../../plugins/apm/typings/es_schemas/raw/error_raw'; +import { ErrorRaw } from '../../../../../../../typings/es_schemas/raw/error_raw'; import { IWaterfallError, IServiceColors diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/index.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/index.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/index.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Marks/index.ts diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/ServiceLegends.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/ServiceLegends.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/ServiceLegends.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/ServiceLegends.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/FlyoutTopLevelProperties.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/FlyoutTopLevelProperties.tsx similarity index 90% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/FlyoutTopLevelProperties.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/FlyoutTopLevelProperties.tsx index 6e58dbc5b6ea3..bbc457450e475 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/FlyoutTopLevelProperties.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/FlyoutTopLevelProperties.tsx @@ -9,8 +9,8 @@ import React from 'react'; import { SERVICE_NAME, TRANSACTION_NAME -} from '../../../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; -import { Transaction } from '../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +} from '../../../../../../../common/elasticsearch_fieldnames'; +import { Transaction } from '../../../../../../../typings/es_schemas/ui/transaction'; import { TransactionDetailLink } from '../../../../../shared/Links/apm/TransactionDetailLink'; import { StickyProperties } from '../../../../../shared/StickyProperties'; import { TransactionOverviewLink } from '../../../../../shared/Links/apm/TransactionOverviewLink'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/ResponsiveFlyout.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/ResponsiveFlyout.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/ResponsiveFlyout.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/ResponsiveFlyout.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx index 6200d5f098ad5..7a08a84bf30ba 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/DatabaseContext.tsx @@ -18,7 +18,7 @@ import SyntaxHighlighter, { // @ts-ignore import { xcode } from 'react-syntax-highlighter/dist/styles'; import styled from 'styled-components'; -import { Span } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; +import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; import { borderRadius, fontFamilyCode, diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/HttpContext.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/HttpContext.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/HttpContext.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/HttpContext.tsx index 438e88df3351d..28564481074fa 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/HttpContext.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/HttpContext.tsx @@ -17,7 +17,7 @@ import { unit, units } from '../../../../../../../style/variables'; -import { Span } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; +import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; const ContextUrl = styled.div` padding: ${px(units.half)} ${px(unit)}; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/StickySpanProperties.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/StickySpanProperties.tsx similarity index 86% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/StickySpanProperties.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/StickySpanProperties.tsx index 621497a0b22e0..d49959c5cbffb 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/StickySpanProperties.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/StickySpanProperties.tsx @@ -6,14 +6,14 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; -import { Transaction } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { SPAN_NAME, TRANSACTION_NAME, SERVICE_NAME -} from '../../../../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../../../../../../plugins/apm/common/i18n'; -import { Span } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; +} from '../../../../../../../../common/elasticsearch_fieldnames'; +import { NOT_AVAILABLE_LABEL } from '../../../../../../../../common/i18n'; +import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; import { StickyProperties } from '../../../../../../shared/StickyProperties'; import { TransactionOverviewLink } from '../../../../../../shared/Links/apm/TransactionOverviewLink'; import { TransactionDetailLink } from '../../../../../../shared/Links/apm/TransactionDetailLink'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/TruncateHeightSection.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/TruncateHeightSection.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/TruncateHeightSection.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/TruncateHeightSection.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx index f57ddb5cf69a2..1da22516629f2 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SpanFlyout/index.tsx @@ -25,8 +25,8 @@ import { px, units } from '../../../../../../../style/variables'; import { Summary } from '../../../../../../shared/Summary'; import { TimestampTooltip } from '../../../../../../shared/TimestampTooltip'; import { DurationSummaryItem } from '../../../../../../shared/Summary/DurationSummaryItem'; -import { Span } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; -import { Transaction } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; +import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { DiscoverSpanLink } from '../../../../../../shared/Links/DiscoverLinks/DiscoverSpanLink'; import { Stacktrace } from '../../../../../../shared/Stacktrace'; import { ResponsiveFlyout } from '../ResponsiveFlyout'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.stories.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/SyncBadge.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/DroppedSpansWarning.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/DroppedSpansWarning.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/DroppedSpansWarning.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/DroppedSpansWarning.tsx index 85cf0b642530f..87ecb96f74735 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/DroppedSpansWarning.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/DroppedSpansWarning.tsx @@ -7,7 +7,7 @@ import { EuiCallOut, EuiHorizontalRule } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { Transaction } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { ElasticDocsLink } from '../../../../../../shared/Links/ElasticDocsLink'; export function DroppedSpansWarning({ diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx index e24414bb28d52..5fb679818f0a7 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/TransactionFlyout/index.tsx @@ -16,7 +16,7 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; -import { Transaction } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { TransactionActionMenu } from '../../../../../../shared/TransactionActionMenu/TransactionActionMenu'; import { TransactionSummary } from '../../../../../../shared/Summary/TransactionSummary'; import { FlyoutTopLevelProperties } from '../FlyoutTopLevelProperties'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallFlyout.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallFlyout.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallFlyout.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallFlyout.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx index 5c6e0cc5ce435..d8edcce46c2d7 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/WaterfallItem.tsx @@ -10,13 +10,13 @@ import styled from 'styled-components'; import { EuiIcon, EuiText, EuiTitle, EuiToolTip } from '@elastic/eui'; import theme from '@elastic/eui/dist/eui_theme_light.json'; import { i18n } from '@kbn/i18n'; -import { isRumAgentName } from '../../../../../../../../../../plugins/apm/common/agent_name'; +import { isRumAgentName } from '../../../../../../../common/agent_name'; import { px, unit, units } from '../../../../../../style/variables'; import { asDuration } from '../../../../../../utils/formatters'; import { ErrorCount } from '../../ErrorCount'; import { IWaterfallItem } from './waterfall_helpers/waterfall_helpers'; import { ErrorOverviewLink } from '../../../../../shared/Links/apm/ErrorOverviewLink'; -import { TRACE_ID } from '../../../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +import { TRACE_ID } from '../../../../../../../common/elasticsearch_fieldnames'; import { SyncBadge } from './SyncBadge'; import { Margins } from '../../../../../shared/charts/Timeline'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/__snapshots__/waterfall_helpers.test.ts.snap diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/spans.json b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/spans.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/spans.json rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/spans.json diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/transaction.json b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/transaction.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/transaction.json rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/mock_responses/transaction.json diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts index e0a01e9422c85..75304932ed2ba 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.test.ts @@ -5,8 +5,8 @@ */ import { groupBy } from 'lodash'; -import { Span } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; -import { Transaction } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; +import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; import { getClockSkew, getOrderedWaterfallItems, @@ -15,7 +15,7 @@ import { IWaterfallTransaction, IWaterfallError } from './waterfall_helpers'; -import { APMError } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; +import { APMError } from '../../../../../../../../typings/es_schemas/ui/apm_error'; describe('waterfall_helpers', () => { describe('getWaterfall', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts index 73193cc7c9dbb..8ddce66f0b853 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/Waterfall/waterfall_helpers/waterfall_helpers.ts @@ -16,10 +16,10 @@ import { zipObject } from 'lodash'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TraceAPIResponse } from '../../../../../../../../../../../plugins/apm/server/lib/traces/get_trace'; -import { APMError } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; -import { Span } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; -import { Transaction } from '../../../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { TraceAPIResponse } from '../../../../../../../../server/lib/traces/get_trace'; +import { APMError } from '../../../../../../../../typings/es_schemas/ui/apm_error'; +import { Span } from '../../../../../../../../typings/es_schemas/ui/span'; +import { Transaction } from '../../../../../../../../typings/es_schemas/ui/transaction'; interface IWaterfallGroup { [key: string]: IWaterfallItem[]; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx index f681f4dfc675a..87710fb9b8d96 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/WaterfallContainer.stories.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { storiesOf } from '@storybook/react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TraceAPIResponse } from '../../../../../../../../../plugins/apm/server/lib/traces/get_trace'; +import { TraceAPIResponse } from '../../../../../../server/lib/traces/get_trace'; import { WaterfallContainer } from './index'; import { location, diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/WaterfallContainer/waterfallContainer.stories.data.ts diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/__tests__/ErrorCount.test.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/__tests__/ErrorCount.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/__tests__/ErrorCount.test.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/__tests__/ErrorCount.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/index.tsx index 1082052c6929d..056e9cdb75148 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/WaterfallWithSummmary/index.tsx @@ -17,7 +17,7 @@ import { i18n } from '@kbn/i18n'; import { Location } from 'history'; import React, { useEffect, useState } from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { IBucket } from '../../../../../../../../plugins/apm/server/lib/transactions/distribution/get_buckets/transform'; +import { IBucket } from '../../../../../server/lib/transactions/distribution/get_buckets/transform'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { history } from '../../../../utils/history'; import { fromQuery, toQuery } from '../../../shared/Links/url_helpers'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx index e2634be0e0be8..2544dc2a1a77c 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionDetails/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionDetails/index.tsx @@ -26,8 +26,8 @@ import { useUrlParams } from '../../../hooks/useUrlParams'; import { FETCH_STATUS } from '../../../hooks/useFetcher'; import { TransactionBreakdown } from '../../shared/TransactionBreakdown'; import { ChartsSyncContextProvider } from '../../../context/ChartsSyncContext'; -import { useTrackPageview } from '../../../../../../../plugins/observability/public'; -import { PROJECTION } from '../../../../../../../plugins/apm/common/projections/typings'; +import { useTrackPageview } from '../../../../../observability/public'; +import { PROJECTION } from '../../../../common/projections/typings'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; import { HeightRetainer } from '../../shared/HeightRetainer'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/List/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionOverview/List/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/List/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionOverview/List/index.tsx index 16fda7c600906..e3b33f11d0805 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/List/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionOverview/List/index.tsx @@ -8,9 +8,9 @@ import { EuiIcon, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { useMemo } from 'react'; import styled from 'styled-components'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../../../plugins/apm/common/i18n'; +import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ITransactionGroup } from '../../../../../../../../plugins/apm/server/lib/transaction_groups/transform'; +import { ITransactionGroup } from '../../../../../server/lib/transaction_groups/transform'; import { fontFamilyCode, truncate } from '../../../../style/variables'; import { asDecimal, convertTo } from '../../../../utils/formatters'; import { ImpactBar } from '../../../shared/ImpactBar'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx b/x-pack/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx rename to x-pack/plugins/apm/public/components/app/TransactionOverview/__jest__/TransactionOverview.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx b/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx rename to x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx index b008c98417867..60aac3fcdfeef 100644 --- a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/TransactionOverview/index.tsx @@ -27,10 +27,10 @@ import { getHasMLJob } from '../../../services/rest/ml'; import { history } from '../../../utils/history'; import { useLocation } from '../../../hooks/useLocation'; import { ChartsSyncContextProvider } from '../../../context/ChartsSyncContext'; -import { useTrackPageview } from '../../../../../../../plugins/observability/public'; +import { useTrackPageview } from '../../../../../observability/public'; import { fromQuery, toQuery } from '../../shared/Links/url_helpers'; import { LocalUIFilters } from '../../shared/LocalUIFilters'; -import { PROJECTION } from '../../../../../../../plugins/apm/common/projections/typings'; +import { PROJECTION } from '../../../../common/projections/typings'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { useServiceTransactionTypes } from '../../../hooks/useServiceTransactionTypes'; import { TransactionTypeFilter } from '../../shared/LocalUIFilters/TransactionTypeFilter'; diff --git a/x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/useRedirect.ts b/x-pack/plugins/apm/public/components/app/TransactionOverview/useRedirect.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/app/TransactionOverview/useRedirect.ts rename to x-pack/plugins/apm/public/components/app/TransactionOverview/useRedirect.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ApmHeader/index.tsx b/x-pack/plugins/apm/public/components/shared/ApmHeader/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ApmHeader/index.tsx rename to x-pack/plugins/apm/public/components/shared/ApmHeader/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx b/x-pack/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx rename to x-pack/plugins/apm/public/components/shared/DatePicker/__test__/DatePicker.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/DatePicker/index.tsx b/x-pack/plugins/apm/public/components/shared/DatePicker/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/DatePicker/index.tsx rename to x-pack/plugins/apm/public/components/shared/DatePicker/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/EmptyMessage.tsx b/x-pack/plugins/apm/public/components/shared/EmptyMessage.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/EmptyMessage.tsx rename to x-pack/plugins/apm/public/components/shared/EmptyMessage.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/EnvironmentBadge/index.tsx b/x-pack/plugins/apm/public/components/shared/EnvironmentBadge/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/EnvironmentBadge/index.tsx rename to x-pack/plugins/apm/public/components/shared/EnvironmentBadge/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx b/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx rename to x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx index e911011f0979c..d17b3b7689b19 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/EnvironmentFilter/index.tsx @@ -15,7 +15,7 @@ import { fromQuery, toQuery } from '../Links/url_helpers'; import { ENVIRONMENT_ALL, ENVIRONMENT_NOT_DEFINED -} from '../../../../../../../plugins/apm/common/environment_filter_values'; +} from '../../../../common/environment_filter_values'; function updateEnvironmentUrl( location: ReturnType, diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.stories.tsx b/x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.stories.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.stories.tsx rename to x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.stories.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx b/x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx rename to x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx index b7e23c2979cb8..658def7ddbb57 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/ErrorRateAlertTrigger/index.tsx @@ -7,8 +7,8 @@ import React from 'react'; import { EuiFieldNumber } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { isFinite } from 'lodash'; -import { ForLastExpression } from '../../../../../../../plugins/triggers_actions_ui/public'; -import { ALERT_TYPES_CONFIG } from '../../../../../../../plugins/apm/common/alert_types'; +import { ForLastExpression } from '../../../../../triggers_actions_ui/public'; +import { ALERT_TYPES_CONFIG } from '../../../../common/alert_types'; import { ServiceAlertTrigger } from '../ServiceAlertTrigger'; import { PopoverExpression } from '../ServiceAlertTrigger/PopoverExpression'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ErrorStatePrompt.tsx b/x-pack/plugins/apm/public/components/shared/ErrorStatePrompt.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ErrorStatePrompt.tsx rename to x-pack/plugins/apm/public/components/shared/ErrorStatePrompt.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/EuiTabLink.tsx b/x-pack/plugins/apm/public/components/shared/EuiTabLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/EuiTabLink.tsx rename to x-pack/plugins/apm/public/components/shared/EuiTabLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/HeightRetainer/index.tsx b/x-pack/plugins/apm/public/components/shared/HeightRetainer/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/HeightRetainer/index.tsx rename to x-pack/plugins/apm/public/components/shared/HeightRetainer/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ImpactBar/__test__/ImpactBar.test.js b/x-pack/plugins/apm/public/components/shared/ImpactBar/__test__/ImpactBar.test.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ImpactBar/__test__/ImpactBar.test.js rename to x-pack/plugins/apm/public/components/shared/ImpactBar/__test__/ImpactBar.test.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ImpactBar/__test__/__snapshots__/ImpactBar.test.js.snap b/x-pack/plugins/apm/public/components/shared/ImpactBar/__test__/__snapshots__/ImpactBar.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ImpactBar/__test__/__snapshots__/ImpactBar.test.js.snap rename to x-pack/plugins/apm/public/components/shared/ImpactBar/__test__/__snapshots__/ImpactBar.test.js.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ImpactBar/index.tsx b/x-pack/plugins/apm/public/components/shared/ImpactBar/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ImpactBar/index.tsx rename to x-pack/plugins/apm/public/components/shared/ImpactBar/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KeyValueTable/FormattedValue.tsx b/x-pack/plugins/apm/public/components/shared/KeyValueTable/FormattedValue.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/KeyValueTable/FormattedValue.tsx rename to x-pack/plugins/apm/public/components/shared/KeyValueTable/FormattedValue.tsx index 4de07f75ff84f..d33960fe5196b 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KeyValueTable/FormattedValue.tsx +++ b/x-pack/plugins/apm/public/components/shared/KeyValueTable/FormattedValue.tsx @@ -8,7 +8,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { isBoolean, isNumber, isObject } from 'lodash'; import React from 'react'; import styled from 'styled-components'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../../plugins/apm/common/i18n'; +import { NOT_AVAILABLE_LABEL } from '../../../../common/i18n'; const EmptyValue = styled.span` color: ${theme.euiColorMediumShade}; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KeyValueTable/__test__/KeyValueTable.test.tsx b/x-pack/plugins/apm/public/components/shared/KeyValueTable/__test__/KeyValueTable.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/KeyValueTable/__test__/KeyValueTable.test.tsx rename to x-pack/plugins/apm/public/components/shared/KeyValueTable/__test__/KeyValueTable.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KeyValueTable/index.tsx b/x-pack/plugins/apm/public/components/shared/KeyValueTable/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/KeyValueTable/index.tsx rename to x-pack/plugins/apm/public/components/shared/KeyValueTable/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/ClickOutside.js b/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/ClickOutside.js similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/ClickOutside.js rename to x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/ClickOutside.js index 5ad256efe0945..93a95c844a975 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/ClickOutside.js +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/ClickOutside.js @@ -27,6 +27,7 @@ export default class ClickOutside extends Component { }; render() { + // eslint-disable-next-line no-unused-vars const { onClickOutside, ...restProps } = this.props; return (
diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestion.js b/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestion.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestion.js rename to x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestion.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestions.js b/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestions.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestions.js rename to x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/Suggestions.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js b/x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js rename to x-pack/plugins/apm/public/components/shared/KueryBar/Typeahead/index.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts b/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts rename to x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts index 19a9ae9538ad6..f4628524cced5 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/get_bool_filter.ts @@ -4,14 +4,14 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ESFilter } from '../../../../../../../plugins/apm/typings/elasticsearch'; +import { ESFilter } from '../../../../typings/elasticsearch'; import { TRANSACTION_TYPE, ERROR_GROUP_ID, PROCESSOR_EVENT, TRANSACTION_NAME, SERVICE_NAME -} from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +} from '../../../../common/elasticsearch_fieldnames'; import { IUrlParams } from '../../../context/UrlParamsContext/types'; export function getBoolFilter(urlParams: IUrlParams) { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx rename to x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx index dba31822dd23e..2622d08d4779d 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/KueryBar/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/KueryBar/index.tsx @@ -21,7 +21,7 @@ import { QuerySuggestion, esKuery, IIndexPattern -} from '../../../../../../../../src/plugins/data/public'; +} from '../../../../../../../src/plugins/data/public'; const Container = styled.div` margin-bottom: 10px; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/LicensePrompt/LicensePrompt.stories.tsx b/x-pack/plugins/apm/public/components/shared/LicensePrompt/LicensePrompt.stories.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/LicensePrompt/LicensePrompt.stories.tsx rename to x-pack/plugins/apm/public/components/shared/LicensePrompt/LicensePrompt.stories.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/LicensePrompt/index.tsx b/x-pack/plugins/apm/public/components/shared/LicensePrompt/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/LicensePrompt/index.tsx rename to x-pack/plugins/apm/public/components/shared/LicensePrompt/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverErrorLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverErrorLink.tsx similarity index 85% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverErrorLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverErrorLink.tsx index 806d9f73369c3..05e4080d5d0b7 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverErrorLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverErrorLink.tsx @@ -8,8 +8,8 @@ import React from 'react'; import { ERROR_GROUP_ID, SERVICE_NAME -} from '../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; -import { APMError } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; +} from '../../../../../common/elasticsearch_fieldnames'; +import { APMError } from '../../../../../typings/es_schemas/ui/apm_error'; import { DiscoverLink } from './DiscoverLink'; function getDiscoverQuery(error: APMError, kuery?: string) { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx index 6dc93292956fa..b58a450d26644 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverLink.tsx @@ -11,7 +11,7 @@ import url from 'url'; import rison, { RisonValue } from 'rison-node'; import { useLocation } from '../../../../hooks/useLocation'; import { getTimepickerRisonData } from '../rison_helpers'; -import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../../../../plugins/apm/common/index_pattern_constants'; +import { APM_STATIC_INDEX_PATTERN_ID } from '../../../../../common/index_pattern_constants'; import { useApmPluginContext } from '../../../../hooks/useApmPluginContext'; import { AppMountContextBasePath } from '../../../../context/ApmPluginContext'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverSpanLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverSpanLink.tsx similarity index 79% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverSpanLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverSpanLink.tsx index 8fe5be28def22..ac9e33b3acd69 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverSpanLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverSpanLink.tsx @@ -5,8 +5,8 @@ */ import React from 'react'; -import { SPAN_ID } from '../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; -import { Span } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; +import { SPAN_ID } from '../../../../../common/elasticsearch_fieldnames'; +import { Span } from '../../../../../typings/es_schemas/ui/span'; import { DiscoverLink } from './DiscoverLink'; function getDiscoverQuery(span: Span) { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverTransactionLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverTransactionLink.tsx similarity index 85% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverTransactionLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverTransactionLink.tsx index b0af33fd7d7f7..a5f4df7dbac1b 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverTransactionLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/DiscoverTransactionLink.tsx @@ -9,8 +9,8 @@ import { PROCESSOR_EVENT, TRACE_ID, TRANSACTION_ID -} from '../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +} from '../../../../../common/elasticsearch_fieldnames'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { DiscoverLink } from './DiscoverLink'; export function getDiscoverQuery(transaction: Transaction) { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorButton.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorButton.test.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorButton.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorButton.test.tsx index eeb9fd20a4bcb..acf8d89432b23 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorButton.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorButton.test.tsx @@ -6,7 +6,7 @@ import { shallow, ShallowWrapper } from 'enzyme'; import React from 'react'; -import { APMError } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; +import { APMError } from '../../../../../../typings/es_schemas/ui/apm_error'; import { DiscoverErrorLink } from '../DiscoverErrorLink'; describe('DiscoverErrorLink without kuery', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorLink.test.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorLink.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorLink.test.tsx index eeb9fd20a4bcb..acf8d89432b23 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorLink.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverErrorLink.test.tsx @@ -6,7 +6,7 @@ import { shallow, ShallowWrapper } from 'enzyme'; import React from 'react'; -import { APMError } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; +import { APMError } from '../../../../../../typings/es_schemas/ui/apm_error'; import { DiscoverErrorLink } from '../DiscoverErrorLink'; describe('DiscoverErrorLink without kuery', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx index 759caa785c1af..ea79fe12ff0bd 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverLinks.integration.test.tsx @@ -6,9 +6,9 @@ import { Location } from 'history'; import React from 'react'; -import { APMError } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; -import { Span } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; -import { Transaction } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { APMError } from '../../../../../../typings/es_schemas/ui/apm_error'; +import { Span } from '../../../../../../typings/es_schemas/ui/span'; +import { Transaction } from '../../../../../../typings/es_schemas/ui/transaction'; import { getRenderedHref } from '../../../../../utils/testHelpers'; import { DiscoverErrorLink } from '../DiscoverErrorLink'; import { DiscoverSpanLink } from '../DiscoverSpanLink'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionButton.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionButton.test.tsx similarity index 90% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionButton.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionButton.test.tsx index d72925c1956a4..5769ca34a9a87 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionButton.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionButton.test.tsx @@ -6,7 +6,7 @@ import { shallow } from 'enzyme'; import React from 'react'; -import { Transaction } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../typings/es_schemas/ui/transaction'; import { DiscoverTransactionLink, getDiscoverQuery diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionLink.test.tsx similarity index 88% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionLink.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionLink.test.tsx index 15a92474fcc6d..2f65cf7734631 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionLink.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/DiscoverTransactionLink.test.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Transaction } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../typings/es_schemas/ui/transaction'; // @ts-ignore import configureStore from '../../../../../store/config/configureStore'; import { getDiscoverQuery } from '../DiscoverTransactionLink'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorButton.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorButton.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorButton.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorButton.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorLink.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorLink.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorLink.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverErrorLink.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionButton.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionButton.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionButton.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionButton.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionLink.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionLink.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionLink.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/__snapshots__/DiscoverTransactionLink.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/mockTransaction.json b/x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/mockTransaction.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/mockTransaction.json rename to x-pack/plugins/apm/public/components/shared/Links/DiscoverLinks/__test__/mockTransaction.json diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/ElasticDocsLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/InfraLink.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/InfraLink.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/InfraLink.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/InfraLink.tsx index 7efe5cb96cfbd..0ae9f64dc24ef 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/InfraLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/InfraLink.tsx @@ -10,7 +10,7 @@ import url from 'url'; import { fromQuery } from './url_helpers'; import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; import { AppMountContextBasePath } from '../../../context/ApmPluginContext'; -import { InfraAppId } from '../../../../../../../plugins/infra/public'; +import { InfraAppId } from '../../../../../infra/public'; interface InfraQueryParams { time?: number; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/KibanaLink.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/KibanaLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/KibanaLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/KibanaLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx similarity index 88% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx index ecf788ddd2e69..81c5d17d491c0 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLJobLink.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; -import { getMlJobId } from '../../../../../../../../plugins/apm/common/ml_job_constants'; +import { getMlJobId } from '../../../../../common/ml_job_constants'; import { MLLink } from './MLLink'; interface Props { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/MachineLearningLinks/MLLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/SetupInstructionsLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/APMLink.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/APMLink.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/APMLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/APMLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/APMLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorDetailLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/ErrorDetailLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorDetailLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/ErrorDetailLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx index fcc0dc7d26695..ebcf220994cda 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/ErrorOverviewLink.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { APMLink, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { pickKeys } from '../../../../utils/pickKeys'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; import { APMQueryParams } from '../url_helpers'; interface Props extends APMLinkExtendProps { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ExternalLinks.test.ts b/x-pack/plugins/apm/public/components/shared/Links/apm/ExternalLinks.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ExternalLinks.test.ts rename to x-pack/plugins/apm/public/components/shared/Links/apm/ExternalLinks.test.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ExternalLinks.ts b/x-pack/plugins/apm/public/components/shared/Links/apm/ExternalLinks.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ExternalLinks.ts rename to x-pack/plugins/apm/public/components/shared/Links/apm/ExternalLinks.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/HomeLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/HomeLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/HomeLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/HomeLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx index 7d21e1efa44f2..bd3e3b36a8601 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/MetricOverviewLink.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { APMLink, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { pickKeys } from '../../../../utils/pickKeys'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; interface Props extends APMLinkExtendProps { serviceName: string; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceMapLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceMapLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceMapLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/ServiceMapLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx index 527c3da9e7e1c..1473221cca2be 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeMetricOverviewLink.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { APMLink, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { pickKeys } from '../../../../utils/pickKeys'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; interface Props extends APMLinkExtendProps { serviceName: string; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx index db1b6ec117bf4..b479ab77e1127 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceNodeOverviewLink.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { APMLink, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { pickKeys } from '../../../../utils/pickKeys'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; interface Props extends APMLinkExtendProps { serviceName: string; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceOverviewLink.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceOverviewLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/ServiceOverviewLink.tsx index 101f1602506aa..577209a26e46b 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/ServiceOverviewLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/ServiceOverviewLink.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { APMLink, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { pickKeys } from '../../../../utils/pickKeys'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; const ServiceOverviewLink = (props: APMLinkExtendProps) => { const { urlParams } = useUrlParams(); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/SettingsLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/SettingsLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/SettingsLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/SettingsLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TraceOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/TraceOverviewLink.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TraceOverviewLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/TraceOverviewLink.tsx index 371544c142a2d..dc4519365cbc2 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TraceOverviewLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/TraceOverviewLink.tsx @@ -12,7 +12,7 @@ import React from 'react'; import { APMLink, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { pickKeys } from '../../../../utils/pickKeys'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; const TraceOverviewLink = (props: APMLinkExtendProps) => { const { urlParams } = useUrlParams(); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx index 784f9b36ff621..6278336751851 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/TransactionDetailLink.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { APMLink, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { pickKeys } from '../../../../utils/pickKeys'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; interface Props extends APMLinkExtendProps { serviceName: string; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionOverviewLink.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/TransactionOverviewLink.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionOverviewLink.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/TransactionOverviewLink.tsx index af60a0a748445..ccef83ee73fb8 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/TransactionOverviewLink.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/TransactionOverviewLink.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { APMLink, APMLinkExtendProps } from './APMLink'; import { useUrlParams } from '../../../../hooks/useUrlParams'; -import { pickKeys } from '../../../../utils/pickKeys'; +import { pickKeys } from '../../../../../common/utils/pick_keys'; interface Props extends APMLinkExtendProps { serviceName: string; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx b/x-pack/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx similarity index 87% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx rename to x-pack/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx index 0c747e0773a69..6885e44f1ad1f 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx +++ b/x-pack/plugins/apm/public/components/shared/Links/apm/agentConfigurationLinks.tsx @@ -5,7 +5,7 @@ */ import { getAPMHref } from './APMLink'; -import { AgentConfigurationIntake } from '../../../../../../../../plugins/apm/common/agent_configuration/configuration_types'; +import { AgentConfigurationIntake } from '../../../../../common/agent_configuration/configuration_types'; import { history } from '../../../../utils/history'; export function editAgentConfigurationHref( diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/rison_helpers.ts b/x-pack/plugins/apm/public/components/shared/Links/rison_helpers.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/rison_helpers.ts rename to x-pack/plugins/apm/public/components/shared/Links/rison_helpers.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/url_helpers.test.tsx b/x-pack/plugins/apm/public/components/shared/Links/url_helpers.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/url_helpers.test.tsx rename to x-pack/plugins/apm/public/components/shared/Links/url_helpers.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Links/url_helpers.ts b/x-pack/plugins/apm/public/components/shared/Links/url_helpers.ts similarity index 87% rename from x-pack/legacy/plugins/apm/public/components/shared/Links/url_helpers.ts rename to x-pack/plugins/apm/public/components/shared/Links/url_helpers.ts index c7d71d0b6dac5..b296302c47edf 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Links/url_helpers.ts +++ b/x-pack/plugins/apm/public/components/shared/Links/url_helpers.ts @@ -6,8 +6,8 @@ import { parse, stringify } from 'query-string'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LocalUIFilterName } from '../../../../../../../plugins/apm/server/lib/ui_filters/local_ui_filters/config'; -import { url } from '../../../../../../../../src/plugins/kibana_utils/public'; +import { LocalUIFilterName } from '../../../../server/lib/ui_filters/local_ui_filters/config'; +import { url } from '../../../../../../../src/plugins/kibana_utils/public'; export function toQuery(search?: string): APMQueryParamsRaw { return search ? parse(search.slice(1), { sort: false }) : {}; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/LoadingStatePrompt.tsx b/x-pack/plugins/apm/public/components/shared/LoadingStatePrompt.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/LoadingStatePrompt.tsx rename to x-pack/plugins/apm/public/components/shared/LoadingStatePrompt.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterBadgeList.tsx b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterBadgeList.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterBadgeList.tsx rename to x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterBadgeList.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterTitleButton.tsx b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterTitleButton.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterTitleButton.tsx rename to x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/FilterTitleButton.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx rename to x-pack/plugins/apm/public/components/shared/LocalUIFilters/Filter/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/TransactionTypeFilter/index.tsx b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/TransactionTypeFilter/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/TransactionTypeFilter/index.tsx rename to x-pack/plugins/apm/public/components/shared/LocalUIFilters/TransactionTypeFilter/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/index.tsx b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/index.tsx similarity index 91% rename from x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/index.tsx rename to x-pack/plugins/apm/public/components/shared/LocalUIFilters/index.tsx index cede3e394cfab..2c755009ed13a 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/LocalUIFilters/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/LocalUIFilters/index.tsx @@ -14,10 +14,10 @@ import { import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LocalUIFilterName } from '../../../../../../../plugins/apm/server/lib/ui_filters/local_ui_filters/config'; +import { LocalUIFilterName } from '../../../../server/lib/ui_filters/local_ui_filters/config'; import { Filter } from './Filter'; import { useLocalUIFilters } from '../../../hooks/useLocalUIFilters'; -import { PROJECTION } from '../../../../../../../plugins/apm/common/projections/typings'; +import { PROJECTION } from '../../../../common/projections/typings'; interface Props { projection: PROJECTION; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ManagedTable/__test__/ManagedTable.test.js b/x-pack/plugins/apm/public/components/shared/ManagedTable/__test__/ManagedTable.test.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ManagedTable/__test__/ManagedTable.test.js rename to x-pack/plugins/apm/public/components/shared/ManagedTable/__test__/ManagedTable.test.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ManagedTable/__test__/__snapshots__/ManagedTable.test.js.snap b/x-pack/plugins/apm/public/components/shared/ManagedTable/__test__/__snapshots__/ManagedTable.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ManagedTable/__test__/__snapshots__/ManagedTable.test.js.snap rename to x-pack/plugins/apm/public/components/shared/ManagedTable/__test__/__snapshots__/ManagedTable.test.js.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ManagedTable/index.tsx b/x-pack/plugins/apm/public/components/shared/ManagedTable/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ManagedTable/index.tsx rename to x-pack/plugins/apm/public/components/shared/ManagedTable/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx index 258788252379a..1913cf79c7935 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/__test__/ErrorMetadata.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { ErrorMetadata } from '..'; import { render } from '@testing-library/react'; -import { APMError } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; +import { APMError } from '../../../../../../typings/es_schemas/ui/apm_error'; import { expectTextsInDocument, expectTextsNotInDocument diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx similarity index 87% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx index ce991d8b0dc00..7cae42a94322b 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/index.tsx @@ -6,7 +6,7 @@ import React, { useMemo } from 'react'; import { ERROR_METADATA_SECTIONS } from './sections'; -import { APMError } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; +import { APMError } from '../../../../../typings/es_schemas/ui/apm_error'; import { getSectionsWithRows } from '../helper'; import { MetadataTable } from '..'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts rename to x-pack/plugins/apm/public/components/shared/MetadataTable/ErrorMetadata/sections.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/Section.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/Section.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/Section.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/Section.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx index 0059b7b8fb4b3..a46539fe72fcb 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/__test__/SpanMetadata.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render } from '@testing-library/react'; import { SpanMetadata } from '..'; -import { Span } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; +import { Span } from '../../../../../../typings/es_schemas/ui/span'; import { expectTextsInDocument, expectTextsNotInDocument diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx similarity index 88% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx index 2134f12531a7a..abef083e39b9e 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/index.tsx @@ -6,7 +6,7 @@ import React, { useMemo } from 'react'; import { SPAN_METADATA_SECTIONS } from './sections'; -import { Span } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/span'; +import { Span } from '../../../../../typings/es_schemas/ui/span'; import { getSectionsWithRows } from '../helper'; import { MetadataTable } from '..'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts rename to x-pack/plugins/apm/public/components/shared/MetadataTable/SpanMetadata/sections.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx index 3d78f36db9786..8ae46d359efc3 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/__test__/TransactionMetadata.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { TransactionMetadata } from '..'; import { render } from '@testing-library/react'; -import { Transaction } from '../../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../../typings/es_schemas/ui/transaction'; import { expectTextsInDocument, expectTextsNotInDocument diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx similarity index 87% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx index 6f93de4e87e49..86ecbba6a0aaa 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/index.tsx @@ -6,7 +6,7 @@ import React, { useMemo } from 'react'; import { TRANSACTION_METADATA_SECTIONS } from './sections'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { getSectionsWithRows } from '../helper'; import { MetadataTable } from '..'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts rename to x-pack/plugins/apm/public/components/shared/MetadataTable/TransactionMetadata/sections.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/__test__/MetadataTable.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/Section.test.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/__test__/Section.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/Section.test.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/__test__/Section.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/helper.test.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/__test__/helper.test.ts similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/helper.test.ts rename to x-pack/plugins/apm/public/components/shared/MetadataTable/__test__/helper.test.ts index b65b52bf30a5c..e754f7163ca11 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/__test__/helper.test.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/__test__/helper.test.ts @@ -6,7 +6,7 @@ import { getSectionsWithRows, filterSectionsByTerm } from '../helper'; import { LABELS, HTTP, SERVICE } from '../sections'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; describe('MetadataTable Helper', () => { const sections = [ diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/helper.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/helper.ts similarity index 85% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/helper.ts rename to x-pack/plugins/apm/public/components/shared/MetadataTable/helper.ts index ef329abafa61b..a8678ee596e43 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/helper.ts +++ b/x-pack/plugins/apm/public/components/shared/MetadataTable/helper.ts @@ -6,9 +6,9 @@ import { get, pick, isEmpty } from 'lodash'; import { Section } from './sections'; -import { Transaction } from '../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; -import { APMError } from '../../../../../../../plugins/apm/typings/es_schemas/ui/apm_error'; -import { Span } from '../../../../../../../plugins/apm/typings/es_schemas/ui/span'; +import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; +import { APMError } from '../../../../typings/es_schemas/ui/apm_error'; +import { Span } from '../../../../typings/es_schemas/ui/span'; import { flattenObject, KeyValuePair } from '../../../utils/flattenObject'; export type SectionsWithRows = ReturnType; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/index.tsx b/x-pack/plugins/apm/public/components/shared/MetadataTable/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/index.tsx rename to x-pack/plugins/apm/public/components/shared/MetadataTable/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/sections.ts b/x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/MetadataTable/sections.ts rename to x-pack/plugins/apm/public/components/shared/MetadataTable/sections.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/SelectWithPlaceholder/index.tsx b/x-pack/plugins/apm/public/components/shared/SelectWithPlaceholder/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/SelectWithPlaceholder/index.tsx rename to x-pack/plugins/apm/public/components/shared/SelectWithPlaceholder/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ServiceAlertTrigger/PopoverExpression/index.tsx b/x-pack/plugins/apm/public/components/shared/ServiceAlertTrigger/PopoverExpression/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ServiceAlertTrigger/PopoverExpression/index.tsx rename to x-pack/plugins/apm/public/components/shared/ServiceAlertTrigger/PopoverExpression/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx b/x-pack/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx rename to x-pack/plugins/apm/public/components/shared/ServiceAlertTrigger/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.test.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.test.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.tsx index eab414ad47c2c..6dfc8778fe1fc 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/CauseStacktrace.tsx @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { EuiAccordion, EuiTitle } from '@elastic/eui'; import { px, unit } from '../../../style/variables'; import { Stacktrace } from '.'; -import { IStackframe } from '../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +import { IStackframe } from '../../../../typings/es_schemas/raw/fields/stackframe'; // @ts-ignore Styled Components has trouble inferring the types of the default props here. const Accordion = styled(EuiAccordion)` diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Context.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/Context.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Context.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/Context.tsx index d289539ca44b1..d48f4b4f51a6a 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Context.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/Context.tsx @@ -22,7 +22,7 @@ import { registerLanguage } from 'react-syntax-highlighter/dist/light'; // @ts-ignore import { xcode } from 'react-syntax-highlighter/dist/styles'; import styled from 'styled-components'; -import { IStackframeWithLineContext } from '../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +import { IStackframeWithLineContext } from '../../../../typings/es_schemas/raw/fields/stackframe'; import { borderRadius, px, unit, units } from '../../../style/variables'; registerLanguage('javascript', javascript); diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/FrameHeading.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/FrameHeading.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/FrameHeading.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/FrameHeading.tsx index daa722255bdf3..4467fe7ad615e 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/FrameHeading.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/FrameHeading.tsx @@ -7,7 +7,7 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import React, { Fragment } from 'react'; import styled from 'styled-components'; -import { IStackframe } from '../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +import { IStackframe } from '../../../../typings/es_schemas/raw/fields/stackframe'; import { fontFamilyCode, fontSize, px, units } from '../../../style/variables'; const FileDetails = styled.div` diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.test.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.test.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.tsx index be6595153aa77..009e97358428c 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/LibraryStacktrace.tsx @@ -8,7 +8,7 @@ import { EuiAccordion } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import styled from 'styled-components'; -import { IStackframe } from '../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +import { IStackframe } from '../../../../typings/es_schemas/raw/fields/stackframe'; import { Stackframe } from './Stackframe'; import { px, unit } from '../../../style/variables'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Stackframe.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/Stackframe.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Stackframe.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/Stackframe.tsx index 404d474a7960a..4c55add56bc40 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Stackframe.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/Stackframe.tsx @@ -11,7 +11,7 @@ import { EuiAccordion } from '@elastic/eui'; import { IStackframe, IStackframeWithLineContext -} from '../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +} from '../../../../typings/es_schemas/raw/fields/stackframe'; import { borderRadius, fontFamilyCode, diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Variables.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/Variables.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Variables.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/Variables.tsx index 0786116a659c7..ec5fb39f83f8c 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/Variables.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/Variables.tsx @@ -10,7 +10,7 @@ import { EuiAccordion } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { borderRadius, px, unit, units } from '../../../style/variables'; -import { IStackframe } from '../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +import { IStackframe } from '../../../../typings/es_schemas/raw/fields/stackframe'; import { KeyValueTable } from '../KeyValueTable'; import { flattenObject } from '../../../utils/flattenObject'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/Stackframe.test.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/Stackframe.test.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/Stackframe.test.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/Stackframe.test.tsx index 1b2268326e6be..478f9cfe921d9 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/Stackframe.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/Stackframe.test.tsx @@ -6,7 +6,7 @@ import { mount, ReactWrapper, shallow } from 'enzyme'; import React from 'react'; -import { IStackframe } from '../../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +import { IStackframe } from '../../../../../typings/es_schemas/raw/fields/stackframe'; import { Stackframe } from '../Stackframe'; import stacktracesMock from './stacktraces.json'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/Stackframe.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/index.test.ts.snap b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/index.test.ts.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/index.test.ts.snap rename to x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/__snapshots__/index.test.ts.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/index.test.ts b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/index.test.ts similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/index.test.ts rename to x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/index.test.ts index 9b6d74033e1c5..22357b9590887 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/index.test.ts +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/index.test.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { IStackframe } from '../../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +import { IStackframe } from '../../../../../typings/es_schemas/raw/fields/stackframe'; import { getGroupedStackframes } from '../index'; import stacktracesMock from './stacktraces.json'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/stacktraces.json b/x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/stacktraces.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/__test__/stacktraces.json rename to x-pack/plugins/apm/public/components/shared/Stacktrace/__test__/stacktraces.json diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/index.tsx b/x-pack/plugins/apm/public/components/shared/Stacktrace/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/index.tsx rename to x-pack/plugins/apm/public/components/shared/Stacktrace/index.tsx index 141ed544a6166..b6435f7c42183 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Stacktrace/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/Stacktrace/index.tsx @@ -8,7 +8,7 @@ import { EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { isEmpty, last } from 'lodash'; import React, { Fragment } from 'react'; -import { IStackframe } from '../../../../../../../plugins/apm/typings/es_schemas/raw/fields/stackframe'; +import { IStackframe } from '../../../../typings/es_schemas/raw/fields/stackframe'; import { EmptyMessage } from '../../shared/EmptyMessage'; import { LibraryStacktrace } from './LibraryStacktrace'; import { Stackframe } from './Stackframe'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/StickyProperties/StickyProperties.test.js b/x-pack/plugins/apm/public/components/shared/StickyProperties/StickyProperties.test.js similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/shared/StickyProperties/StickyProperties.test.js rename to x-pack/plugins/apm/public/components/shared/StickyProperties/StickyProperties.test.js index 08283dee3825d..b6acb6904f865 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/StickyProperties/StickyProperties.test.js +++ b/x-pack/plugins/apm/public/components/shared/StickyProperties/StickyProperties.test.js @@ -7,10 +7,7 @@ import React from 'react'; import { StickyProperties } from './index'; import { shallow } from 'enzyme'; -import { - USER_ID, - URL_FULL -} from '../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +import { USER_ID, URL_FULL } from '../../../../common/elasticsearch_fieldnames'; import { mockMoment } from '../../../utils/testHelpers'; describe('StickyProperties', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/StickyProperties/__snapshots__/StickyProperties.test.js.snap b/x-pack/plugins/apm/public/components/shared/StickyProperties/__snapshots__/StickyProperties.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/StickyProperties/__snapshots__/StickyProperties.test.js.snap rename to x-pack/plugins/apm/public/components/shared/StickyProperties/__snapshots__/StickyProperties.test.js.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/StickyProperties/index.tsx b/x-pack/plugins/apm/public/components/shared/StickyProperties/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/StickyProperties/index.tsx rename to x-pack/plugins/apm/public/components/shared/StickyProperties/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/DurationSummaryItem.tsx b/x-pack/plugins/apm/public/components/shared/Summary/DurationSummaryItem.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/DurationSummaryItem.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/DurationSummaryItem.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/ErrorCountSummaryItemBadge.tsx b/x-pack/plugins/apm/public/components/shared/Summary/ErrorCountSummaryItemBadge.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/ErrorCountSummaryItemBadge.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/ErrorCountSummaryItemBadge.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/__test__/HttpInfoSummaryItem.test.tsx b/x-pack/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/__test__/HttpInfoSummaryItem.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/__test__/HttpInfoSummaryItem.test.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/__test__/HttpInfoSummaryItem.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/index.tsx b/x-pack/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/index.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/HttpInfoSummaryItem/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpStatusBadge/__test__/HttpStatusBadge.test.tsx b/x-pack/plugins/apm/public/components/shared/Summary/HttpStatusBadge/__test__/HttpStatusBadge.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpStatusBadge/__test__/HttpStatusBadge.test.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/HttpStatusBadge/__test__/HttpStatusBadge.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpStatusBadge/index.tsx b/x-pack/plugins/apm/public/components/shared/Summary/HttpStatusBadge/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpStatusBadge/index.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/HttpStatusBadge/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpStatusBadge/statusCodes.ts b/x-pack/plugins/apm/public/components/shared/Summary/HttpStatusBadge/statusCodes.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/HttpStatusBadge/statusCodes.ts rename to x-pack/plugins/apm/public/components/shared/Summary/HttpStatusBadge/statusCodes.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/TransactionResultSummaryItem.tsx b/x-pack/plugins/apm/public/components/shared/Summary/TransactionResultSummaryItem.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/TransactionResultSummaryItem.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/TransactionResultSummaryItem.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/TransactionSummary.test.tsx b/x-pack/plugins/apm/public/components/shared/Summary/TransactionSummary.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/TransactionSummary.test.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/TransactionSummary.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/TransactionSummary.tsx b/x-pack/plugins/apm/public/components/shared/Summary/TransactionSummary.tsx similarity index 91% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/TransactionSummary.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/TransactionSummary.tsx index f0fe57e46f2fe..f24a806426510 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Summary/TransactionSummary.tsx +++ b/x-pack/plugins/apm/public/components/shared/Summary/TransactionSummary.tsx @@ -4,12 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; -import { Transaction } from '../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { Summary } from './'; import { TimestampTooltip } from '../TimestampTooltip'; import { DurationSummaryItem } from './DurationSummaryItem'; import { ErrorCountSummaryItemBadge } from './ErrorCountSummaryItemBadge'; -import { isRumAgentName } from '../../../../../../../plugins/apm/common/agent_name'; +import { isRumAgentName } from '../../../../common/agent_name'; import { HttpInfoSummaryItem } from './HttpInfoSummaryItem'; import { TransactionResultSummaryItem } from './TransactionResultSummaryItem'; import { UserAgentSummaryItem } from './UserAgentSummaryItem'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.test.tsx b/x-pack/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.test.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.tsx b/x-pack/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.tsx similarity index 90% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.tsx index 10a6bcc1ef7bd..8173170b72f23 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.tsx +++ b/x-pack/plugins/apm/public/components/shared/Summary/UserAgentSummaryItem.tsx @@ -9,7 +9,7 @@ import styled from 'styled-components'; import theme from '@elastic/eui/dist/eui_theme_light.json'; import { EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { UserAgent } from '../../../../../../../plugins/apm/typings/es_schemas/raw/fields/user_agent'; +import { UserAgent } from '../../../../typings/es_schemas/raw/fields/user_agent'; type UserAgentSummaryItemProps = UserAgent; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/__fixtures__/transactions.ts b/x-pack/plugins/apm/public/components/shared/Summary/__fixtures__/transactions.ts similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/__fixtures__/transactions.ts rename to x-pack/plugins/apm/public/components/shared/Summary/__fixtures__/transactions.ts index 05fb73a9e2749..e1615934cd92e 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Summary/__fixtures__/transactions.ts +++ b/x-pack/plugins/apm/public/components/shared/Summary/__fixtures__/transactions.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; export const httpOk: Transaction = { '@timestamp': '0', diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/__test__/ErrorCountSummaryItemBadge.test.tsx b/x-pack/plugins/apm/public/components/shared/Summary/__test__/ErrorCountSummaryItemBadge.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/__test__/ErrorCountSummaryItemBadge.test.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/__test__/ErrorCountSummaryItemBadge.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/Summary/index.tsx b/x-pack/plugins/apm/public/components/shared/Summary/index.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/shared/Summary/index.tsx rename to x-pack/plugins/apm/public/components/shared/Summary/index.tsx index ef99f3a4933a7..ce6935d1858aa 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/Summary/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/Summary/index.tsx @@ -8,7 +8,7 @@ import { EuiFlexGrid, EuiFlexItem } from '@elastic/eui'; import styled from 'styled-components'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; import { px, units } from '../../../../public/style/variables'; -import { Maybe } from '../../../../../../../plugins/apm/typings/common'; +import { Maybe } from '../../../../typings/common'; interface Props { items: Array>; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TimestampTooltip/__test__/index.test.tsx b/x-pack/plugins/apm/public/components/shared/TimestampTooltip/__test__/index.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/TimestampTooltip/__test__/index.test.tsx rename to x-pack/plugins/apm/public/components/shared/TimestampTooltip/__test__/index.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TimestampTooltip/index.tsx b/x-pack/plugins/apm/public/components/shared/TimestampTooltip/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/TimestampTooltip/index.tsx rename to x-pack/plugins/apm/public/components/shared/TimestampTooltip/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx similarity index 91% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx index 8df6d952cfacd..49f8fddb303bd 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.test.tsx @@ -5,10 +5,10 @@ */ import React from 'react'; import { render, act, fireEvent } from '@testing-library/react'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { CustomLinkPopover } from './CustomLinkPopover'; import { expectTextsInDocument } from '../../../../utils/testHelpers'; -import { CustomLink } from '../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +import { CustomLink } from '../../../../../common/custom_link/custom_link_types'; describe('CustomLinkPopover', () => { const customLinks = [ diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx similarity index 90% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx index 3aed1b7ac2953..a63c226a5c46e 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkPopover.tsx @@ -12,8 +12,8 @@ import { } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; -import { CustomLink } from '../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { CustomLink } from '../../../../../common/custom_link/custom_link_types'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { CustomLinkSection } from './CustomLinkSection'; import { ManageCustomLink } from './ManageCustomLink'; import { px } from '../../../../style/variables'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx similarity index 85% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx index d429fa56894eb..6cf8b9ee5e98a 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.test.tsx @@ -10,8 +10,8 @@ import { expectTextsInDocument, expectTextsNotInDocument } from '../../../../utils/testHelpers'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; -import { CustomLink } from '../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; +import { CustomLink } from '../../../../../common/custom_link/custom_link_types'; describe('CustomLinkSection', () => { const customLinks = [ diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx similarity index 86% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx index bd00bcf600ffe..e22f4b4a37745 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/CustomLinkSection.tsx @@ -7,8 +7,8 @@ import { EuiLink, EuiText } from '@elastic/eui'; import Mustache from 'mustache'; import React from 'react'; import styled from 'styled-components'; -import { CustomLink } from '../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { CustomLink } from '../../../../../common/custom_link/custom_link_types'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { px, truncate, units } from '../../../../style/variables'; const LinkContainer = styled.li` diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.test.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/ManageCustomLink.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx index 9d1eeb9a3136d..c7a2d77d85fa6 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.test.tsx @@ -7,13 +7,13 @@ import React from 'react'; import { render, act, fireEvent } from '@testing-library/react'; import { CustomLink } from '.'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { FETCH_STATUS } from '../../../../hooks/useFetcher'; import { expectTextsInDocument, expectTextsNotInDocument } from '../../../../utils/testHelpers'; -import { CustomLink as CustomLinkType } from '../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; +import { CustomLink as CustomLinkType } from '../../../../../common/custom_link/custom_link_types'; describe('Custom links', () => { it('shows empty message when no custom link is available', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx index 38b672a181fce..710b2175e3377 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/CustomLink/index.tsx @@ -15,12 +15,12 @@ import { import { i18n } from '@kbn/i18n'; import styled from 'styled-components'; import { isEmpty } from 'lodash'; -import { CustomLink as CustomLinkType } from '../../../../../../../../plugins/apm/common/custom_link/custom_link_types'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { CustomLink as CustomLinkType } from '../../../../../common/custom_link/custom_link_types'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { ActionMenuDivider, SectionSubtitle -} from '../../../../../../../../plugins/observability/public'; +} from '../../../../../../observability/public'; import { CustomLinkSection } from './CustomLinkSection'; import { ManageCustomLink } from './ManageCustomLink'; import { FETCH_STATUS } from '../../../../hooks/useFetcher'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx index 7ebfe26b83630..c9376cdc01b5b 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/TransactionActionMenu.tsx @@ -7,8 +7,8 @@ import { EuiButtonEmpty } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React, { FunctionComponent, useMemo, useState } from 'react'; -import { Filter } from '../../../../../../../plugins/apm/common/custom_link/custom_link_types'; -import { Transaction } from '../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Filter } from '../../../../common/custom_link/custom_link_types'; +import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { ActionMenu, ActionMenuDivider, @@ -17,7 +17,7 @@ import { SectionLinks, SectionSubtitle, SectionTitle -} from '../../../../../../../plugins/observability/public'; +} from '../../../../../observability/public'; import { useApmPluginContext } from '../../../hooks/useApmPluginContext'; import { useFetcher } from '../../../hooks/useFetcher'; import { useLocation } from '../../../hooks/useLocation'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx index 8dc2076eab5b5..cda602204469c 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/TransactionActionMenu.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { render, fireEvent, act, wait } from '@testing-library/react'; import { TransactionActionMenu } from '../TransactionActionMenu'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import * as Transactions from './mockData'; import { expectTextsNotInDocument, @@ -15,7 +15,7 @@ import { } from '../../../../utils/testHelpers'; import * as hooks from '../../../../hooks/useFetcher'; import { LicenseContext } from '../../../../context/LicenseContext'; -import { License } from '../../../../../../../../plugins/licensing/common/license'; +import { License } from '../../../../../../licensing/common/license'; import { MockApmPluginContextWrapper } from '../../../../context/ApmPluginContext/MockApmPluginContext'; import * as apmApi from '../../../../services/rest/createCallApmApi'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/__snapshots__/TransactionActionMenu.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/__snapshots__/TransactionActionMenu.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/__snapshots__/TransactionActionMenu.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/__snapshots__/TransactionActionMenu.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/mockData.ts b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/mockData.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/mockData.ts rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/mockData.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/sections.test.ts b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/sections.test.ts similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/sections.test.ts rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/sections.test.ts index 3032dd1704f4e..b2f6f39e0b596 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/__test__/sections.test.ts +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/__test__/sections.test.ts @@ -5,7 +5,7 @@ */ import { Location } from 'history'; import { getSections } from '../sections'; -import { Transaction } from '../../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../../typings/es_schemas/ui/transaction'; import { AppMountContextBasePath } from '../../../../context/ApmPluginContext'; describe('Transaction action menu', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/sections.ts b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/sections.ts similarity index 98% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/sections.ts rename to x-pack/plugins/apm/public/components/shared/TransactionActionMenu/sections.ts index ffdf0b485da64..2c2f4bfcadd7d 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionActionMenu/sections.ts +++ b/x-pack/plugins/apm/public/components/shared/TransactionActionMenu/sections.ts @@ -8,7 +8,7 @@ import { Location } from 'history'; import { pick, isEmpty } from 'lodash'; import moment from 'moment'; import url from 'url'; -import { Transaction } from '../../../../../../../plugins/apm/typings/es_schemas/ui/transaction'; +import { Transaction } from '../../../../typings/es_schemas/ui/transaction'; import { IUrlParams } from '../../../context/UrlParamsContext/types'; import { getDiscoverHref } from '../Links/DiscoverLinks/DiscoverLink'; import { getDiscoverQuery } from '../Links/DiscoverLinks/DiscoverTransactionLink'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx similarity index 81% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx index 50ea169c017f9..966cc64fde505 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownGraph/index.tsx @@ -7,17 +7,14 @@ import React, { useMemo } from 'react'; import numeral from '@elastic/numeral'; import { throttle } from 'lodash'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../../../plugins/apm/common/i18n'; -import { - Coordinate, - TimeSeries -} from '../../../../../../../../plugins/apm/typings/timeseries'; -import { Maybe } from '../../../../../../../../plugins/apm/typings/common'; +import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; +import { Coordinate, TimeSeries } from '../../../../../typings/timeseries'; +import { Maybe } from '../../../../../typings/common'; import { TransactionLineChart } from '../../charts/TransactionCharts/TransactionLineChart'; import { asPercent } from '../../../../utils/formatters'; import { unit } from '../../../../style/variables'; import { isValidCoordinateValue } from '../../../../utils/isValidCoordinateValue'; -import { useUiTracker } from '../../../../../../../../plugins/observability/public'; +import { useUiTracker } from '../../../../../../observability/public'; interface Props { timeseries: TimeSeries[]; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownHeader.tsx b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownHeader.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownHeader.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownHeader.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx similarity index 95% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx index 91f5f4e0a7176..c4a8e07fb3004 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/TransactionBreakdownKpiList.tsx @@ -13,10 +13,7 @@ import { EuiIcon } from '@elastic/eui'; import styled from 'styled-components'; -import { - FORMATTERS, - InfraFormatterType -} from '../../../../../../../plugins/infra/public'; +import { FORMATTERS, InfraFormatterType } from '../../../../../infra/public'; interface TransactionBreakdownKpi { name: string; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx index 85f5f83fb920e..be5860190c11e 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionBreakdown/index.tsx @@ -11,7 +11,7 @@ import { TransactionBreakdownHeader } from './TransactionBreakdownHeader'; import { TransactionBreakdownKpiList } from './TransactionBreakdownKpiList'; import { TransactionBreakdownGraph } from './TransactionBreakdownGraph'; import { FETCH_STATUS } from '../../../hooks/useFetcher'; -import { useUiTracker } from '../../../../../../../plugins/observability/public'; +import { useUiTracker } from '../../../../../observability/public'; const emptyMessage = i18n.translate('xpack.apm.transactionBreakdown.noData', { defaultMessage: 'No data within this time range.' diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.stories.tsx b/x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.stories.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.stories.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.stories.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx b/x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx rename to x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx index 077e6535a8b21..1e9fbd2c1c135 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/TransactionDurationAlertTrigger/index.tsx @@ -7,11 +7,11 @@ import React from 'react'; import { map } from 'lodash'; import { EuiFieldNumber, EuiSelect } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { ForLastExpression } from '../../../../../../../plugins/triggers_actions_ui/public'; +import { ForLastExpression } from '../../../../../triggers_actions_ui/public'; import { TRANSACTION_ALERT_AGGREGATION_TYPES, ALERT_TYPES_CONFIG -} from '../../../../../../../plugins/apm/common/alert_types'; +} from '../../../../common/alert_types'; import { ServiceAlertTrigger } from '../ServiceAlertTrigger'; import { useUrlParams } from '../../../hooks/useUrlParams'; import { useServiceTransactionTypes } from '../../../hooks/useServiceTransactionTypes'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx index ec6168df5b134..6eff4759b2e7c 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/AnnotationsPlot.tsx @@ -14,8 +14,8 @@ import { EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { Maybe } from '../../../../../../../../plugins/apm/typings/common'; -import { Annotation } from '../../../../../../../../plugins/apm/common/annotations'; +import { Maybe } from '../../../../../typings/common'; +import { Annotation } from '../../../../../common/annotations'; import { PlotValues, SharedPlot } from './plotUtils'; import { asAbsoluteDateTime } from '../../../../utils/formatters'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/InteractivePlot.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/InteractivePlot.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/InteractivePlot.js rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/InteractivePlot.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/Legends.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/SelectionMarker.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/SelectionMarker.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/SelectionMarker.js rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/SelectionMarker.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/StaticPlot.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/StatusText.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/StatusText.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/StatusText.js rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/StatusText.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/VoronoiPlot.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/getEmptySeries.ts b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/getEmptySeries.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/getEmptySeries.ts rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/getEmptySeries.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.test.ts b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.test.ts rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.test.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.ts b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.ts rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/getTimezoneOffsetInMs.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/index.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/index.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/index.js rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/index.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts similarity index 94% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts index bfc5c7c243f31..b130deed7f098 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts +++ b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.test.ts @@ -6,10 +6,7 @@ // @ts-ignore import * as plotUtils from './plotUtils'; -import { - TimeSeries, - Coordinate -} from '../../../../../../../../plugins/apm/typings/timeseries'; +import { TimeSeries, Coordinate } from '../../../../../typings/timeseries'; describe('plotUtils', () => { describe('getPlotValues', () => { diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx index c489c270d19ac..64350a5741647 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/plotUtils.tsx @@ -11,10 +11,7 @@ import d3 from 'd3'; import PropTypes from 'prop-types'; import React from 'react'; -import { - TimeSeries, - Coordinate -} from '../../../../../../../../plugins/apm/typings/timeseries'; +import { TimeSeries, Coordinate } from '../../../../../typings/timeseries'; import { unit } from '../../../../style/variables'; import { getDomainTZ, getTimeTicksTZ } from '../helper/timezone'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/CustomPlot.test.js b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/CustomPlot.test.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/CustomPlot.test.js rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/CustomPlot.test.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/__snapshots__/CustomPlot.test.js.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/responseWithData.json b/x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/responseWithData.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/CustomPlot/test/responseWithData.json rename to x-pack/plugins/apm/public/components/shared/charts/CustomPlot/test/responseWithData.json diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/SingleRect.js b/x-pack/plugins/apm/public/components/shared/charts/Histogram/SingleRect.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/SingleRect.js rename to x-pack/plugins/apm/public/components/shared/charts/Histogram/SingleRect.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/__test__/Histogram.test.js b/x-pack/plugins/apm/public/components/shared/charts/Histogram/__test__/Histogram.test.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/__test__/Histogram.test.js rename to x-pack/plugins/apm/public/components/shared/charts/Histogram/__test__/Histogram.test.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/__test__/__snapshots__/Histogram.test.js.snap b/x-pack/plugins/apm/public/components/shared/charts/Histogram/__test__/__snapshots__/Histogram.test.js.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/__test__/__snapshots__/Histogram.test.js.snap rename to x-pack/plugins/apm/public/components/shared/charts/Histogram/__test__/__snapshots__/Histogram.test.js.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/__test__/response.json b/x-pack/plugins/apm/public/components/shared/charts/Histogram/__test__/response.json similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/__test__/response.json rename to x-pack/plugins/apm/public/components/shared/charts/Histogram/__test__/response.json diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/index.js b/x-pack/plugins/apm/public/components/shared/charts/Histogram/index.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Histogram/index.js rename to x-pack/plugins/apm/public/components/shared/charts/Histogram/index.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Legend/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/Legend/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Legend/index.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Legend/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/MetricsChart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/MetricsChart/index.tsx similarity index 90% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/MetricsChart/index.tsx rename to x-pack/plugins/apm/public/components/shared/charts/MetricsChart/index.tsx index 2ceac87d9aab3..862f2a8987067 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/MetricsChart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/MetricsChart/index.tsx @@ -6,7 +6,7 @@ import { EuiTitle } from '@elastic/eui'; import React from 'react'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { GenericMetricsChart } from '../../../../../../../../plugins/apm/server/lib/metrics/transform_metrics_chart'; +import { GenericMetricsChart } from '../../../../../server/lib/metrics/transform_metrics_chart'; // @ts-ignore import CustomPlot from '../CustomPlot'; import { @@ -17,10 +17,10 @@ import { getFixedByteFormatter, asDuration } from '../../../../utils/formatters'; -import { Coordinate } from '../../../../../../../../plugins/apm/typings/timeseries'; +import { Coordinate } from '../../../../../typings/timeseries'; import { isValidCoordinateValue } from '../../../../utils/isValidCoordinateValue'; import { useChartsSync } from '../../../../hooks/useChartsSync'; -import { Maybe } from '../../../../../../../../plugins/apm/typings/common'; +import { Maybe } from '../../../../../typings/common'; interface Props { start: Maybe; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/LastTickValue.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/LastTickValue.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/LastTickValue.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/LastTickValue.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/AgentMarker.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/AgentMarker.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/AgentMarker.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/AgentMarker.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.tsx similarity index 97% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.tsx index 48265ce7c80a8..51368a4fb946d 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.tsx @@ -11,7 +11,7 @@ import styled from 'styled-components'; import { TRACE_ID, TRANSACTION_ID -} from '../../../../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +} from '../../../../../../common/elasticsearch_fieldnames'; import { useUrlParams } from '../../../../../hooks/useUrlParams'; import { px, unit, units } from '../../../../../style/variables'; import { asDuration } from '../../../../../utils/formatters'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/AgentMarker.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/AgentMarker.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/AgentMarker.test.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/AgentMarker.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/ErrorMarker.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/ErrorMarker.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/ErrorMarker.test.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/ErrorMarker.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/Marker.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/Marker.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/Marker.test.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/Marker.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/AgentMarker.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/AgentMarker.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/AgentMarker.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/AgentMarker.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/ErrorMarker.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/ErrorMarker.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/ErrorMarker.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/ErrorMarker.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/Marker.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/Marker.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/Marker.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/__test__/__snapshots__/Marker.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Marker/index.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Timeline.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Timeline.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/Timeline.test.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/Timeline.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/TimelineAxis.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/TimelineAxis.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/TimelineAxis.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/TimelineAxis.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/VerticalLines.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/VerticalLines.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/VerticalLines.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/VerticalLines.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/__snapshots__/Timeline.test.tsx.snap b/x-pack/plugins/apm/public/components/shared/charts/Timeline/__snapshots__/Timeline.test.tsx.snap similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/__snapshots__/Timeline.test.tsx.snap rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/__snapshots__/Timeline.test.tsx.snap diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/index.tsx rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/plotUtils.ts b/x-pack/plugins/apm/public/components/shared/charts/Timeline/plotUtils.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Timeline/plotUtils.ts rename to x-pack/plugins/apm/public/components/shared/charts/Timeline/plotUtils.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/Tooltip/index.js b/x-pack/plugins/apm/public/components/shared/charts/Tooltip/index.js similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/Tooltip/index.js rename to x-pack/plugins/apm/public/components/shared/charts/Tooltip/index.js diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx rename to x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.tsx rename to x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/BrowserLineChart.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/ChoroplethToolTip.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/ChoroplethToolTip.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/ChoroplethToolTip.tsx rename to x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/ChoroplethToolTip.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/index.tsx rename to x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/ChoroplethMap/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/DurationByCountryMap/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/DurationByCountryMap/index.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/DurationByCountryMap/index.tsx rename to x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/DurationByCountryMap/index.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/TransactionLineChart/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/TransactionLineChart/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/TransactionLineChart/index.tsx rename to x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/TransactionLineChart/index.tsx index c9c31b05e264c..27c829f63cf0a 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/TransactionLineChart/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/TransactionLineChart/index.tsx @@ -8,7 +8,7 @@ import React, { useCallback } from 'react'; import { Coordinate, RectCoordinate -} from '../../../../../../../../../plugins/apm/typings/timeseries'; +} from '../../../../../../typings/timeseries'; import { useChartsSync } from '../../../../../hooks/useChartsSync'; // @ts-ignore import CustomPlot from '../../CustomPlot'; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx rename to x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx index 368a39e4ad228..b0555da705a30 100644 --- a/x-pack/legacy/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/TransactionCharts/index.tsx @@ -19,11 +19,8 @@ import { Location } from 'history'; import React, { Component } from 'react'; import { isEmpty, flatten } from 'lodash'; import styled from 'styled-components'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../../../plugins/apm/common/i18n'; -import { - Coordinate, - TimeSeries -} from '../../../../../../../../plugins/apm/typings/timeseries'; +import { NOT_AVAILABLE_LABEL } from '../../../../../common/i18n'; +import { Coordinate, TimeSeries } from '../../../../../typings/timeseries'; import { ITransactionChartData } from '../../../../selectors/chartSelectors'; import { IUrlParams } from '../../../../context/UrlParamsContext/types'; import { @@ -42,7 +39,7 @@ import { TRANSACTION_PAGE_LOAD, TRANSACTION_ROUTE_CHANGE, TRANSACTION_REQUEST -} from '../../../../../../../../plugins/apm/common/transaction_types'; +} from '../../../../../common/transaction_types'; interface TransactionChartProps { hasMLJob: boolean; diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/helper/__test__/timezone.test.ts b/x-pack/plugins/apm/public/components/shared/charts/helper/__test__/timezone.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/helper/__test__/timezone.test.ts rename to x-pack/plugins/apm/public/components/shared/charts/helper/__test__/timezone.test.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/charts/helper/timezone.ts b/x-pack/plugins/apm/public/components/shared/charts/helper/timezone.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/charts/helper/timezone.ts rename to x-pack/plugins/apm/public/components/shared/charts/helper/timezone.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.test.tsx b/x-pack/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.test.tsx rename to x-pack/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts b/x-pack/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts rename to x-pack/plugins/apm/public/components/shared/useDelayedVisibility/Delayed/index.ts diff --git a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx b/x-pack/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx rename to x-pack/plugins/apm/public/components/shared/useDelayedVisibility/index.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.ts b/x-pack/plugins/apm/public/components/shared/useDelayedVisibility/index.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/components/shared/useDelayedVisibility/index.ts rename to x-pack/plugins/apm/public/components/shared/useDelayedVisibility/index.ts diff --git a/x-pack/legacy/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx b/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx similarity index 93% rename from x-pack/legacy/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx rename to x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx index cc2e382611628..865e3dbe6dafc 100644 --- a/x-pack/legacy/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx +++ b/x-pack/plugins/apm/public/context/ApmPluginContext/MockApmPluginContext.tsx @@ -6,7 +6,7 @@ import React from 'react'; import { ApmPluginContext, ApmPluginContextValue } from '.'; import { createCallApmApi } from '../../services/rest/createCallApmApi'; -import { ConfigSchema } from '../../new-platform/plugin'; +import { ConfigSchema } from '../..'; const mockCore = { chrome: { @@ -30,7 +30,6 @@ const mockCore = { }; const mockConfig: ConfigSchema = { - indexPatternTitle: 'apm-*', serviceMapEnabled: true, ui: { enabled: false diff --git a/x-pack/legacy/plugins/apm/public/context/ApmPluginContext/index.tsx b/x-pack/plugins/apm/public/context/ApmPluginContext/index.tsx similarity index 87% rename from x-pack/legacy/plugins/apm/public/context/ApmPluginContext/index.tsx rename to x-pack/plugins/apm/public/context/ApmPluginContext/index.tsx index acc3886586889..37304d292540d 100644 --- a/x-pack/legacy/plugins/apm/public/context/ApmPluginContext/index.tsx +++ b/x-pack/plugins/apm/public/context/ApmPluginContext/index.tsx @@ -6,7 +6,8 @@ import { createContext } from 'react'; import { AppMountContext } from 'kibana/public'; -import { ApmPluginSetupDeps, ConfigSchema } from '../../new-platform/plugin'; +import { ConfigSchema } from '../..'; +import { ApmPluginSetupDeps } from '../../plugin'; export type AppMountContextBasePath = AppMountContext['core']['http']['basePath']; diff --git a/x-pack/legacy/plugins/apm/public/context/ChartsSyncContext.tsx b/x-pack/plugins/apm/public/context/ChartsSyncContext.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/context/ChartsSyncContext.tsx rename to x-pack/plugins/apm/public/context/ChartsSyncContext.tsx diff --git a/x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx b/x-pack/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx rename to x-pack/plugins/apm/public/context/LicenseContext/InvalidLicenseNotification.tsx diff --git a/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx b/x-pack/plugins/apm/public/context/LicenseContext/index.tsx similarity index 94% rename from x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx rename to x-pack/plugins/apm/public/context/LicenseContext/index.tsx index 62cdbd3bbc995..e6615a2fc98bf 100644 --- a/x-pack/legacy/plugins/apm/public/context/LicenseContext/index.tsx +++ b/x-pack/plugins/apm/public/context/LicenseContext/index.tsx @@ -6,7 +6,7 @@ import React from 'react'; import useObservable from 'react-use/lib/useObservable'; -import { ILicense } from '../../../../../../plugins/licensing/public'; +import { ILicense } from '../../../../licensing/public'; import { useApmPluginContext } from '../../hooks/useApmPluginContext'; import { InvalidLicenseNotification } from './InvalidLicenseNotification'; diff --git a/x-pack/legacy/plugins/apm/public/context/LoadingIndicatorContext.tsx b/x-pack/plugins/apm/public/context/LoadingIndicatorContext.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/context/LoadingIndicatorContext.tsx rename to x-pack/plugins/apm/public/context/LoadingIndicatorContext.tsx diff --git a/x-pack/legacy/plugins/apm/public/context/LocationContext.tsx b/x-pack/plugins/apm/public/context/LocationContext.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/context/LocationContext.tsx rename to x-pack/plugins/apm/public/context/LocationContext.tsx diff --git a/x-pack/legacy/plugins/apm/public/context/MatchedRouteContext.tsx b/x-pack/plugins/apm/public/context/MatchedRouteContext.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/context/MatchedRouteContext.tsx rename to x-pack/plugins/apm/public/context/MatchedRouteContext.tsx diff --git a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/MockUrlParamsContextProvider.tsx b/x-pack/plugins/apm/public/context/UrlParamsContext/MockUrlParamsContextProvider.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/context/UrlParamsContext/MockUrlParamsContextProvider.tsx rename to x-pack/plugins/apm/public/context/UrlParamsContext/MockUrlParamsContextProvider.tsx diff --git a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx b/x-pack/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx rename to x-pack/plugins/apm/public/context/UrlParamsContext/__tests__/UrlParamsContext.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/constants.ts b/x-pack/plugins/apm/public/context/UrlParamsContext/constants.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/context/UrlParamsContext/constants.ts rename to x-pack/plugins/apm/public/context/UrlParamsContext/constants.ts diff --git a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/helpers.ts b/x-pack/plugins/apm/public/context/UrlParamsContext/helpers.ts similarity index 97% rename from x-pack/legacy/plugins/apm/public/context/UrlParamsContext/helpers.ts rename to x-pack/plugins/apm/public/context/UrlParamsContext/helpers.ts index b80db0e9ae073..f1e45fe45255d 100644 --- a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/helpers.ts +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/helpers.ts @@ -7,7 +7,7 @@ import { compact, pick } from 'lodash'; import datemath from '@elastic/datemath'; import { IUrlParams } from './types'; -import { ProcessorEvent } from '../../../../../../plugins/apm/common/processor_event'; +import { ProcessorEvent } from '../../../common/processor_event'; interface PathParams { processorEvent?: ProcessorEvent; diff --git a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/index.tsx b/x-pack/plugins/apm/public/context/UrlParamsContext/index.tsx similarity index 92% rename from x-pack/legacy/plugins/apm/public/context/UrlParamsContext/index.tsx rename to x-pack/plugins/apm/public/context/UrlParamsContext/index.tsx index 588936039c2bc..7a929380bce37 100644 --- a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/index.tsx +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/index.tsx @@ -16,13 +16,13 @@ import { uniqueId, mapValues } from 'lodash'; import { IUrlParams } from './types'; import { getParsedDate } from './helpers'; import { resolveUrlParams } from './resolveUrlParams'; -import { UIFilters } from '../../../../../../plugins/apm/typings/ui_filters'; +import { UIFilters } from '../../../typings/ui_filters'; import { localUIFilterNames, LocalUIFilterName // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../../plugins/apm/server/lib/ui_filters/local_ui_filters/config'; -import { pickKeys } from '../../utils/pickKeys'; +} from '../../../server/lib/ui_filters/local_ui_filters/config'; +import { pickKeys } from '../../../common/utils/pick_keys'; import { useDeepObjectIdentity } from '../../hooks/useDeepObjectIdentity'; interface TimeRange { diff --git a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts b/x-pack/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts similarity index 93% rename from x-pack/legacy/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts rename to x-pack/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts index f022d2084583b..34af18431a2df 100644 --- a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/resolveUrlParams.ts @@ -18,8 +18,8 @@ import { import { toQuery } from '../../components/shared/Links/url_helpers'; import { TIMEPICKER_DEFAULTS } from './constants'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { localUIFilterNames } from '../../../../../../plugins/apm/server/lib/ui_filters/local_ui_filters/config'; -import { pickKeys } from '../../utils/pickKeys'; +import { localUIFilterNames } from '../../../server/lib/ui_filters/local_ui_filters/config'; +import { pickKeys } from '../../../common/utils/pick_keys'; type TimeUrlParams = Pick< IUrlParams, diff --git a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/types.ts b/x-pack/plugins/apm/public/context/UrlParamsContext/types.ts similarity index 83% rename from x-pack/legacy/plugins/apm/public/context/UrlParamsContext/types.ts rename to x-pack/plugins/apm/public/context/UrlParamsContext/types.ts index acde09308ab46..78fe662b88d75 100644 --- a/x-pack/legacy/plugins/apm/public/context/UrlParamsContext/types.ts +++ b/x-pack/plugins/apm/public/context/UrlParamsContext/types.ts @@ -5,8 +5,8 @@ */ // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LocalUIFilterName } from '../../../../../../plugins/apm/server/lib/ui_filters/local_ui_filters/config'; -import { ProcessorEvent } from '../../../../../../plugins/apm/common/processor_event'; +import { LocalUIFilterName } from '../../../server/lib/ui_filters/local_ui_filters/config'; +import { ProcessorEvent } from '../../../common/processor_event'; export type IUrlParams = { detailTab?: string; diff --git a/x-pack/legacy/plugins/apm/public/new-platform/featureCatalogueEntry.ts b/x-pack/plugins/apm/public/featureCatalogueEntry.ts similarity index 88% rename from x-pack/legacy/plugins/apm/public/new-platform/featureCatalogueEntry.ts rename to x-pack/plugins/apm/public/featureCatalogueEntry.ts index 7a150de6d5d02..f76c6f5169dc5 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/featureCatalogueEntry.ts +++ b/x-pack/plugins/apm/public/featureCatalogueEntry.ts @@ -5,7 +5,7 @@ */ import { i18n } from '@kbn/i18n'; -import { FeatureCatalogueCategory } from '../../../../../../src/plugins/home/public'; +import { FeatureCatalogueCategory } from '../../../../src/plugins/home/public'; export const featureCatalogueEntry = { id: 'apm', diff --git a/x-pack/legacy/plugins/apm/public/hooks/useAgentName.ts b/x-pack/plugins/apm/public/hooks/useAgentName.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useAgentName.ts rename to x-pack/plugins/apm/public/hooks/useAgentName.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useApmPluginContext.ts b/x-pack/plugins/apm/public/hooks/useApmPluginContext.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useApmPluginContext.ts rename to x-pack/plugins/apm/public/hooks/useApmPluginContext.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useAvgDurationByBrowser.test.ts b/x-pack/plugins/apm/public/hooks/useAvgDurationByBrowser.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useAvgDurationByBrowser.test.ts rename to x-pack/plugins/apm/public/hooks/useAvgDurationByBrowser.test.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useAvgDurationByBrowser.ts b/x-pack/plugins/apm/public/hooks/useAvgDurationByBrowser.ts similarity index 83% rename from x-pack/legacy/plugins/apm/public/hooks/useAvgDurationByBrowser.ts rename to x-pack/plugins/apm/public/hooks/useAvgDurationByBrowser.ts index 256c2fa68bfbc..5d0c9d1435798 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useAvgDurationByBrowser.ts +++ b/x-pack/plugins/apm/public/hooks/useAvgDurationByBrowser.ts @@ -8,9 +8,9 @@ import theme from '@elastic/eui/dist/eui_theme_light.json'; import { useFetcher } from './useFetcher'; import { useUrlParams } from './useUrlParams'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { AvgDurationByBrowserAPIResponse } from '../../../../../plugins/apm/server/lib/transactions/avg_duration_by_browser'; -import { TimeSeries } from '../../../../../plugins/apm/typings/timeseries'; -import { getVizColorForIndex } from '../../../../../plugins/apm/common/viz_colors'; +import { AvgDurationByBrowserAPIResponse } from '../../server/lib/transactions/avg_duration_by_browser'; +import { TimeSeries } from '../../typings/timeseries'; +import { getVizColorForIndex } from '../../common/viz_colors'; function toTimeSeries(data?: AvgDurationByBrowserAPIResponse): TimeSeries[] { if (!data) { diff --git a/x-pack/legacy/plugins/apm/public/hooks/useAvgDurationByCountry.ts b/x-pack/plugins/apm/public/hooks/useAvgDurationByCountry.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useAvgDurationByCountry.ts rename to x-pack/plugins/apm/public/hooks/useAvgDurationByCountry.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useCallApi.ts b/x-pack/plugins/apm/public/hooks/useCallApi.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useCallApi.ts rename to x-pack/plugins/apm/public/hooks/useCallApi.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useChartsSync.tsx b/x-pack/plugins/apm/public/hooks/useChartsSync.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useChartsSync.tsx rename to x-pack/plugins/apm/public/hooks/useChartsSync.tsx diff --git a/x-pack/legacy/plugins/apm/public/hooks/useComponentId.tsx b/x-pack/plugins/apm/public/hooks/useComponentId.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useComponentId.tsx rename to x-pack/plugins/apm/public/hooks/useComponentId.tsx diff --git a/x-pack/legacy/plugins/apm/public/hooks/useDeepObjectIdentity.ts b/x-pack/plugins/apm/public/hooks/useDeepObjectIdentity.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useDeepObjectIdentity.ts rename to x-pack/plugins/apm/public/hooks/useDeepObjectIdentity.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useDynamicIndexPattern.ts b/x-pack/plugins/apm/public/hooks/useDynamicIndexPattern.ts similarity index 89% rename from x-pack/legacy/plugins/apm/public/hooks/useDynamicIndexPattern.ts rename to x-pack/plugins/apm/public/hooks/useDynamicIndexPattern.ts index ee3d2e81f259f..9a95bd925d6e1 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useDynamicIndexPattern.ts +++ b/x-pack/plugins/apm/public/hooks/useDynamicIndexPattern.ts @@ -5,7 +5,7 @@ */ import { useFetcher } from './useFetcher'; -import { ProcessorEvent } from '../../../../../plugins/apm/common/processor_event'; +import { ProcessorEvent } from '../../common/processor_event'; export function useDynamicIndexPattern( processorEvent: ProcessorEvent | undefined diff --git a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx b/x-pack/plugins/apm/public/hooks/useFetcher.integration.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useFetcher.integration.test.tsx rename to x-pack/plugins/apm/public/hooks/useFetcher.integration.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.test.tsx b/x-pack/plugins/apm/public/hooks/useFetcher.test.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useFetcher.test.tsx rename to x-pack/plugins/apm/public/hooks/useFetcher.test.tsx diff --git a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.tsx b/x-pack/plugins/apm/public/hooks/useFetcher.tsx similarity index 98% rename from x-pack/legacy/plugins/apm/public/hooks/useFetcher.tsx rename to x-pack/plugins/apm/public/hooks/useFetcher.tsx index 95cebd6b2a465..5d5128d969aad 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useFetcher.tsx +++ b/x-pack/plugins/apm/public/hooks/useFetcher.tsx @@ -9,7 +9,7 @@ import React, { useContext, useEffect, useState, useMemo } from 'react'; import { i18n } from '@kbn/i18n'; import { IHttpFetchError } from 'src/core/public'; -import { toMountPoint } from '../../../../../../src/plugins/kibana_react/public'; +import { toMountPoint } from '../../../../../src/plugins/kibana_react/public'; import { LoadingIndicatorContext } from '../context/LoadingIndicatorContext'; import { APMClient, callApmApi } from '../services/rest/createCallApmApi'; import { useApmPluginContext } from './useApmPluginContext'; diff --git a/x-pack/legacy/plugins/apm/public/hooks/useKibanaUrl.ts b/x-pack/plugins/apm/public/hooks/useKibanaUrl.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useKibanaUrl.ts rename to x-pack/plugins/apm/public/hooks/useKibanaUrl.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useLicense.ts b/x-pack/plugins/apm/public/hooks/useLicense.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useLicense.ts rename to x-pack/plugins/apm/public/hooks/useLicense.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useLoadingIndicator.ts b/x-pack/plugins/apm/public/hooks/useLoadingIndicator.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useLoadingIndicator.ts rename to x-pack/plugins/apm/public/hooks/useLoadingIndicator.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useLocalUIFilters.ts b/x-pack/plugins/apm/public/hooks/useLocalUIFilters.ts similarity index 88% rename from x-pack/legacy/plugins/apm/public/hooks/useLocalUIFilters.ts rename to x-pack/plugins/apm/public/hooks/useLocalUIFilters.ts index 9f14b2b25fc94..1dfd3ec7c3ee3 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useLocalUIFilters.ts +++ b/x-pack/plugins/apm/public/hooks/useLocalUIFilters.ts @@ -7,18 +7,18 @@ import { omit } from 'lodash'; import { useFetcher } from './useFetcher'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { LocalUIFiltersAPIResponse } from '../../../../../plugins/apm/server/lib/ui_filters/local_ui_filters'; +import { LocalUIFiltersAPIResponse } from '../../server/lib/ui_filters/local_ui_filters'; import { useUrlParams } from './useUrlParams'; import { LocalUIFilterName, localUIFilters // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../plugins/apm/server/lib/ui_filters/local_ui_filters/config'; +} from '../../server/lib/ui_filters/local_ui_filters/config'; import { history } from '../utils/history'; import { toQuery, fromQuery } from '../components/shared/Links/url_helpers'; import { removeUndefinedProps } from '../context/UrlParamsContext/helpers'; -import { PROJECTION } from '../../../../../plugins/apm/common/projections/typings'; -import { pickKeys } from '../utils/pickKeys'; +import { PROJECTION } from '../../common/projections/typings'; +import { pickKeys } from '../../common/utils/pick_keys'; import { useCallApi } from './useCallApi'; const getInitialData = ( diff --git a/x-pack/legacy/plugins/apm/public/hooks/useLocation.tsx b/x-pack/plugins/apm/public/hooks/useLocation.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useLocation.tsx rename to x-pack/plugins/apm/public/hooks/useLocation.tsx diff --git a/x-pack/legacy/plugins/apm/public/hooks/useMatchedRoutes.tsx b/x-pack/plugins/apm/public/hooks/useMatchedRoutes.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useMatchedRoutes.tsx rename to x-pack/plugins/apm/public/hooks/useMatchedRoutes.tsx diff --git a/x-pack/legacy/plugins/apm/public/hooks/useServiceMetricCharts.ts b/x-pack/plugins/apm/public/hooks/useServiceMetricCharts.ts similarity index 91% rename from x-pack/legacy/plugins/apm/public/hooks/useServiceMetricCharts.ts rename to x-pack/plugins/apm/public/hooks/useServiceMetricCharts.ts index 72618a6254f4c..ebcd6ab063708 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useServiceMetricCharts.ts +++ b/x-pack/plugins/apm/public/hooks/useServiceMetricCharts.ts @@ -5,7 +5,7 @@ */ // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { MetricsChartsByAgentAPIResponse } from '../../../../../plugins/apm/server/lib/metrics/get_metrics_chart_data_by_agent'; +import { MetricsChartsByAgentAPIResponse } from '../../server/lib/metrics/get_metrics_chart_data_by_agent'; import { IUrlParams } from '../context/UrlParamsContext/types'; import { useUiFilters } from '../context/UrlParamsContext'; import { useFetcher } from './useFetcher'; diff --git a/x-pack/legacy/plugins/apm/public/hooks/useServiceTransactionTypes.tsx b/x-pack/plugins/apm/public/hooks/useServiceTransactionTypes.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useServiceTransactionTypes.tsx rename to x-pack/plugins/apm/public/hooks/useServiceTransactionTypes.tsx diff --git a/x-pack/legacy/plugins/apm/public/hooks/useTransactionBreakdown.ts b/x-pack/plugins/apm/public/hooks/useTransactionBreakdown.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useTransactionBreakdown.ts rename to x-pack/plugins/apm/public/hooks/useTransactionBreakdown.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useTransactionCharts.ts b/x-pack/plugins/apm/public/hooks/useTransactionCharts.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useTransactionCharts.ts rename to x-pack/plugins/apm/public/hooks/useTransactionCharts.ts diff --git a/x-pack/legacy/plugins/apm/public/hooks/useTransactionDistribution.ts b/x-pack/plugins/apm/public/hooks/useTransactionDistribution.ts similarity index 93% rename from x-pack/legacy/plugins/apm/public/hooks/useTransactionDistribution.ts rename to x-pack/plugins/apm/public/hooks/useTransactionDistribution.ts index 9a93a2334924a..152980b5655d6 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useTransactionDistribution.ts +++ b/x-pack/plugins/apm/public/hooks/useTransactionDistribution.ts @@ -8,7 +8,7 @@ import { IUrlParams } from '../context/UrlParamsContext/types'; import { useFetcher } from './useFetcher'; import { useUiFilters } from '../context/UrlParamsContext'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TransactionDistributionAPIResponse } from '../../../../../plugins/apm/server/lib/transactions/distribution'; +import { TransactionDistributionAPIResponse } from '../../server/lib/transactions/distribution'; const INITIAL_DATA = { buckets: [] as TransactionDistributionAPIResponse['buckets'], diff --git a/x-pack/legacy/plugins/apm/public/hooks/useTransactionList.ts b/x-pack/plugins/apm/public/hooks/useTransactionList.ts similarity index 94% rename from x-pack/legacy/plugins/apm/public/hooks/useTransactionList.ts rename to x-pack/plugins/apm/public/hooks/useTransactionList.ts index 6ede77023790b..e048e8fe0e3cb 100644 --- a/x-pack/legacy/plugins/apm/public/hooks/useTransactionList.ts +++ b/x-pack/plugins/apm/public/hooks/useTransactionList.ts @@ -9,7 +9,7 @@ import { IUrlParams } from '../context/UrlParamsContext/types'; import { useUiFilters } from '../context/UrlParamsContext'; import { useFetcher } from './useFetcher'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TransactionGroupListAPIResponse } from '../../../../../plugins/apm/server/lib/transaction_groups'; +import { TransactionGroupListAPIResponse } from '../../server/lib/transaction_groups'; const getRelativeImpact = ( impact: number, diff --git a/x-pack/legacy/plugins/apm/public/hooks/useUrlParams.tsx b/x-pack/plugins/apm/public/hooks/useUrlParams.tsx similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useUrlParams.tsx rename to x-pack/plugins/apm/public/hooks/useUrlParams.tsx diff --git a/x-pack/legacy/plugins/apm/public/hooks/useWaterfall.ts b/x-pack/plugins/apm/public/hooks/useWaterfall.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/hooks/useWaterfall.ts rename to x-pack/plugins/apm/public/hooks/useWaterfall.ts diff --git a/x-pack/legacy/plugins/apm/public/icon.svg b/x-pack/plugins/apm/public/icon.svg similarity index 100% rename from x-pack/legacy/plugins/apm/public/icon.svg rename to x-pack/plugins/apm/public/icon.svg diff --git a/x-pack/legacy/plugins/apm/public/images/apm-ml-anomaly-detection-example.png b/x-pack/plugins/apm/public/images/apm-ml-anomaly-detection-example.png similarity index 100% rename from x-pack/legacy/plugins/apm/public/images/apm-ml-anomaly-detection-example.png rename to x-pack/plugins/apm/public/images/apm-ml-anomaly-detection-example.png diff --git a/x-pack/plugins/apm/public/index.ts b/x-pack/plugins/apm/public/index.ts new file mode 100644 index 0000000000000..4ac06e1eb8a1c --- /dev/null +++ b/x-pack/plugins/apm/public/index.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 { + PluginInitializer, + PluginInitializerContext +} from '../../../../src/core/public'; +import { ApmPlugin, ApmPluginSetup, ApmPluginStart } from './plugin'; + +export interface ConfigSchema { + serviceMapEnabled: boolean; + ui: { + enabled: boolean; + }; +} + +export const plugin: PluginInitializer = ( + pluginInitializerContext: PluginInitializerContext +) => new ApmPlugin(pluginInitializerContext); + +export { ApmPluginSetup, ApmPluginStart }; +export { getTraceUrl } from './components/shared/Links/apm/ExternalLinks'; diff --git a/x-pack/plugins/apm/public/plugin.ts b/x-pack/plugins/apm/public/plugin.ts new file mode 100644 index 0000000000000..f13c8853d0582 --- /dev/null +++ b/x-pack/plugins/apm/public/plugin.ts @@ -0,0 +1,133 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { + AppMountParameters, + CoreSetup, + CoreStart, + Plugin, + PluginInitializerContext +} from '../../../../src/core/public'; +import { DEFAULT_APP_CATEGORIES } from '../../../../src/core/utils'; + +import { + PluginSetupContract as AlertingPluginPublicSetup, + PluginStartContract as AlertingPluginPublicStart +} from '../../alerting/public'; +import { FeaturesPluginSetup } from '../../features/public'; +import { + DataPublicPluginSetup, + DataPublicPluginStart +} from '../../../../src/plugins/data/public'; +import { HomePublicPluginSetup } from '../../../../src/plugins/home/public'; +import { LicensingPluginSetup } from '../../licensing/public'; +import { + TriggersAndActionsUIPublicPluginSetup, + TriggersAndActionsUIPublicPluginStart +} from '../../triggers_actions_ui/public'; +import { ConfigSchema } from '.'; +import { createCallApmApi } from './services/rest/createCallApmApi'; +import { featureCatalogueEntry } from './featureCatalogueEntry'; +import { AlertType } from '../common/alert_types'; +import { ErrorRateAlertTrigger } from './components/shared/ErrorRateAlertTrigger'; +import { TransactionDurationAlertTrigger } from './components/shared/TransactionDurationAlertTrigger'; +import { setHelpExtension } from './setHelpExtension'; +import { toggleAppLinkInNav } from './toggleAppLinkInNav'; +import { setReadonlyBadge } from './updateBadge'; +import { createStaticIndexPattern } from './services/rest/index_pattern'; + +export type ApmPluginSetup = void; +export type ApmPluginStart = void; + +export interface ApmPluginSetupDeps { + alerting?: AlertingPluginPublicSetup; + data: DataPublicPluginSetup; + features: FeaturesPluginSetup; + home: HomePublicPluginSetup; + licensing: LicensingPluginSetup; + triggers_actions_ui: TriggersAndActionsUIPublicPluginSetup; +} + +export interface ApmPluginStartDeps { + alerting?: AlertingPluginPublicStart; + data: DataPublicPluginStart; + home: void; + licensing: void; + triggers_actions_ui: TriggersAndActionsUIPublicPluginStart; +} + +export class ApmPlugin implements Plugin { + private readonly initializerContext: PluginInitializerContext; + constructor(initializerContext: PluginInitializerContext) { + this.initializerContext = initializerContext; + } + public setup(core: CoreSetup, plugins: ApmPluginSetupDeps) { + const config = this.initializerContext.config.get(); + const pluginSetupDeps = plugins; + + pluginSetupDeps.home.environment.update({ apmUi: true }); + pluginSetupDeps.home.featureCatalogue.register(featureCatalogueEntry); + + core.application.register({ + id: 'apm', + title: 'APM', + order: 8100, + euiIconType: 'apmApp', + appRoute: '/app/apm', + icon: 'plugins/apm/public/icon.svg', + category: DEFAULT_APP_CATEGORIES.observability, + + async mount(params: AppMountParameters) { + // Load application bundle + const { renderApp } = await import('./application'); + // Get start services + const [coreStart] = await core.getStartServices(); + + // render APM feedback link in global help menu + setHelpExtension(coreStart); + setReadonlyBadge(coreStart); + + // Automatically creates static index pattern and stores as saved object + createStaticIndexPattern().catch(e => { + // eslint-disable-next-line no-console + console.log('Error creating static index pattern', e); + }); + + return renderApp(coreStart, pluginSetupDeps, params, config); + } + }); + } + public start(core: CoreStart, plugins: ApmPluginStartDeps) { + createCallApmApi(core.http); + + toggleAppLinkInNav(core, this.initializerContext.config.get()); + + plugins.triggers_actions_ui.alertTypeRegistry.register({ + id: AlertType.ErrorRate, + name: i18n.translate('xpack.apm.alertTypes.errorRate', { + defaultMessage: 'Error rate' + }), + iconClass: 'bell', + alertParamsExpression: ErrorRateAlertTrigger, + validate: () => ({ + errors: [] + }) + }); + + plugins.triggers_actions_ui.alertTypeRegistry.register({ + id: AlertType.TransactionDuration, + name: i18n.translate('xpack.apm.alertTypes.transactionDuration', { + defaultMessage: 'Transaction duration' + }), + iconClass: 'bell', + alertParamsExpression: TransactionDurationAlertTrigger, + validate: () => ({ + errors: [] + }) + }); + } +} diff --git a/x-pack/legacy/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts b/x-pack/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts rename to x-pack/plugins/apm/public/selectors/__tests__/chartSelectors.test.ts diff --git a/x-pack/legacy/plugins/apm/public/selectors/__tests__/mockData/anomalyData.ts b/x-pack/plugins/apm/public/selectors/__tests__/mockData/anomalyData.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/selectors/__tests__/mockData/anomalyData.ts rename to x-pack/plugins/apm/public/selectors/__tests__/mockData/anomalyData.ts diff --git a/x-pack/legacy/plugins/apm/public/selectors/chartSelectors.ts b/x-pack/plugins/apm/public/selectors/chartSelectors.ts similarity index 94% rename from x-pack/legacy/plugins/apm/public/selectors/chartSelectors.ts rename to x-pack/plugins/apm/public/selectors/chartSelectors.ts index d60b63e243d71..e6ef9361ee52a 100644 --- a/x-pack/legacy/plugins/apm/public/selectors/chartSelectors.ts +++ b/x-pack/plugins/apm/public/selectors/chartSelectors.ts @@ -10,14 +10,14 @@ import { difference, zipObject } from 'lodash'; import mean from 'lodash.mean'; import { rgba } from 'polished'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { TimeSeriesAPIResponse } from '../../../../../plugins/apm/server/lib/transactions/charts'; +import { TimeSeriesAPIResponse } from '../../server/lib/transactions/charts'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { ApmTimeSeriesResponse } from '../../../../../plugins/apm/server/lib/transactions/charts/get_timeseries_data/transform'; +import { ApmTimeSeriesResponse } from '../../server/lib/transactions/charts/get_timeseries_data/transform'; import { Coordinate, RectCoordinate, TimeSeries -} from '../../../../../plugins/apm/typings/timeseries'; +} from '../../typings/timeseries'; import { asDecimal, tpmUnit, convertTo } from '../utils/formatters'; import { IUrlParams } from '../context/UrlParamsContext/types'; import { getEmptySeries } from '../components/shared/charts/CustomPlot/getEmptySeries'; diff --git a/x-pack/legacy/plugins/apm/public/services/__test__/SessionStorageMock.ts b/x-pack/plugins/apm/public/services/__test__/SessionStorageMock.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/services/__test__/SessionStorageMock.ts rename to x-pack/plugins/apm/public/services/__test__/SessionStorageMock.ts diff --git a/x-pack/legacy/plugins/apm/public/services/__test__/callApi.test.ts b/x-pack/plugins/apm/public/services/__test__/callApi.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/services/__test__/callApi.test.ts rename to x-pack/plugins/apm/public/services/__test__/callApi.test.ts diff --git a/x-pack/legacy/plugins/apm/public/services/__test__/callApmApi.test.ts b/x-pack/plugins/apm/public/services/__test__/callApmApi.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/services/__test__/callApmApi.test.ts rename to x-pack/plugins/apm/public/services/__test__/callApmApi.test.ts diff --git a/x-pack/legacy/plugins/apm/public/services/rest/callApi.ts b/x-pack/plugins/apm/public/services/rest/callApi.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/services/rest/callApi.ts rename to x-pack/plugins/apm/public/services/rest/callApi.ts diff --git a/x-pack/legacy/plugins/apm/public/services/rest/createCallApmApi.ts b/x-pack/plugins/apm/public/services/rest/createCallApmApi.ts similarity index 89% rename from x-pack/legacy/plugins/apm/public/services/rest/createCallApmApi.ts rename to x-pack/plugins/apm/public/services/rest/createCallApmApi.ts index 2fffb40d353fc..1027e8b885d71 100644 --- a/x-pack/legacy/plugins/apm/public/services/rest/createCallApmApi.ts +++ b/x-pack/plugins/apm/public/services/rest/createCallApmApi.ts @@ -6,9 +6,9 @@ import { HttpSetup } from 'kibana/public'; import { callApi, FetchOptions } from './callApi'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { APMAPI } from '../../../../../../plugins/apm/server/routes/create_apm_api'; +import { APMAPI } from '../../../server/routes/create_apm_api'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { Client } from '../../../../../../plugins/apm/server/routes/typings'; +import { Client } from '../../../server/routes/typings'; export type APMClient = Client; export type APMClientOptions = Omit & { diff --git a/x-pack/legacy/plugins/apm/public/services/rest/index_pattern.ts b/x-pack/plugins/apm/public/services/rest/index_pattern.ts similarity index 76% rename from x-pack/legacy/plugins/apm/public/services/rest/index_pattern.ts rename to x-pack/plugins/apm/public/services/rest/index_pattern.ts index 1efcc98bbbd66..ac7a0d3cf734b 100644 --- a/x-pack/legacy/plugins/apm/public/services/rest/index_pattern.ts +++ b/x-pack/plugins/apm/public/services/rest/index_pattern.ts @@ -12,3 +12,9 @@ export const createStaticIndexPattern = async () => { pathname: '/api/apm/index_pattern/static' }); }; + +export const getApmIndexPatternTitle = async () => { + return await callApmApi({ + pathname: '/api/apm/index_pattern/title' + }); +}; diff --git a/x-pack/legacy/plugins/apm/public/services/rest/ml.ts b/x-pack/plugins/apm/public/services/rest/ml.ts similarity index 91% rename from x-pack/legacy/plugins/apm/public/services/rest/ml.ts rename to x-pack/plugins/apm/public/services/rest/ml.ts index 0cd1bdf907531..b333a08d2eb05 100644 --- a/x-pack/legacy/plugins/apm/public/services/rest/ml.ts +++ b/x-pack/plugins/apm/public/services/rest/ml.ts @@ -9,14 +9,14 @@ import { PROCESSOR_EVENT, SERVICE_NAME, TRANSACTION_TYPE -} from '../../../../../../plugins/apm/common/elasticsearch_fieldnames'; +} from '../../../common/elasticsearch_fieldnames'; import { getMlJobId, getMlPrefix, encodeForMlApi -} from '../../../../../../plugins/apm/common/ml_job_constants'; +} from '../../../common/ml_job_constants'; import { callApi } from './callApi'; -import { ESFilter } from '../../../../../../plugins/apm/typings/elasticsearch'; +import { ESFilter } from '../../../typings/elasticsearch'; import { callApmApi } from './createCallApmApi'; interface MlResponseItem { diff --git a/x-pack/legacy/plugins/apm/public/services/rest/watcher.ts b/x-pack/plugins/apm/public/services/rest/watcher.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/services/rest/watcher.ts rename to x-pack/plugins/apm/public/services/rest/watcher.ts diff --git a/x-pack/legacy/plugins/apm/public/new-platform/setHelpExtension.ts b/x-pack/plugins/apm/public/setHelpExtension.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/new-platform/setHelpExtension.ts rename to x-pack/plugins/apm/public/setHelpExtension.ts diff --git a/x-pack/legacy/plugins/apm/public/style/variables.ts b/x-pack/plugins/apm/public/style/variables.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/style/variables.ts rename to x-pack/plugins/apm/public/style/variables.ts diff --git a/x-pack/legacy/plugins/apm/public/new-platform/toggleAppLinkInNav.ts b/x-pack/plugins/apm/public/toggleAppLinkInNav.ts similarity index 91% rename from x-pack/legacy/plugins/apm/public/new-platform/toggleAppLinkInNav.ts rename to x-pack/plugins/apm/public/toggleAppLinkInNav.ts index c807cebf97525..8204e1a022d7e 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/toggleAppLinkInNav.ts +++ b/x-pack/plugins/apm/public/toggleAppLinkInNav.ts @@ -5,7 +5,7 @@ */ import { CoreStart } from 'kibana/public'; -import { ConfigSchema } from './plugin'; +import { ConfigSchema } from '.'; export function toggleAppLinkInNav(core: CoreStart, { ui }: ConfigSchema) { if (ui.enabled === false) { diff --git a/x-pack/legacy/plugins/apm/public/new-platform/updateBadge.ts b/x-pack/plugins/apm/public/updateBadge.ts similarity index 99% rename from x-pack/legacy/plugins/apm/public/new-platform/updateBadge.ts rename to x-pack/plugins/apm/public/updateBadge.ts index b3e29bb891c23..10849754313c4 100644 --- a/x-pack/legacy/plugins/apm/public/new-platform/updateBadge.ts +++ b/x-pack/plugins/apm/public/updateBadge.ts @@ -10,7 +10,6 @@ import { CoreStart } from 'kibana/public'; export function setReadonlyBadge({ application, chrome }: CoreStart) { const canSave = application.capabilities.apm.save; const { setBadge } = chrome; - setBadge( !canSave ? { diff --git a/x-pack/legacy/plugins/apm/public/utils/__test__/flattenObject.test.ts b/x-pack/plugins/apm/public/utils/__test__/flattenObject.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/__test__/flattenObject.test.ts rename to x-pack/plugins/apm/public/utils/__test__/flattenObject.test.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/flattenObject.ts b/x-pack/plugins/apm/public/utils/flattenObject.ts similarity index 94% rename from x-pack/legacy/plugins/apm/public/utils/flattenObject.ts rename to x-pack/plugins/apm/public/utils/flattenObject.ts index 020bfec2cbd6a..295ea1f9f900f 100644 --- a/x-pack/legacy/plugins/apm/public/utils/flattenObject.ts +++ b/x-pack/plugins/apm/public/utils/flattenObject.ts @@ -5,7 +5,7 @@ */ import { compact, isObject } from 'lodash'; -import { Maybe } from '../../../../../plugins/apm/typings/common'; +import { Maybe } from '../../typings/common'; export interface KeyValuePair { key: string; diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/__test__/datetime.test.ts b/x-pack/plugins/apm/public/utils/formatters/__test__/datetime.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/formatters/__test__/datetime.test.ts rename to x-pack/plugins/apm/public/utils/formatters/__test__/datetime.test.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/__test__/duration.test.ts b/x-pack/plugins/apm/public/utils/formatters/__test__/duration.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/formatters/__test__/duration.test.ts rename to x-pack/plugins/apm/public/utils/formatters/__test__/duration.test.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/__test__/formatters.test.ts b/x-pack/plugins/apm/public/utils/formatters/__test__/formatters.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/formatters/__test__/formatters.test.ts rename to x-pack/plugins/apm/public/utils/formatters/__test__/formatters.test.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/__test__/size.test.ts b/x-pack/plugins/apm/public/utils/formatters/__test__/size.test.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/formatters/__test__/size.test.ts rename to x-pack/plugins/apm/public/utils/formatters/__test__/size.test.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/datetime.ts b/x-pack/plugins/apm/public/utils/formatters/datetime.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/formatters/datetime.ts rename to x-pack/plugins/apm/public/utils/formatters/datetime.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/duration.ts b/x-pack/plugins/apm/public/utils/formatters/duration.ts similarity index 96% rename from x-pack/legacy/plugins/apm/public/utils/formatters/duration.ts rename to x-pack/plugins/apm/public/utils/formatters/duration.ts index 681d876ca3beb..39341e1ff4443 100644 --- a/x-pack/legacy/plugins/apm/public/utils/formatters/duration.ts +++ b/x-pack/plugins/apm/public/utils/formatters/duration.ts @@ -7,10 +7,10 @@ import { i18n } from '@kbn/i18n'; import moment from 'moment'; import { memoize } from 'lodash'; -import { NOT_AVAILABLE_LABEL } from '../../../../../../plugins/apm/common/i18n'; +import { NOT_AVAILABLE_LABEL } from '../../../common/i18n'; import { asDecimal, asInteger } from './formatters'; import { TimeUnit } from './datetime'; -import { Maybe } from '../../../../../../plugins/apm/typings/common'; +import { Maybe } from '../../../typings/common'; interface FormatterOptions { defaultValue?: string; diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/formatters.ts b/x-pack/plugins/apm/public/utils/formatters/formatters.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/formatters/formatters.ts rename to x-pack/plugins/apm/public/utils/formatters/formatters.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/index.ts b/x-pack/plugins/apm/public/utils/formatters/index.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/formatters/index.ts rename to x-pack/plugins/apm/public/utils/formatters/index.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/formatters/size.ts b/x-pack/plugins/apm/public/utils/formatters/size.ts similarity index 95% rename from x-pack/legacy/plugins/apm/public/utils/formatters/size.ts rename to x-pack/plugins/apm/public/utils/formatters/size.ts index 8fe6ebf3e573d..2cdf8af1d46de 100644 --- a/x-pack/legacy/plugins/apm/public/utils/formatters/size.ts +++ b/x-pack/plugins/apm/public/utils/formatters/size.ts @@ -5,7 +5,7 @@ */ import { memoize } from 'lodash'; import { asDecimal } from './formatters'; -import { Maybe } from '../../../../../../plugins/apm/typings/common'; +import { Maybe } from '../../../typings/common'; function asKilobytes(value: number) { return `${asDecimal(value / 1000)} KB`; diff --git a/x-pack/legacy/plugins/apm/public/utils/getRangeFromTimeSeries.ts b/x-pack/plugins/apm/public/utils/getRangeFromTimeSeries.ts similarity index 88% rename from x-pack/legacy/plugins/apm/public/utils/getRangeFromTimeSeries.ts rename to x-pack/plugins/apm/public/utils/getRangeFromTimeSeries.ts index 4301ead2fc79f..1865d5ae574a7 100644 --- a/x-pack/legacy/plugins/apm/public/utils/getRangeFromTimeSeries.ts +++ b/x-pack/plugins/apm/public/utils/getRangeFromTimeSeries.ts @@ -5,7 +5,7 @@ */ import { flatten } from 'lodash'; -import { TimeSeries } from '../../../../../plugins/apm/typings/timeseries'; +import { TimeSeries } from '../../typings/timeseries'; export const getRangeFromTimeSeries = (timeseries: TimeSeries[]) => { const dataPoints = flatten(timeseries.map(series => series.data)); diff --git a/x-pack/legacy/plugins/apm/public/utils/history.ts b/x-pack/plugins/apm/public/utils/history.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/history.ts rename to x-pack/plugins/apm/public/utils/history.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/httpStatusCodeToColor.ts b/x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts similarity index 100% rename from x-pack/legacy/plugins/apm/public/utils/httpStatusCodeToColor.ts rename to x-pack/plugins/apm/public/utils/httpStatusCodeToColor.ts diff --git a/x-pack/legacy/plugins/apm/public/utils/isValidCoordinateValue.ts b/x-pack/plugins/apm/public/utils/isValidCoordinateValue.ts similarity index 84% rename from x-pack/legacy/plugins/apm/public/utils/isValidCoordinateValue.ts rename to x-pack/plugins/apm/public/utils/isValidCoordinateValue.ts index f7c13603c3535..c36efc232b782 100644 --- a/x-pack/legacy/plugins/apm/public/utils/isValidCoordinateValue.ts +++ b/x-pack/plugins/apm/public/utils/isValidCoordinateValue.ts @@ -3,7 +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 { Maybe } from '../../../../../plugins/apm/typings/common'; +import { Maybe } from '../../typings/common'; export const isValidCoordinateValue = (value: Maybe): value is number => value !== null && value !== undefined; diff --git a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx b/x-pack/plugins/apm/public/utils/testHelpers.tsx similarity index 96% rename from x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx rename to x-pack/plugins/apm/public/utils/testHelpers.tsx index 36c0e18777bfd..def41a1cabd61 100644 --- a/x-pack/legacy/plugins/apm/public/utils/testHelpers.tsx +++ b/x-pack/plugins/apm/public/utils/testHelpers.tsx @@ -16,14 +16,14 @@ import { render, waitForElement } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; import { MemoryRouter } from 'react-router-dom'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { APMConfig } from '../../../../../plugins/apm/server'; +import { APMConfig } from '../../server'; import { LocationProvider } from '../context/LocationContext'; -import { PromiseReturnType } from '../../../../../plugins/apm/typings/common'; +import { PromiseReturnType } from '../../typings/common'; import { ESFilter, ESSearchResponse, ESSearchRequest -} from '../../../../../plugins/apm/typings/elasticsearch'; +} from '../../typings/elasticsearch'; import { MockApmPluginContextWrapper } from '../context/ApmPluginContext/MockApmPluginContext'; export function toJson(wrapper: ReactWrapper) { diff --git a/x-pack/legacy/plugins/apm/readme.md b/x-pack/plugins/apm/readme.md similarity index 92% rename from x-pack/legacy/plugins/apm/readme.md rename to x-pack/plugins/apm/readme.md index e8e2514c83fcb..62465e920d793 100644 --- a/x-pack/legacy/plugins/apm/readme.md +++ b/x-pack/plugins/apm/readme.md @@ -32,7 +32,7 @@ _Docker Compose is required_ ### E2E (Cypress) tests ```sh -x-pack/legacy/plugins/apm/e2e/run-e2e.sh +x-pack/plugins/apm/e2e/run-e2e.sh ``` _Starts Kibana (:5701), APM Server (:8201) and Elasticsearch (:9201). Ingests sample data into Elasticsearch via APM Server and runs the Cypress tests_ @@ -94,13 +94,13 @@ _Note: Run the following commands from `kibana/`._ #### Prettier ``` -yarn prettier "./x-pack/legacy/plugins/apm/**/*.{tsx,ts,js}" --write +yarn prettier "./x-pack/plugins/apm/**/*.{tsx,ts,js}" --write ``` #### ESLint ``` -yarn eslint ./x-pack/legacy/plugins/apm --fix +yarn eslint ./x-pack/plugins/apm --fix ``` ### Setup default APM users @@ -117,7 +117,7 @@ For testing purposes APM uses 3 custom users: To create the users with the correct roles run the following script: ```sh -node x-pack/legacy/plugins/apm/scripts/setup-kibana-security.js --role-suffix +node x-pack/plugins/apm/scripts/setup-kibana-security.js --role-suffix ``` The users will be created with the password specified in kibana.dev.yml for `elasticsearch.password` diff --git a/x-pack/legacy/plugins/apm/scripts/.gitignore b/x-pack/plugins/apm/scripts/.gitignore similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/.gitignore rename to x-pack/plugins/apm/scripts/.gitignore diff --git a/x-pack/legacy/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts b/x-pack/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts rename to x-pack/plugins/apm/scripts/kibana-security/setup-custom-kibana-user-role.ts diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig.js b/x-pack/plugins/apm/scripts/optimize-tsconfig.js similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/optimize-tsconfig.js rename to x-pack/plugins/apm/scripts/optimize-tsconfig.js diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/optimize.js b/x-pack/plugins/apm/scripts/optimize-tsconfig/optimize.js similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/optimize.js rename to x-pack/plugins/apm/scripts/optimize-tsconfig/optimize.js diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/paths.js b/x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/paths.js rename to x-pack/plugins/apm/scripts/optimize-tsconfig/paths.js diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json b/x-pack/plugins/apm/scripts/optimize-tsconfig/tsconfig.json similarity index 60% rename from x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json rename to x-pack/plugins/apm/scripts/optimize-tsconfig/tsconfig.json index 8f6b0f35e4b52..5e05d3962eccb 100644 --- a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/tsconfig.json +++ b/x-pack/plugins/apm/scripts/optimize-tsconfig/tsconfig.json @@ -1,11 +1,10 @@ { "include": [ "./plugins/apm/**/*", - "./legacy/plugins/apm/**/*", "./typings/**/*" ], "exclude": [ "**/__fixtures__/**/*", - "./legacy/plugins/apm/e2e/cypress/**/*" + "./plugins/apm/e2e/cypress/**/*" ] } diff --git a/x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/unoptimize.js b/x-pack/plugins/apm/scripts/optimize-tsconfig/unoptimize.js similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/optimize-tsconfig/unoptimize.js rename to x-pack/plugins/apm/scripts/optimize-tsconfig/unoptimize.js diff --git a/x-pack/legacy/plugins/apm/scripts/package.json b/x-pack/plugins/apm/scripts/package.json similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/package.json rename to x-pack/plugins/apm/scripts/package.json diff --git a/x-pack/legacy/plugins/apm/scripts/setup-kibana-security.js b/x-pack/plugins/apm/scripts/setup-kibana-security.js similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/setup-kibana-security.js rename to x-pack/plugins/apm/scripts/setup-kibana-security.js diff --git a/x-pack/legacy/plugins/apm/scripts/storybook.js b/x-pack/plugins/apm/scripts/storybook.js similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/storybook.js rename to x-pack/plugins/apm/scripts/storybook.js diff --git a/x-pack/legacy/plugins/apm/scripts/unoptimize-tsconfig.js b/x-pack/plugins/apm/scripts/unoptimize-tsconfig.js similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/unoptimize-tsconfig.js rename to x-pack/plugins/apm/scripts/unoptimize-tsconfig.js diff --git a/x-pack/legacy/plugins/apm/scripts/upload-telemetry-data.js b/x-pack/plugins/apm/scripts/upload-telemetry-data.js similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/upload-telemetry-data.js rename to x-pack/plugins/apm/scripts/upload-telemetry-data.js diff --git a/x-pack/legacy/plugins/apm/scripts/upload-telemetry-data/download-telemetry-template.ts b/x-pack/plugins/apm/scripts/upload-telemetry-data/download-telemetry-template.ts similarity index 100% rename from x-pack/legacy/plugins/apm/scripts/upload-telemetry-data/download-telemetry-template.ts rename to x-pack/plugins/apm/scripts/upload-telemetry-data/download-telemetry-template.ts diff --git a/x-pack/legacy/plugins/apm/scripts/upload-telemetry-data/generate-sample-documents.ts b/x-pack/plugins/apm/scripts/upload-telemetry-data/generate-sample-documents.ts similarity index 97% rename from x-pack/legacy/plugins/apm/scripts/upload-telemetry-data/generate-sample-documents.ts rename to x-pack/plugins/apm/scripts/upload-telemetry-data/generate-sample-documents.ts index 8d76063a7fdf6..390609996874b 100644 --- a/x-pack/legacy/plugins/apm/scripts/upload-telemetry-data/generate-sample-documents.ts +++ b/x-pack/plugins/apm/scripts/upload-telemetry-data/generate-sample-documents.ts @@ -18,7 +18,7 @@ import { CollectTelemetryParams, collectDataTelemetry // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../../plugins/apm/server/lib/apm_telemetry/collect_data_telemetry'; +} from '../../server/lib/apm_telemetry/collect_data_telemetry'; interface GenerateOptions { days: number; diff --git a/x-pack/legacy/plugins/apm/scripts/upload-telemetry-data/index.ts b/x-pack/plugins/apm/scripts/upload-telemetry-data/index.ts similarity index 98% rename from x-pack/legacy/plugins/apm/scripts/upload-telemetry-data/index.ts rename to x-pack/plugins/apm/scripts/upload-telemetry-data/index.ts index bdc57eac412fc..4f69a3a3bd213 100644 --- a/x-pack/legacy/plugins/apm/scripts/upload-telemetry-data/index.ts +++ b/x-pack/plugins/apm/scripts/upload-telemetry-data/index.ts @@ -25,7 +25,7 @@ import { Logger } from 'kibana/server'; // @ts-ignore import consoleStamp from 'console-stamp'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths -import { CollectTelemetryParams } from '../../../../../plugins/apm/server/lib/apm_telemetry/collect_data_telemetry'; +import { CollectTelemetryParams } from '../../server/lib/apm_telemetry/collect_data_telemetry'; import { downloadTelemetryTemplate } from './download-telemetry-template'; import mapping from '../../mappings.json'; import { generateSampleDocuments } from './generate-sample-documents'; diff --git a/x-pack/plugins/apm/server/feature.ts b/x-pack/plugins/apm/server/feature.ts new file mode 100644 index 0000000000000..ae0f5510cd80e --- /dev/null +++ b/x-pack/plugins/apm/server/feature.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 { i18n } from '@kbn/i18n'; + +export const APM_FEATURE = { + id: 'apm', + name: i18n.translate('xpack.apm.featureRegistry.apmFeatureName', { + defaultMessage: 'APM' + }), + order: 900, + icon: 'apmApp', + navLinkId: 'apm', + app: ['apm', 'kibana'], + catalogue: ['apm'], + // see x-pack/plugins/features/common/feature_kibana_privileges.ts + privileges: { + all: { + app: ['apm', 'kibana'], + api: [ + 'apm', + 'apm_write', + 'actions-read', + 'actions-all', + 'alerting-read', + 'alerting-all' + ], + catalogue: ['apm'], + savedObject: { + all: ['alert', 'action', 'action_task_params'], + read: [] + }, + ui: [ + 'show', + 'save', + 'alerting:show', + 'actions:show', + 'alerting:save', + 'actions:save', + 'alerting:delete', + 'actions:delete' + ] + }, + read: { + app: ['apm', 'kibana'], + api: [ + 'apm', + 'actions-read', + 'actions-all', + 'alerting-read', + 'alerting-all' + ], + catalogue: ['apm'], + savedObject: { + all: ['alert', 'action', 'action_task_params'], + read: [] + }, + ui: [ + 'show', + 'alerting:show', + 'actions:show', + 'alerting:save', + 'actions:save', + 'alerting:delete', + 'actions:delete' + ] + } + } +}; diff --git a/x-pack/plugins/apm/server/index.ts b/x-pack/plugins/apm/server/index.ts index 77655568a7e9c..9009008790631 100644 --- a/x-pack/plugins/apm/server/index.ts +++ b/x-pack/plugins/apm/server/index.ts @@ -73,4 +73,4 @@ export type APMConfig = ReturnType; export const plugin = (initContext: PluginInitializerContext) => new APMPlugin(initContext); -export { APMPlugin, APMPluginContract } from './plugin'; +export { APMPlugin, APMPluginSetup } from './plugin'; diff --git a/x-pack/plugins/apm/server/lib/errors/distribution/queries.test.ts b/x-pack/plugins/apm/server/lib/errors/distribution/queries.test.ts index 0d539a09f091b..fcc456c653303 100644 --- a/x-pack/plugins/apm/server/lib/errors/distribution/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/errors/distribution/queries.test.ts @@ -8,7 +8,7 @@ import { getErrorDistribution } from './get_distribution'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../../public/utils/testHelpers'; describe('error distribution queries', () => { let mock: SearchParamsMock; diff --git a/x-pack/plugins/apm/server/lib/errors/queries.test.ts b/x-pack/plugins/apm/server/lib/errors/queries.test.ts index 5b063c2fb2b61..f1e5d31efd4bd 100644 --- a/x-pack/plugins/apm/server/lib/errors/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/errors/queries.test.ts @@ -9,7 +9,7 @@ import { getErrorGroups } from './get_error_groups'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../public/utils/testHelpers'; describe('error queries', () => { let mock: SearchParamsMock; diff --git a/x-pack/plugins/apm/server/lib/helpers/es_client.ts b/x-pack/plugins/apm/server/lib/helpers/es_client.ts index c22084dbb7168..de9ab87b69fc8 100644 --- a/x-pack/plugins/apm/server/lib/helpers/es_client.ts +++ b/x-pack/plugins/apm/server/lib/helpers/es_client.ts @@ -20,7 +20,7 @@ import { ESSearchResponse } from '../../../typings/elasticsearch'; import { OBSERVER_VERSION_MAJOR } from '../../../common/elasticsearch_fieldnames'; -import { pickKeys } from '../../../../../legacy/plugins/apm/public/utils/pickKeys'; +import { pickKeys } from '../../../common/utils/pick_keys'; import { APMRequestHandlerContext } from '../../routes/typings'; import { getApmIndices } from '../settings/apm_indices/get_apm_indices'; diff --git a/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts b/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts index 8e8cf698a84cf..40a2a0e7216a0 100644 --- a/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts +++ b/x-pack/plugins/apm/server/lib/helpers/setup_request.test.ts @@ -39,19 +39,6 @@ function getMockRequest() { _debug: false } }, - __LEGACY: { - server: { - plugins: { - elasticsearch: { - getCluster: jest.fn().mockReturnValue({ callWithInternalUser: {} }) - } - }, - savedObjects: { - SavedObjectsClient: jest.fn(), - getSavedObjectsRepository: jest.fn() - } - } - }, core: { elasticsearch: { dataClient: { diff --git a/x-pack/plugins/apm/server/lib/index_pattern/get_apm_index_pattern_title.ts b/x-pack/plugins/apm/server/lib/index_pattern/get_apm_index_pattern_title.ts new file mode 100644 index 0000000000000..b3b40bac7bd54 --- /dev/null +++ b/x-pack/plugins/apm/server/lib/index_pattern/get_apm_index_pattern_title.ts @@ -0,0 +1,10 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { APMRequestHandlerContext } from '../../routes/typings'; + +export function getApmIndexPatternTitle(context: APMRequestHandlerContext) { + return context.config['apm_oss.indexPattern']; +} diff --git a/x-pack/plugins/apm/server/lib/metrics/queries.test.ts b/x-pack/plugins/apm/server/lib/metrics/queries.test.ts index ac4e13ae442cf..f276fa69e20e3 100644 --- a/x-pack/plugins/apm/server/lib/metrics/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/metrics/queries.test.ts @@ -12,7 +12,7 @@ import { getThreadCountChart } from './by_agent/java/thread_count'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../public/utils/testHelpers'; import { SERVICE_NODE_NAME_MISSING } from '../../../common/service_nodes'; describe('metrics queries', () => { diff --git a/x-pack/plugins/apm/server/lib/service_nodes/queries.test.ts b/x-pack/plugins/apm/server/lib/service_nodes/queries.test.ts index 672d568b3a5e3..80cd94b1549d7 100644 --- a/x-pack/plugins/apm/server/lib/service_nodes/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/service_nodes/queries.test.ts @@ -13,7 +13,7 @@ import { getServiceNodes } from './'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../public/utils/testHelpers'; import { getServiceNodeMetadata } from '../services/get_service_node_metadata'; import { SERVICE_NODE_NAME_MISSING } from '../../../common/service_nodes'; diff --git a/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts b/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts index 0e52982c6de28..614014ee37afc 100644 --- a/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts +++ b/x-pack/plugins/apm/server/lib/services/annotations/index.test.ts @@ -7,7 +7,7 @@ import { getServiceAnnotations } from '.'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../../public/utils/testHelpers'; import noVersions from './__fixtures__/no_versions.json'; import oneVersion from './__fixtures__/one_version.json'; import multipleVersions from './__fixtures__/multiple_versions.json'; diff --git a/x-pack/plugins/apm/server/lib/services/queries.test.ts b/x-pack/plugins/apm/server/lib/services/queries.test.ts index e75d9ad05648c..16490ace77744 100644 --- a/x-pack/plugins/apm/server/lib/services/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/services/queries.test.ts @@ -12,7 +12,7 @@ import { hasHistoricalAgentData } from './get_services/has_historical_agent_data import { SearchParamsMock, inspectSearchParams -} from '../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../public/utils/testHelpers'; describe('services queries', () => { let mock: SearchParamsMock; diff --git a/x-pack/plugins/apm/server/lib/settings/agent_configuration/queries.test.ts b/x-pack/plugins/apm/server/lib/settings/agent_configuration/queries.test.ts index b951b7f350eed..a1a915e6a84a5 100644 --- a/x-pack/plugins/apm/server/lib/settings/agent_configuration/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/settings/agent_configuration/queries.test.ts @@ -12,7 +12,7 @@ import { searchConfigurations } from './search_configurations'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../../public/utils/testHelpers'; import { findExactConfiguration } from './find_exact_configuration'; describe('agent configuration queries', () => { diff --git a/x-pack/plugins/apm/server/lib/settings/custom_link/create_or_update_custom_link.test.ts b/x-pack/plugins/apm/server/lib/settings/custom_link/create_or_update_custom_link.test.ts index 9bd6c78797605..5d0bf329368f7 100644 --- a/x-pack/plugins/apm/server/lib/settings/custom_link/create_or_update_custom_link.test.ts +++ b/x-pack/plugins/apm/server/lib/settings/custom_link/create_or_update_custom_link.test.ts @@ -5,7 +5,7 @@ */ import { Setup } from '../../helpers/setup_request'; -import { mockNow } from '../../../../../../legacy/plugins/apm/public/utils/testHelpers'; +import { mockNow } from '../../../../public/utils/testHelpers'; import { CustomLink } from '../../../../common/custom_link/custom_link_types'; import { createOrUpdateCustomLink } from './create_or_update_custom_link'; diff --git a/x-pack/plugins/apm/server/lib/settings/custom_link/get_transaction.test.ts b/x-pack/plugins/apm/server/lib/settings/custom_link/get_transaction.test.ts index 514e473b8e78c..0254660e3523f 100644 --- a/x-pack/plugins/apm/server/lib/settings/custom_link/get_transaction.test.ts +++ b/x-pack/plugins/apm/server/lib/settings/custom_link/get_transaction.test.ts @@ -6,7 +6,7 @@ import { inspectSearchParams, SearchParamsMock -} from '../../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../../public/utils/testHelpers'; import { getTransaction } from './get_transaction'; import { Setup } from '../../helpers/setup_request'; import { diff --git a/x-pack/plugins/apm/server/lib/settings/custom_link/list_custom_links.test.ts b/x-pack/plugins/apm/server/lib/settings/custom_link/list_custom_links.test.ts index 45610e36786b7..6a67c30bee197 100644 --- a/x-pack/plugins/apm/server/lib/settings/custom_link/list_custom_links.test.ts +++ b/x-pack/plugins/apm/server/lib/settings/custom_link/list_custom_links.test.ts @@ -8,7 +8,7 @@ import { listCustomLinks } from './list_custom_links'; import { inspectSearchParams, SearchParamsMock -} from '../../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../../public/utils/testHelpers'; import { Setup } from '../../helpers/setup_request'; import { SERVICE_NAME, diff --git a/x-pack/plugins/apm/server/lib/traces/queries.test.ts b/x-pack/plugins/apm/server/lib/traces/queries.test.ts index 0c2ac4d0f9201..871d0fd1c7fb6 100644 --- a/x-pack/plugins/apm/server/lib/traces/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/traces/queries.test.ts @@ -8,7 +8,7 @@ import { getTraceItems } from './get_trace_items'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../public/utils/testHelpers'; describe('trace queries', () => { let mock: SearchParamsMock; diff --git a/x-pack/plugins/apm/server/lib/transaction_groups/queries.test.ts b/x-pack/plugins/apm/server/lib/transaction_groups/queries.test.ts index 8d6495c2e0b5f..73122d8580134 100644 --- a/x-pack/plugins/apm/server/lib/transaction_groups/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/transaction_groups/queries.test.ts @@ -8,7 +8,7 @@ import { transactionGroupsFetcher } from './fetcher'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../public/utils/testHelpers'; describe('transaction group queries', () => { let mock: SearchParamsMock; diff --git a/x-pack/plugins/apm/server/lib/transactions/queries.test.ts b/x-pack/plugins/apm/server/lib/transactions/queries.test.ts index 116738da5ef9b..a9e4204fde1ad 100644 --- a/x-pack/plugins/apm/server/lib/transactions/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/transactions/queries.test.ts @@ -11,7 +11,7 @@ import { getTransaction } from './get_transaction'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../public/utils/testHelpers'; describe('transaction queries', () => { let mock: SearchParamsMock; diff --git a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/queries.test.ts b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/queries.test.ts index 21cc35da72cb9..b72186f528f28 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/local_ui_filters/queries.test.ts @@ -8,7 +8,7 @@ import { getLocalUIFilters } from './'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../../public/utils/testHelpers'; import { getServicesProjection } from '../../../../common/projections/services'; describe('local ui filter queries', () => { diff --git a/x-pack/plugins/apm/server/lib/ui_filters/queries.test.ts b/x-pack/plugins/apm/server/lib/ui_filters/queries.test.ts index 63c8c3e494bb0..079ab64f32db3 100644 --- a/x-pack/plugins/apm/server/lib/ui_filters/queries.test.ts +++ b/x-pack/plugins/apm/server/lib/ui_filters/queries.test.ts @@ -8,7 +8,7 @@ import { getEnvironments } from './get_environments'; import { SearchParamsMock, inspectSearchParams -} from '../../../../../legacy/plugins/apm/public/utils/testHelpers'; +} from '../../../public/utils/testHelpers'; describe('ui filter queries', () => { let mock: SearchParamsMock; diff --git a/x-pack/plugins/apm/server/plugin.ts b/x-pack/plugins/apm/server/plugin.ts index b434d41982f4c..8cf29de5b8b73 100644 --- a/x-pack/plugins/apm/server/plugin.ts +++ b/x-pack/plugins/apm/server/plugin.ts @@ -10,10 +10,8 @@ import { CoreStart, Logger } from 'src/core/server'; -import { Observable, combineLatest, AsyncSubject } from 'rxjs'; +import { Observable, combineLatest } from 'rxjs'; import { map, take } from 'rxjs/operators'; -import { Server } from 'hapi'; -import { once } from 'lodash'; import { UsageCollectionSetup } from '../../../../src/plugins/usage_collection/server'; import { TaskManagerSetupContract } from '../../task_manager/server'; import { AlertingPlugin } from '../../alerting/server'; @@ -31,24 +29,20 @@ import { getInternalSavedObjectsClient } from './lib/helpers/get_internal_saved_ import { LicensingPluginSetup } from '../../licensing/public'; import { registerApmAlerts } from './lib/alerts/register_apm_alerts'; import { createApmTelemetry } from './lib/apm_telemetry'; +import { PluginSetupContract as FeaturesPluginSetup } from '../../../plugins/features/server'; +import { APM_FEATURE } from './feature'; +import { apmIndices, apmTelemetry } from './saved_objects'; -export interface LegacySetup { - server: Server; -} - -export interface APMPluginContract { +export interface APMPluginSetup { config$: Observable; - registerLegacyAPI: (__LEGACY: LegacySetup) => void; getApmIndices: () => ReturnType; } -export class APMPlugin implements Plugin { +export class APMPlugin implements Plugin { private currentConfig?: APMConfig; private logger?: Logger; - legacySetup$: AsyncSubject; constructor(private readonly initContext: PluginInitializerContext) { this.initContext = initContext; - this.legacySetup$ = new AsyncSubject(); } public async setup( @@ -62,6 +56,7 @@ export class APMPlugin implements Plugin { taskManager?: TaskManagerSetupContract; alerting?: AlertingPlugin['setup']; actions?: ActionsPlugin['setup']; + features: FeaturesPluginSetup; } ) { this.logger = this.initContext.logger.get(); @@ -70,6 +65,9 @@ export class APMPlugin implements Plugin { map(([apmOssConfig, apmConfig]) => mergeConfigs(apmOssConfig, apmConfig)) ); + core.savedObjects.registerType(apmIndices); + core.savedObjects.registerType(apmTelemetry); + if (plugins.actions && plugins.alerting) { registerApmAlerts({ alerting: plugins.alerting, @@ -78,14 +76,6 @@ export class APMPlugin implements Plugin { }); } - this.legacySetup$.subscribe(__LEGACY => { - createApmApi().init(core, { - config$: mergedConfig$, - logger: this.logger!, - __LEGACY - }); - }); - this.currentConfig = await mergedConfig$.pipe(take(1)).toPromise(); if ( @@ -116,13 +106,15 @@ export class APMPlugin implements Plugin { } }) ); + plugins.features.registerFeature(APM_FEATURE); + + createApmApi().init(core, { + config$: mergedConfig$, + logger: this.logger! + }); return { config$: mergedConfig$, - registerLegacyAPI: once((__LEGACY: LegacySetup) => { - this.legacySetup$.next(__LEGACY); - this.legacySetup$.complete(); - }), getApmIndices: async () => getApmIndices({ savedObjectsClient: await getInternalSavedObjectsClient(core), diff --git a/x-pack/plugins/apm/server/routes/create_api/index.test.ts b/x-pack/plugins/apm/server/routes/create_api/index.test.ts index 312dae1d1f9d2..20c586868a979 100644 --- a/x-pack/plugins/apm/server/routes/create_api/index.test.ts +++ b/x-pack/plugins/apm/server/routes/create_api/index.test.ts @@ -9,7 +9,6 @@ import { CoreSetup, Logger } from 'src/core/server'; import { Params } from '../typings'; import { BehaviorSubject } from 'rxjs'; import { APMConfig } from '../..'; -import { LegacySetup } from '../../plugin'; const getCoreMock = () => { const get = jest.fn(); @@ -40,8 +39,7 @@ const getCoreMock = () => { config$: new BehaviorSubject({} as APMConfig), logger: ({ error: jest.fn() - } as unknown) as Logger, - __LEGACY: {} as LegacySetup + } as unknown) as Logger } }; }; diff --git a/x-pack/plugins/apm/server/routes/create_api/index.ts b/x-pack/plugins/apm/server/routes/create_api/index.ts index e216574f8a02e..a97e2f30fc2b6 100644 --- a/x-pack/plugins/apm/server/routes/create_api/index.ts +++ b/x-pack/plugins/apm/server/routes/create_api/index.ts @@ -30,7 +30,7 @@ export function createApi() { factoryFns.push(fn); return this as any; }, - init(core, { config$, logger, __LEGACY }) { + init(core, { config$, logger }) { const router = core.http.createRouter(); let config = {} as APMConfig; @@ -136,7 +136,6 @@ export function createApi() { request, context: { ...context, - __LEGACY, // Only return values for parameters that have runtime types, // but always include query as _debug is always set even if // it's not defined in the route. diff --git a/x-pack/plugins/apm/server/routes/create_apm_api.ts b/x-pack/plugins/apm/server/routes/create_apm_api.ts index 57b3f282852c4..7964d8b0268e8 100644 --- a/x-pack/plugins/apm/server/routes/create_apm_api.ts +++ b/x-pack/plugins/apm/server/routes/create_apm_api.ts @@ -6,7 +6,8 @@ import { staticIndexPatternRoute, - dynamicIndexPatternRoute + dynamicIndexPatternRoute, + apmIndexPatternTitleRoute } from './index_pattern'; import { errorDistributionRoute, @@ -73,6 +74,7 @@ const createApmApi = () => { // index pattern .add(staticIndexPatternRoute) .add(dynamicIndexPatternRoute) + .add(apmIndexPatternTitleRoute) // Errors .add(errorDistributionRoute) diff --git a/x-pack/plugins/apm/server/routes/index_pattern.ts b/x-pack/plugins/apm/server/routes/index_pattern.ts index b7964dc8e91ed..e296057203ff1 100644 --- a/x-pack/plugins/apm/server/routes/index_pattern.ts +++ b/x-pack/plugins/apm/server/routes/index_pattern.ts @@ -8,6 +8,7 @@ import { createStaticIndexPattern } from '../lib/index_pattern/create_static_ind import { createRoute } from './create_route'; import { setupRequest } from '../lib/helpers/setup_request'; import { getInternalSavedObjectsClient } from '../lib/helpers/get_internal_saved_objects_client'; +import { getApmIndexPatternTitle } from '../lib/index_pattern/get_apm_index_pattern_title'; export const staticIndexPatternRoute = createRoute(core => ({ method: 'POST', @@ -38,3 +39,10 @@ export const dynamicIndexPatternRoute = createRoute(() => ({ return { dynamicIndexPattern }; } })); + +export const apmIndexPatternTitleRoute = createRoute(() => ({ + path: '/api/apm/index_pattern/title', + handler: async ({ context }) => { + return getApmIndexPatternTitle(context); + } +})); diff --git a/x-pack/plugins/apm/server/routes/typings.ts b/x-pack/plugins/apm/server/routes/typings.ts index 3dc485630c180..6543f2015599b 100644 --- a/x-pack/plugins/apm/server/routes/typings.ts +++ b/x-pack/plugins/apm/server/routes/typings.ts @@ -14,7 +14,8 @@ import { import { PickByValue, Optional } from 'utility-types'; import { Observable } from 'rxjs'; import { Server } from 'hapi'; -import { FetchOptions } from '../../../../legacy/plugins/apm/public/services/rest/callApi'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { FetchOptions } from '../../public/services/rest/callApi'; import { APMConfig } from '..'; export interface Params { @@ -61,9 +62,6 @@ export type APMRequestHandlerContext< params: { query: { _debug: boolean } } & TDecodedParams; config: APMConfig; logger: Logger; - __LEGACY: { - server: APMLegacyServer; - }; }; export type RouteFactoryFn< @@ -107,7 +105,6 @@ export interface ServerAPI { context: { config$: Observable; logger: Logger; - __LEGACY: { server: Server }; } ) => void; } diff --git a/x-pack/plugins/apm/server/saved_objects/apm_indices.ts b/x-pack/plugins/apm/server/saved_objects/apm_indices.ts new file mode 100644 index 0000000000000..c641f4546aae7 --- /dev/null +++ b/x-pack/plugins/apm/server/saved_objects/apm_indices.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { SavedObjectsType } from 'src/core/server'; + +export const apmIndices: SavedObjectsType = { + name: 'apm-indices', + hidden: false, + namespaceType: 'agnostic', + mappings: { + properties: { + 'apm_oss.sourcemapIndices': { + type: 'keyword' + }, + 'apm_oss.errorIndices': { + type: 'keyword' + }, + 'apm_oss.onboardingIndices': { + type: 'keyword' + }, + 'apm_oss.spanIndices': { + type: 'keyword' + }, + 'apm_oss.transactionIndices': { + type: 'keyword' + }, + 'apm_oss.metricsIndices': { + type: 'keyword' + } + } + } +}; diff --git a/x-pack/plugins/apm/server/saved_objects/apm_telemetry.ts b/x-pack/plugins/apm/server/saved_objects/apm_telemetry.ts new file mode 100644 index 0000000000000..f711e85076e14 --- /dev/null +++ b/x-pack/plugins/apm/server/saved_objects/apm_telemetry.ts @@ -0,0 +1,921 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { SavedObjectsType } from 'src/core/server'; + +export const apmTelemetry: SavedObjectsType = { + name: 'apm-telemetry', + hidden: false, + namespaceType: 'agnostic', + mappings: { + properties: { + agents: { + properties: { + dotnet: { + properties: { + agent: { + properties: { + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + service: { + properties: { + framework: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + language: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + runtime: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + } + } + } + } + }, + go: { + properties: { + agent: { + properties: { + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + service: { + properties: { + framework: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + language: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + runtime: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + } + } + } + } + }, + java: { + properties: { + agent: { + properties: { + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + service: { + properties: { + framework: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + language: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + runtime: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + } + } + } + } + }, + 'js-base': { + properties: { + agent: { + properties: { + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + service: { + properties: { + framework: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + language: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + runtime: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + } + } + } + } + }, + nodejs: { + properties: { + agent: { + properties: { + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + service: { + properties: { + framework: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + language: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + runtime: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + } + } + } + } + }, + python: { + properties: { + agent: { + properties: { + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + service: { + properties: { + framework: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + language: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + runtime: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + } + } + } + } + }, + ruby: { + properties: { + agent: { + properties: { + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + service: { + properties: { + framework: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + language: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + runtime: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + } + } + } + } + }, + 'rum-js': { + properties: { + agent: { + properties: { + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + service: { + properties: { + framework: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + language: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + }, + runtime: { + properties: { + composite: { + type: 'keyword', + ignore_above: 1024 + }, + name: { + type: 'keyword', + ignore_above: 1024 + }, + version: { + type: 'keyword', + ignore_above: 1024 + } + } + } + } + } + } + } + } + }, + counts: { + properties: { + agent_configuration: { + properties: { + all: { + type: 'long' + } + } + }, + error: { + properties: { + '1d': { + type: 'long' + }, + all: { + type: 'long' + } + } + }, + max_error_groups_per_service: { + properties: { + '1d': { + type: 'long' + } + } + }, + max_transaction_groups_per_service: { + properties: { + '1d': { + type: 'long' + } + } + }, + metric: { + properties: { + '1d': { + type: 'long' + }, + all: { + type: 'long' + } + } + }, + onboarding: { + properties: { + '1d': { + type: 'long' + }, + all: { + type: 'long' + } + } + }, + services: { + properties: { + '1d': { + type: 'long' + } + } + }, + sourcemap: { + properties: { + '1d': { + type: 'long' + }, + all: { + type: 'long' + } + } + }, + span: { + properties: { + '1d': { + type: 'long' + }, + all: { + type: 'long' + } + } + }, + traces: { + properties: { + '1d': { + type: 'long' + } + } + }, + transaction: { + properties: { + '1d': { + type: 'long' + }, + all: { + type: 'long' + } + } + } + } + }, + cardinality: { + properties: { + user_agent: { + properties: { + original: { + properties: { + all_agents: { + properties: { + '1d': { + type: 'long' + } + } + }, + rum: { + properties: { + '1d': { + type: 'long' + } + } + } + } + } + } + }, + transaction: { + properties: { + name: { + properties: { + all_agents: { + properties: { + '1d': { + type: 'long' + } + } + }, + rum: { + properties: { + '1d': { + type: 'long' + } + } + } + } + } + } + } + } + }, + has_any_services: { + type: 'boolean' + }, + indices: { + properties: { + all: { + properties: { + total: { + properties: { + docs: { + properties: { + count: { + type: 'long' + } + } + }, + store: { + properties: { + size_in_bytes: { + type: 'long' + } + } + } + } + } + } + }, + shards: { + properties: { + total: { + type: 'long' + } + } + } + } + }, + integrations: { + properties: { + ml: { + properties: { + all_jobs_count: { + type: 'long' + } + } + } + } + }, + retainment: { + properties: { + error: { + properties: { + ms: { + type: 'long' + } + } + }, + metric: { + properties: { + ms: { + type: 'long' + } + } + }, + onboarding: { + properties: { + ms: { + type: 'long' + } + } + }, + span: { + properties: { + ms: { + type: 'long' + } + } + }, + transaction: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + services_per_agent: { + properties: { + dotnet: { + type: 'long', + null_value: 0 + }, + go: { + type: 'long', + null_value: 0 + }, + java: { + type: 'long', + null_value: 0 + }, + 'js-base': { + type: 'long', + null_value: 0 + }, + nodejs: { + type: 'long', + null_value: 0 + }, + python: { + type: 'long', + null_value: 0 + }, + ruby: { + type: 'long', + null_value: 0 + }, + 'rum-js': { + type: 'long', + null_value: 0 + } + } + }, + tasks: { + properties: { + agent_configuration: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + agents: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + cardinality: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + groupings: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + indices_stats: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + integrations: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + processor_events: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + services: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + }, + versions: { + properties: { + took: { + properties: { + ms: { + type: 'long' + } + } + } + } + } + } + }, + version: { + properties: { + apm_server: { + properties: { + major: { + type: 'long' + }, + minor: { + type: 'long' + }, + patch: { + type: 'long' + } + } + } + } + } + } as SavedObjectsType['mappings']['properties'] + } +}; diff --git a/x-pack/plugins/apm/server/saved_objects/index.ts b/x-pack/plugins/apm/server/saved_objects/index.ts new file mode 100644 index 0000000000000..30c557c526356 --- /dev/null +++ b/x-pack/plugins/apm/server/saved_objects/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 { apmIndices } from './apm_indices'; +export { apmTelemetry } from './apm_telemetry'; diff --git a/x-pack/plugins/apm/typings/common.d.ts b/x-pack/plugins/apm/typings/common.d.ts index bdd2c75f161e9..eeeb85cd1e7c3 100644 --- a/x-pack/plugins/apm/typings/common.d.ts +++ b/x-pack/plugins/apm/typings/common.d.ts @@ -4,12 +4,10 @@ * you may not use this file except in compliance with the Elastic License. */ -import '../../../legacy/plugins/infra/types/rison_node'; -import '../../../legacy/plugins/infra/types/eui'; +import '../../../typings/rison_node'; +import '../../infra/types/eui'; // EUIBasicTable -import '../../../legacy/plugins/reporting/public/components/report_listing'; -// .svg -import '../../../legacy/plugins/canvas/types/webpack'; +import '../../reporting/public/components/report_listing'; // Allow unknown properties in an object export type AllowUnknownProperties = T extends Array diff --git a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx index 206e9821190fb..a8597b7073c95 100644 --- a/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_entry_flyout/log_entry_actions_menu.tsx @@ -9,7 +9,7 @@ import { EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel, EuiPopover } f import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo } from 'react'; import { useVisibilityState } from '../../../utils/use_visibility_state'; -import { getTraceUrl } from '../../../../../../legacy/plugins/apm/public/components/shared/Links/apm/ExternalLinks'; +import { getTraceUrl } from '../../../../../apm/public'; import { LogEntriesItem } from '../../../../common/http_api'; import { useLinkProps, LinkDescriptor } from '../../../hooks/use_link_props'; import { decodeOrThrow } from '../../../../common/runtime_types'; diff --git a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts index 038fd457fb6c7..4bbbf8dcdee03 100644 --- a/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts +++ b/x-pack/plugins/infra/server/lib/adapters/framework/adapter_types.ts @@ -11,7 +11,7 @@ import { RouteMethod, RouteConfig } from '../../../../../../../src/core/server'; import { PluginSetupContract as FeaturesPluginSetup } from '../../../../../../plugins/features/server'; import { SpacesPluginSetup } from '../../../../../../plugins/spaces/server'; import { VisTypeTimeseriesSetup } from '../../../../../../../src/plugins/vis_type_timeseries/server'; -import { APMPluginContract } from '../../../../../../plugins/apm/server'; +import { APMPluginSetup } from '../../../../../../plugins/apm/server'; import { HomeServerPluginSetup } from '../../../../../../../src/plugins/home/server'; import { PluginSetupContract as AlertingPluginContract } from '../../../../../../plugins/alerting/server'; @@ -22,7 +22,7 @@ export interface InfraServerPluginDeps { usageCollection: UsageCollectionSetup; visTypeTimeseries: VisTypeTimeseriesSetup; features: FeaturesPluginSetup; - apm: APMPluginContract; + apm: APMPluginSetup; alerting: AlertingPluginContract; } diff --git a/x-pack/plugins/siem/scripts/optimize_tsconfig/README.md b/x-pack/plugins/siem/scripts/optimize_tsconfig/README.md index 2b402367c1db3..fbcd3329312aa 100644 --- a/x-pack/plugins/siem/scripts/optimize_tsconfig/README.md +++ b/x-pack/plugins/siem/scripts/optimize_tsconfig/README.md @@ -1,5 +1,5 @@ Hard forked from here: -x-pack/legacy/plugins/apm/scripts/optimize-tsconfig.js +x-pack/plugins/apm/scripts/optimize-tsconfig.js #### Optimizing TypeScript diff --git a/x-pack/plugins/siem/server/utils/build_query/calculate_timeseries_interval.ts b/x-pack/plugins/siem/server/utils/build_query/calculate_timeseries_interval.ts index 5b667f461fc60..78aadf75e54c3 100644 --- a/x-pack/plugins/siem/server/utils/build_query/calculate_timeseries_interval.ts +++ b/x-pack/plugins/siem/server/utils/build_query/calculate_timeseries_interval.ts @@ -5,7 +5,7 @@ */ /* ** Applying the same logic as: - ** x-pack/legacy/plugins/apm/server/lib/helpers/get_bucket_size/calculate_auto.js + ** x-pack/plugins/apm/server/lib/helpers/get_bucket_size/calculate_auto.js */ import moment from 'moment'; import { get } from 'lodash/fp'; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 4cd152f2d297d..28e290c90687b 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -4184,7 +4184,6 @@ "xpack.apm.alertTypes.errorRate": "エラー率", "xpack.apm.alertTypes.transactionDuration": "トランザクション期間", "xpack.apm.apmDescription": "アプリケーション内から自動的に詳細なパフォーマンスメトリックやエラーを集めます。", - "xpack.apm.apmForESDescription": "Elastic Stack 用の APM", "xpack.apm.applyFilter": "{title} フィルターを適用", "xpack.apm.applyOptions": "オプションを適用", "xpack.apm.breadcrumb.errorsTitle": "エラー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 619ea0646eb44..321fd533aab6d 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -4185,7 +4185,6 @@ "xpack.apm.alertTypes.errorRate": "错误率", "xpack.apm.alertTypes.transactionDuration": "事务持续时间", "xpack.apm.apmDescription": "自动从您的应用程序内收集深入全面的性能指标和错误。", - "xpack.apm.apmForESDescription": "Elastic Stack 的 APM", "xpack.apm.applyFilter": "应用 {title} 筛选", "xpack.apm.applyOptions": "应用选项", "xpack.apm.breadcrumb.errorsTitle": "错误", diff --git a/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js index 936eae04ffa64..282cf1311a7a9 100644 --- a/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestion.js @@ -14,7 +14,8 @@ import { units, fontSizes, unit, -} from '../../../../../../../legacy/plugins/apm/public/style/variables'; + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../../apm/public/style/variables'; import { tint } from 'polished'; import theme from '@elastic/eui/dist/eui_theme_light.json'; diff --git a/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js index ac6832050b9d3..0fdf8c3400562 100644 --- a/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js +++ b/x-pack/plugins/uptime/public/components/overview/kuery_bar/typeahead/suggestions.js @@ -9,7 +9,8 @@ import PropTypes from 'prop-types'; import styled from 'styled-components'; import { isEmpty } from 'lodash'; import Suggestion from './suggestion'; -import { units, px, unit } from '../../../../../../../legacy/plugins/apm/public/style/variables'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { units, px, unit } from '../../../../../../apm/public/style/variables'; import { tint } from 'polished'; import theme from '@elastic/eui/dist/eui_theme_light.json'; diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index a540c7e3c9786..81b29732377da 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -12,7 +12,7 @@ "exclude": [ "test/**/*", "plugins/siem/cypress/**/*", - "legacy/plugins/apm/e2e/cypress/**/*", + "plugins/apm/e2e/cypress/**/*", "**/typespec_tests.ts" ], "compilerOptions": { From 47b8ba5d5b80e51cfe7263ef60390463a25a1673 Mon Sep 17 00:00:00 2001 From: Christos Nasikas Date: Fri, 1 May 2020 00:20:00 +0300 Subject: [PATCH 05/10] [SIEM][CASE] Refactor Connectors - Jira Connector (#63450) --- x-pack/plugins/actions/README.md | 60 +- .../server/builtin_action_types/case/api.ts | 93 ++ .../{servicenow => case}/constants.ts | 1 - .../builtin_action_types/case/schema.ts | 98 ++ .../case/transformers.test.ts | 131 +++ .../builtin_action_types/case/transformers.ts | 29 + .../builtin_action_types/case/translations.ts | 55 ++ .../server/builtin_action_types/case/types.ts | 161 ++++ .../helpers.test.ts => case/utils.test.ts} | 319 +++++-- .../server/builtin_action_types/case/utils.ts | 249 +++++ .../builtin_action_types/case/validators.ts | 35 + .../server/builtin_action_types/index.ts | 6 +- .../builtin_action_types/jira/api.test.ts | 517 +++++++++++ .../server/builtin_action_types/jira/api.ts | 7 + .../builtin_action_types/jira/config.ts | 13 + .../server/builtin_action_types/jira/index.ts | 24 + .../server/builtin_action_types/jira/mocks.ts | 124 +++ .../builtin_action_types/jira/schema.ts | 22 + .../builtin_action_types/jira/service.test.ts | 297 ++++++ .../builtin_action_types/jira/service.ts | 156 ++++ .../builtin_action_types/jira/translations.ts | 11 + .../server/builtin_action_types/jira/types.ts | 32 + .../builtin_action_types/jira/validators.ts | 13 + .../servicenow/action_handlers.test.ts | 850 ------------------ .../servicenow/action_handlers.ts | 129 --- .../servicenow/api.test.ts | 523 +++++++++++ .../builtin_action_types/servicenow/api.ts | 7 + .../builtin_action_types/servicenow/config.ts | 13 + .../servicenow/helpers.ts | 125 --- .../servicenow/index.test.ts | 268 ------ .../builtin_action_types/servicenow/index.ts | 124 +-- .../servicenow/lib/constants.ts | 13 - .../servicenow/lib/index.test.ts | 334 ------- .../servicenow/lib/index.ts | 186 ---- .../servicenow/lib/types.ts | 32 - .../builtin_action_types/servicenow/mock.ts | 115 --- .../builtin_action_types/servicenow/mocks.ts | 117 +++ .../builtin_action_types/servicenow/schema.ts | 70 -- .../servicenow/service.test.ts | 255 ++++++ .../servicenow/service.ts | 138 +++ .../servicenow/transformers.ts | 43 - .../servicenow/translations.ts | 73 +- .../builtin_action_types/servicenow/types.ts | 102 +-- .../servicenow/validators.ts | 13 + x-pack/plugins/case/common/api/cases/case.ts | 41 +- x-pack/plugins/case/common/constants.ts | 2 + .../api/cases/configure/get_connectors.ts | 11 +- .../siem/public/containers/case/api.test.tsx | 4 +- .../siem/public/containers/case/api.ts | 4 +- .../siem/public/containers/case/mock.ts | 7 +- .../case/use_post_push_to_service.test.tsx | 4 +- .../case/use_post_push_to_service.tsx | 6 +- .../components/connector_flyout/index.tsx | 148 +++ .../siem/public/lib/connectors/config.ts | 16 +- .../siem/public/lib/connectors/index.ts | 1 + .../siem/public/lib/connectors/jira/config.ts | 20 + .../public/lib/connectors/jira/flyout.tsx | 110 +++ .../siem/public/lib/connectors/jira/index.tsx | 54 ++ .../{logos/servicenow.svg => jira/logo.svg} | 0 .../lib/connectors/jira/translations.ts | 28 + .../siem/public/lib/connectors/jira/types.ts | 18 + .../siem/public/lib/connectors/servicenow.tsx | 246 ----- .../lib/connectors/servicenow/config.ts | 20 + .../lib/connectors/servicenow/flyout.tsx | 83 ++ .../lib/connectors/servicenow/index.tsx | 48 + .../public/lib/connectors/servicenow/logo.svg | 5 + .../lib/connectors/servicenow/translations.ts | 23 + .../public/lib/connectors/servicenow/types.ts | 18 + .../public/lib/connectors/translations.ts | 65 +- .../siem/public/lib/connectors/types.ts | 44 +- .../siem/public/lib/connectors/utils.ts | 71 ++ .../configure_cases/connectors_dropdown.tsx | 4 +- .../components/configure_cases/index.test.tsx | 10 + .../case/components/configure_cases/index.tsx | 13 +- x-pack/plugins/siem/public/plugin.tsx | 3 +- .../translations/translations/ja-JP.json | 18 - .../translations/translations/zh-CN.json | 18 - .../alerting_api_integration/common/config.ts | 1 + .../plugins/actions_simulators/index.ts | 9 +- .../actions_simulators/jira_simulation.ts | 101 +++ .../servicenow_simulation.ts | 8 +- .../actions/builtin_action_types/jira.ts | 549 +++++++++++ .../builtin_action_types/servicenow.ts | 750 +++++++++------- .../tests/actions/index.ts | 1 + 84 files changed, 5330 insertions(+), 3235 deletions(-) create mode 100644 x-pack/plugins/actions/server/builtin_action_types/case/api.ts rename x-pack/plugins/actions/server/builtin_action_types/{servicenow => case}/constants.ts (87%) create mode 100644 x-pack/plugins/actions/server/builtin_action_types/case/schema.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/case/transformers.test.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/case/transformers.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/case/translations.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/case/types.ts rename x-pack/plugins/actions/server/builtin_action_types/{servicenow/helpers.test.ts => case/utils.test.ts} (56%) create mode 100644 x-pack/plugins/actions/server/builtin_action_types/case/utils.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/case/validators.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/api.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/config.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/index.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/service.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/translations.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/types.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/jira/validators.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.test.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/config.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/constants.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.test.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/types.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/mock.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts delete mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/transformers.ts create mode 100644 x-pack/plugins/actions/server/builtin_action_types/servicenow/validators.ts create mode 100644 x-pack/plugins/siem/public/lib/connectors/components/connector_flyout/index.tsx create mode 100644 x-pack/plugins/siem/public/lib/connectors/jira/config.ts create mode 100644 x-pack/plugins/siem/public/lib/connectors/jira/flyout.tsx create mode 100644 x-pack/plugins/siem/public/lib/connectors/jira/index.tsx rename x-pack/plugins/siem/public/lib/connectors/{logos/servicenow.svg => jira/logo.svg} (100%) mode change 100755 => 100644 create mode 100644 x-pack/plugins/siem/public/lib/connectors/jira/translations.ts create mode 100644 x-pack/plugins/siem/public/lib/connectors/jira/types.ts delete mode 100644 x-pack/plugins/siem/public/lib/connectors/servicenow.tsx create mode 100644 x-pack/plugins/siem/public/lib/connectors/servicenow/config.ts create mode 100644 x-pack/plugins/siem/public/lib/connectors/servicenow/flyout.tsx create mode 100644 x-pack/plugins/siem/public/lib/connectors/servicenow/index.tsx create mode 100644 x-pack/plugins/siem/public/lib/connectors/servicenow/logo.svg create mode 100644 x-pack/plugins/siem/public/lib/connectors/servicenow/translations.ts create mode 100644 x-pack/plugins/siem/public/lib/connectors/servicenow/types.ts create mode 100644 x-pack/plugins/siem/public/lib/connectors/utils.ts create mode 100644 x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/jira_simulation.ts create mode 100644 x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts diff --git a/x-pack/plugins/actions/README.md b/x-pack/plugins/actions/README.md index decd170ca5dd6..4c8cc3aa503e6 100644 --- a/x-pack/plugins/actions/README.md +++ b/x-pack/plugins/actions/README.md @@ -28,7 +28,7 @@ Table of Contents - [RESTful API](#restful-api) - [`POST /api/action`: Create action](#post-apiaction-create-action) - [`DELETE /api/action/{id}`: Delete action](#delete-apiactionid-delete-action) - - [`GET /api/action/_getAll`: Get all actions](#get-apiaction-get-all-actions) + - [`GET /api/action/_getAll`: Get all actions](#get-apiactiongetall-get-all-actions) - [`GET /api/action/{id}`: Get action](#get-apiactionid-get-action) - [`GET /api/action/types`: List action types](#get-apiactiontypes-list-action-types) - [`PUT /api/action/{id}`: Update action](#put-apiactionid-update-action) @@ -64,6 +64,12 @@ Table of Contents - [`config`](#config-6) - [`secrets`](#secrets-6) - [`params`](#params-6) + - [`subActionParams (pushToService)`](#subactionparams-pushtoservice) + - [Jira](#jira) + - [`config`](#config-7) + - [`secrets`](#secrets-7) + - [`params`](#params-7) + - [`subActionParams (pushToService)`](#subactionparams-pushtoservice-1) - [Command Line Utility](#command-line-utility) ## Terminology @@ -143,8 +149,8 @@ This is the primary function for an action type. Whenever the action needs to ex | actionId | The action saved object id that the action type is executing for. | | config | The decrypted configuration given to an action. This comes from the action saved object that is partially or fully encrypted within the data store. If you would like to validate the config before being passed to the executor, define `validate.config` within the action type. | | params | Parameters for the execution. These will be given at execution time by either an alert or manually provided when calling the plugin provided execute function. | -| services.callCluster(path, opts) | Use this to do Elasticsearch queries on the cluster Kibana connects to. This function is the same as any other `callCluster` in Kibana but runs in the context of the user who is calling the action when security is enabled.| -| services.getScopedCallCluster | This function scopes an instance of CallCluster by returning a `callCluster(path, opts)` function that runs in the context of the user who is calling the action when security is enabled. This must only be called with instances of CallCluster provided by core.| +| services.callCluster(path, opts) | Use this to do Elasticsearch queries on the cluster Kibana connects to. This function is the same as any other `callCluster` in Kibana but runs in the context of the user who is calling the action when security is enabled. | +| services.getScopedCallCluster | This function scopes an instance of CallCluster by returning a `callCluster(path, opts)` function that runs in the context of the user who is calling the action when security is enabled. This must only be called with instances of CallCluster provided by core. | | services.savedObjectsClient | This is an instance of the saved objects client. This provides the ability to do CRUD on any saved objects within the same space the alert lives in.

The scope of the saved objects client is tied to the user in context calling the execute API or the API key provided to the execute plugin function (only when security isenabled). | | services.log(tags, [data], [timestamp]) | Use this to create server logs. (This is the same function as server.log) | @@ -483,13 +489,59 @@ The ServiceNow action uses the [V2 Table API](https://developer.servicenow.com/a ### `params` +| Property | Description | Type | +| --------------- | ------------------------------------------------------------------------------------ | ------ | +| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string | +| subActionParams | The parameters of the sub action | object | + +#### `subActionParams (pushToService)` + | Property | Description | Type | | ----------- | -------------------------------------------------------------------------------------------------------------------------- | --------------------- | | caseId | The case id | string | | title | The title of the case | string _(optional)_ | | description | The description of the case | string _(optional)_ | | comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | -| incidentID | The id of the incident in ServiceNow . If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | +| externalId | The id of the incident in ServiceNow . If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | + +--- + +## Jira + +ID: `.jira` + +The Jira action uses the [V2 API](https://developer.atlassian.com/cloud/jira/platform/rest/v2/) to create and update Jira incidents. + +### `config` + +| Property | Description | Type | +| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ | +| apiUrl | ServiceNow instance URL. | string | +| casesConfiguration | Case configuration object. The object should contain an attribute called `mapping`. A `mapping` is an array of objects. Each mapping object should be of the form `{ source: string, target: string, actionType: string }`. `source` is the Case field. `target` is the Jira field where `source` will be mapped to. `actionType` can be one of `nothing`, `overwrite` or `append`. For example the `{ source: 'title', target: 'summary', actionType: 'overwrite' }` record, inside mapping array, means that the title of a case will be mapped to the short description of an incident in ServiceNow and will be overwrite on each update. | object | + +### `secrets` + +| Property | Description | Type | +| -------- | --------------------------------------- | ------ | +| email | email for HTTP Basic authentication | string | +| apiToken | API token for HTTP Basic authentication | string | + +### `params` + +| Property | Description | Type | +| --------------- | ------------------------------------------------------------------------------------ | ------ | +| subAction | The sub action to perform. It can be `pushToService`, `handshake`, and `getIncident` | string | +| subActionParams | The parameters of the sub action | object | + +#### `subActionParams (pushToService)` + +| Property | Description | Type | +| ----------- | ------------------------------------------------------------------------------------------------------------------- | --------------------- | +| caseId | The case id | string | +| title | The title of the case | string _(optional)_ | +| description | The description of the case | string _(optional)_ | +| comments | The comments of the case. A comment is of the form `{ commentId: string, version: string, comment: string }` | object[] _(optional)_ | +| externalId | The id of the incident in Jira. If presented the incident will be update. Otherwise a new incident will be created. | string _(optional)_ | # Command Line Utility diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/api.ts b/x-pack/plugins/actions/server/builtin_action_types/case/api.ts new file mode 100644 index 0000000000000..6dc8a9cc9af6a --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/case/api.ts @@ -0,0 +1,93 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + ExternalServiceApi, + ExternalServiceParams, + PushToServiceResponse, + GetIncidentApiHandlerArgs, + HandshakeApiHandlerArgs, + PushToServiceApiHandlerArgs, +} from './types'; +import { prepareFieldsForTransformation, transformFields, transformComments } from './utils'; + +const handshakeHandler = async ({ + externalService, + mapping, + params, +}: HandshakeApiHandlerArgs) => {}; +const getIncidentHandler = async ({ + externalService, + mapping, + params, +}: GetIncidentApiHandlerArgs) => {}; + +const pushToServiceHandler = async ({ + externalService, + mapping, + params, +}: PushToServiceApiHandlerArgs): Promise => { + const { externalId, comments } = params; + const updateIncident = externalId ? true : false; + const defaultPipes = updateIncident ? ['informationUpdated'] : ['informationCreated']; + let currentIncident: ExternalServiceParams | undefined; + let res: PushToServiceResponse; + + if (externalId) { + currentIncident = await externalService.getIncident(externalId); + } + + const fields = prepareFieldsForTransformation({ + params, + mapping, + defaultPipes, + }); + + const incident = transformFields({ + params, + fields, + currentIncident, + }); + + if (updateIncident) { + res = await externalService.updateIncident({ incidentId: externalId, incident }); + } else { + res = await externalService.createIncident({ incident }); + } + + if ( + comments && + Array.isArray(comments) && + comments.length > 0 && + mapping.get('comments')?.actionType !== 'nothing' + ) { + const commentsTransformed = transformComments(comments, ['informationAdded']); + + res.comments = []; + for (const currentComment of commentsTransformed) { + const comment = await externalService.createComment({ + incidentId: res.id, + comment: currentComment, + field: mapping.get('comments')?.target ?? 'comments', + }); + res.comments = [ + ...(res.comments ?? []), + { + commentId: comment.commentId, + pushedDate: comment.pushedDate, + }, + ]; + } + } + + return res; +}; + +export const api: ExternalServiceApi = { + handshake: handshakeHandler, + pushToService: pushToServiceHandler, + getIncident: getIncidentHandler, +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/constants.ts b/x-pack/plugins/actions/server/builtin_action_types/case/constants.ts similarity index 87% rename from x-pack/plugins/actions/server/builtin_action_types/servicenow/constants.ts rename to x-pack/plugins/actions/server/builtin_action_types/case/constants.ts index a0ffd859e14ca..1f2bc7f5e8e53 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/constants.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/case/constants.ts @@ -4,5 +4,4 @@ * you may not use this file except in compliance with the Elastic License. */ -export const ACTION_TYPE_ID = '.servicenow'; export const SUPPORTED_SOURCE_FIELDS = ['title', 'comments', 'description']; diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/case/schema.ts new file mode 100644 index 0000000000000..33b2ad6d18684 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/case/schema.ts @@ -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. + */ + +import { schema } from '@kbn/config-schema'; + +export const MappingActionType = schema.oneOf([ + schema.literal('nothing'), + schema.literal('overwrite'), + schema.literal('append'), +]); + +export const MapRecordSchema = schema.object({ + source: schema.string(), + target: schema.string(), + actionType: MappingActionType, +}); + +export const CaseConfigurationSchema = schema.object({ + mapping: schema.arrayOf(MapRecordSchema), +}); + +export const ExternalIncidentServiceConfiguration = { + apiUrl: schema.string(), + casesConfiguration: CaseConfigurationSchema, +}; + +export const ExternalIncidentServiceConfigurationSchema = schema.object( + ExternalIncidentServiceConfiguration +); + +export const ExternalIncidentServiceSecretConfiguration = { + password: schema.string(), + username: schema.string(), +}; + +export const ExternalIncidentServiceSecretConfigurationSchema = schema.object( + ExternalIncidentServiceSecretConfiguration +); + +export const UserSchema = schema.object({ + fullName: schema.nullable(schema.string()), + username: schema.nullable(schema.string()), +}); + +const EntityInformation = { + createdAt: schema.string(), + createdBy: UserSchema, + updatedAt: schema.nullable(schema.string()), + updatedBy: schema.nullable(UserSchema), +}; + +export const EntityInformationSchema = schema.object(EntityInformation); + +export const CommentSchema = schema.object({ + commentId: schema.string(), + comment: schema.string(), + ...EntityInformation, +}); + +export const ExecutorSubActionSchema = schema.oneOf([ + schema.literal('getIncident'), + schema.literal('pushToService'), + schema.literal('handshake'), +]); + +export const ExecutorSubActionPushParamsSchema = schema.object({ + caseId: schema.string(), + title: schema.string(), + description: schema.nullable(schema.string()), + comments: schema.nullable(schema.arrayOf(CommentSchema)), + externalId: schema.nullable(schema.string()), + ...EntityInformation, +}); + +export const ExecutorSubActionGetIncidentParamsSchema = schema.object({ + externalId: schema.string(), +}); + +// Reserved for future implementation +export const ExecutorSubActionHandshakeParamsSchema = schema.object({}); + +export const ExecutorParamsSchema = schema.oneOf([ + schema.object({ + subAction: schema.literal('getIncident'), + subActionParams: ExecutorSubActionGetIncidentParamsSchema, + }), + schema.object({ + subAction: schema.literal('handshake'), + subActionParams: ExecutorSubActionHandshakeParamsSchema, + }), + schema.object({ + subAction: schema.literal('pushToService'), + subActionParams: ExecutorSubActionPushParamsSchema, + }), +]); diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/transformers.test.ts b/x-pack/plugins/actions/server/builtin_action_types/case/transformers.test.ts new file mode 100644 index 0000000000000..75dcab65ee9f2 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/case/transformers.test.ts @@ -0,0 +1,131 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { transformers } from './transformers'; + +const { informationCreated, informationUpdated, informationAdded, append } = transformers; + +describe('informationCreated', () => { + test('transforms correctly', () => { + const res = informationCreated({ + value: 'a value', + date: '2020-04-15T08:19:27.400Z', + user: 'elastic', + }); + expect(res).toEqual({ value: 'a value (created at 2020-04-15T08:19:27.400Z by elastic)' }); + }); + + test('transforms correctly without optional fields', () => { + const res = informationCreated({ + value: 'a value', + }); + expect(res).toEqual({ value: 'a value (created at by )' }); + }); + + test('returns correctly rest fields', () => { + const res = informationCreated({ + value: 'a value', + date: '2020-04-15T08:19:27.400Z', + user: 'elastic', + previousValue: 'previous value', + }); + expect(res).toEqual({ + value: 'a value (created at 2020-04-15T08:19:27.400Z by elastic)', + previousValue: 'previous value', + }); + }); +}); + +describe('informationUpdated', () => { + test('transforms correctly', () => { + const res = informationUpdated({ + value: 'a value', + date: '2020-04-15T08:19:27.400Z', + user: 'elastic', + }); + expect(res).toEqual({ value: 'a value (updated at 2020-04-15T08:19:27.400Z by elastic)' }); + }); + + test('transforms correctly without optional fields', () => { + const res = informationUpdated({ + value: 'a value', + }); + expect(res).toEqual({ value: 'a value (updated at by )' }); + }); + + test('returns correctly rest fields', () => { + const res = informationUpdated({ + value: 'a value', + date: '2020-04-15T08:19:27.400Z', + user: 'elastic', + previousValue: 'previous value', + }); + expect(res).toEqual({ + value: 'a value (updated at 2020-04-15T08:19:27.400Z by elastic)', + previousValue: 'previous value', + }); + }); +}); + +describe('informationAdded', () => { + test('transforms correctly', () => { + const res = informationAdded({ + value: 'a value', + date: '2020-04-15T08:19:27.400Z', + user: 'elastic', + }); + expect(res).toEqual({ value: 'a value (added at 2020-04-15T08:19:27.400Z by elastic)' }); + }); + + test('transforms correctly without optional fields', () => { + const res = informationAdded({ + value: 'a value', + }); + expect(res).toEqual({ value: 'a value (added at by )' }); + }); + + test('returns correctly rest fields', () => { + const res = informationAdded({ + value: 'a value', + date: '2020-04-15T08:19:27.400Z', + user: 'elastic', + previousValue: 'previous value', + }); + expect(res).toEqual({ + value: 'a value (added at 2020-04-15T08:19:27.400Z by elastic)', + previousValue: 'previous value', + }); + }); +}); + +describe('append', () => { + test('transforms correctly', () => { + const res = append({ + value: 'a value', + previousValue: 'previous value', + }); + expect(res).toEqual({ value: 'previous value \r\na value' }); + }); + + test('transforms correctly without optional fields', () => { + const res = append({ + value: 'a value', + }); + expect(res).toEqual({ value: 'a value' }); + }); + + test('returns correctly rest fields', () => { + const res = append({ + value: 'a value', + user: 'elastic', + previousValue: 'previous value', + }); + expect(res).toEqual({ + value: 'previous value \r\na value', + user: 'elastic', + }); + }); +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/transformers.ts b/x-pack/plugins/actions/server/builtin_action_types/case/transformers.ts new file mode 100644 index 0000000000000..3dca1fd703430 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/case/transformers.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 { TransformerArgs } from './types'; +import * as i18n from './translations'; + +export type Transformer = (args: TransformerArgs) => TransformerArgs; + +export const transformers: Record = { + informationCreated: ({ value, date, user, ...rest }: TransformerArgs): TransformerArgs => ({ + value: `${value} ${i18n.FIELD_INFORMATION('create', date, user)}`, + ...rest, + }), + informationUpdated: ({ value, date, user, ...rest }: TransformerArgs): TransformerArgs => ({ + value: `${value} ${i18n.FIELD_INFORMATION('update', date, user)}`, + ...rest, + }), + informationAdded: ({ value, date, user, ...rest }: TransformerArgs): TransformerArgs => ({ + value: `${value} ${i18n.FIELD_INFORMATION('add', date, user)}`, + ...rest, + }), + append: ({ value, previousValue, ...rest }: TransformerArgs): TransformerArgs => ({ + value: previousValue ? `${previousValue} \r\n${value}` : `${value}`, + ...rest, + }), +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/translations.ts b/x-pack/plugins/actions/server/builtin_action_types/case/translations.ts new file mode 100644 index 0000000000000..4842728b0e4e7 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/case/translations.ts @@ -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. + */ + +import { i18n } from '@kbn/i18n'; + +export const API_URL_REQUIRED = i18n.translate('xpack.actions.builtin.case.connectorApiNullError', { + defaultMessage: 'connector [apiUrl] is required', +}); + +export const FIELD_INFORMATION = ( + mode: string, + date: string | undefined, + user: string | undefined +) => { + switch (mode) { + case 'create': + return i18n.translate('xpack.actions.builtin.case.common.externalIncidentCreated', { + values: { date, user }, + defaultMessage: '(created at {date} by {user})', + }); + case 'update': + return i18n.translate('xpack.actions.builtin.case.common.externalIncidentUpdated', { + values: { date, user }, + defaultMessage: '(updated at {date} by {user})', + }); + case 'add': + return i18n.translate('xpack.actions.builtin.case.common.externalIncidentAdded', { + values: { date, user }, + defaultMessage: '(added at {date} by {user})', + }); + default: + return i18n.translate('xpack.actions.builtin.case.common.externalIncidentDefault', { + values: { date, user }, + defaultMessage: '(created at {date} by {user})', + }); + } +}; + +export const MAPPING_EMPTY = i18n.translate( + 'xpack.actions.builtin.case.configuration.emptyMapping', + { + defaultMessage: '[casesConfiguration.mapping]: expected non-empty but got empty', + } +); + +export const WHITE_LISTED_ERROR = (message: string) => + i18n.translate('xpack.actions.builtin.case.configuration.apiWhitelistError', { + defaultMessage: 'error configuring connector action: {message}', + values: { + message, + }, + }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/types.ts b/x-pack/plugins/actions/server/builtin_action_types/case/types.ts new file mode 100644 index 0000000000000..459e9d2b03f92 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/case/types.ts @@ -0,0 +1,161 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// This will have to remain `any` until we can extend connectors with generics +// and circular dependencies eliminated. +/* eslint-disable @typescript-eslint/no-explicit-any */ + +import { TypeOf } from '@kbn/config-schema'; + +import { + ExternalIncidentServiceConfigurationSchema, + ExternalIncidentServiceSecretConfigurationSchema, + ExecutorParamsSchema, + CaseConfigurationSchema, + MapRecordSchema, + CommentSchema, + ExecutorSubActionPushParamsSchema, + ExecutorSubActionGetIncidentParamsSchema, + ExecutorSubActionHandshakeParamsSchema, +} from './schema'; + +export interface AnyParams { + [index: string]: string | number | object | undefined | null; +} + +export type ExternalIncidentServiceConfiguration = TypeOf< + typeof ExternalIncidentServiceConfigurationSchema +>; +export type ExternalIncidentServiceSecretConfiguration = TypeOf< + typeof ExternalIncidentServiceSecretConfigurationSchema +>; + +export type ExecutorParams = TypeOf; +export type ExecutorSubActionPushParams = TypeOf; + +export type ExecutorSubActionGetIncidentParams = TypeOf< + typeof ExecutorSubActionGetIncidentParamsSchema +>; + +export type ExecutorSubActionHandshakeParams = TypeOf< + typeof ExecutorSubActionHandshakeParamsSchema +>; + +export type CaseConfiguration = TypeOf; +export type MapRecord = TypeOf; +export type Comment = TypeOf; + +export interface ExternalServiceConfiguration { + id: string; + name: string; +} + +export interface ExternalServiceCredentials { + config: Record; + secrets: Record; +} + +export interface ExternalServiceValidation { + config: (configurationUtilities: any, configObject: any) => void; + secrets: (configurationUtilities: any, secrets: any) => void; +} + +export interface ExternalServiceIncidentResponse { + id: string; + title: string; + url: string; + pushedDate: string; +} + +export interface ExternalServiceCommentResponse { + commentId: string; + pushedDate: string; + externalCommentId?: string; +} + +export interface ExternalServiceParams { + [index: string]: any; +} + +export interface ExternalService { + getIncident: (id: string) => Promise; + createIncident: (params: ExternalServiceParams) => Promise; + updateIncident: (params: ExternalServiceParams) => Promise; + createComment: (params: ExternalServiceParams) => Promise; +} + +export interface PushToServiceApiParams extends ExecutorSubActionPushParams { + externalCase: Record; +} + +export interface ExternalServiceApiHandlerArgs { + externalService: ExternalService; + mapping: Map; +} + +export interface PushToServiceApiHandlerArgs extends ExternalServiceApiHandlerArgs { + params: PushToServiceApiParams; +} + +export interface GetIncidentApiHandlerArgs extends ExternalServiceApiHandlerArgs { + params: ExecutorSubActionGetIncidentParams; +} + +export interface HandshakeApiHandlerArgs extends ExternalServiceApiHandlerArgs { + params: ExecutorSubActionHandshakeParams; +} + +export interface PushToServiceResponse extends ExternalServiceIncidentResponse { + comments?: ExternalServiceCommentResponse[]; +} + +export interface ExternalServiceApi { + handshake: (args: HandshakeApiHandlerArgs) => Promise; + pushToService: (args: PushToServiceApiHandlerArgs) => Promise; + getIncident: (args: GetIncidentApiHandlerArgs) => Promise; +} + +export interface CreateExternalServiceBasicArgs { + api: ExternalServiceApi; + createExternalService: (credentials: ExternalServiceCredentials) => ExternalService; +} + +export interface CreateExternalServiceArgs extends CreateExternalServiceBasicArgs { + config: ExternalServiceConfiguration; + validate: ExternalServiceValidation; + validationSchema: { config: any; secrets: any }; +} + +export interface CreateActionTypeArgs { + configurationUtilities: any; + executor?: any; +} + +export interface PipedField { + key: string; + value: string; + actionType: string; + pipes: string[]; +} + +export interface PrepareFieldsForTransformArgs { + params: PushToServiceApiParams; + mapping: Map; + defaultPipes?: string[]; +} + +export interface TransformFieldsArgs { + params: PushToServiceApiParams; + fields: PipedField[]; + currentIncident?: ExternalServiceParams; +} + +export interface TransformerArgs { + value: string; + date?: string; + user?: string; + previousValue?: string; +} diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.test.ts b/x-pack/plugins/actions/server/builtin_action_types/case/utils.test.ts similarity index 56% rename from x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.test.ts rename to x-pack/plugins/actions/server/builtin_action_types/case/utils.test.ts index cbcefe6364e8f..1e8cc3eda20e5 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.test.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/case/utils.test.ts @@ -4,28 +4,65 @@ * you may not use this file except in compliance with the Elastic License. */ +import axios from 'axios'; + import { normalizeMapping, buildMap, mapParams, - appendField, - appendInformationToField, prepareFieldsForTransformation, transformFields, transformComments, -} from './helpers'; -import { mapping, finalMapping } from './mock'; + addTimeZoneToDate, + throwIfNotAlive, + request, + patch, + getErrorMessage, +} from './utils'; + import { SUPPORTED_SOURCE_FIELDS } from './constants'; -import { MapEntry, Params, Comment } from './types'; +import { Comment, MapRecord, PushToServiceApiParams } from './types'; + +jest.mock('axios'); +const axiosMock = (axios as unknown) as jest.Mock; + +const mapping: MapRecord[] = [ + { source: 'title', target: 'short_description', actionType: 'overwrite' }, + { source: 'description', target: 'description', actionType: 'append' }, + { source: 'comments', target: 'comments', actionType: 'append' }, +]; + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +const finalMapping: Map = new Map(); + +finalMapping.set('title', { + target: 'short_description', + actionType: 'overwrite', +}); -const maliciousMapping: MapEntry[] = [ +finalMapping.set('description', { + target: 'description', + actionType: 'append', +}); + +finalMapping.set('comments', { + target: 'comments', + actionType: 'append', +}); + +finalMapping.set('short_description', { + target: 'title', + actionType: 'overwrite', +}); + +const maliciousMapping: MapRecord[] = [ { source: '__proto__', target: 'short_description', actionType: 'nothing' }, { source: 'description', target: '__proto__', actionType: 'nothing' }, { source: 'comments', target: 'comments', actionType: 'nothing' }, { source: 'unsupportedSource', target: 'comments', actionType: 'nothing' }, ]; -const fullParams: Params = { +const fullParams: PushToServiceApiParams = { caseId: 'd4387ac5-0899-4dc2-bbfa-0dd605c934aa', title: 'a title', description: 'a description', @@ -33,15 +70,14 @@ const fullParams: Params = { createdBy: { fullName: 'Elastic User', username: 'elastic' }, updatedAt: null, updatedBy: null, - incidentId: null, - incident: { + externalId: null, + externalCase: { short_description: 'a title', description: 'a description', }, comments: [ { commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', comment: 'first comment', createdAt: '2020-03-13T08:34:53.450Z', createdBy: { fullName: 'Elastic User', username: 'elastic' }, @@ -50,7 +86,6 @@ const fullParams: Params = { }, { commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', comment: 'second comment', createdAt: '2020-03-13T08:34:53.450Z', createdBy: { fullName: 'Elastic User', username: 'elastic' }, @@ -60,7 +95,7 @@ const fullParams: Params = { ], }; -describe('sanitizeMapping', () => { +describe('normalizeMapping', () => { test('remove malicious fields', () => { const sanitizedMapping = normalizeMapping(SUPPORTED_SOURCE_FIELDS, maliciousMapping); expect(sanitizedMapping.every(m => m.source !== '__proto__' && m.target !== '__proto__')).toBe( @@ -194,7 +229,10 @@ describe('transformFields', () => { params: { ...fullParams, updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { username: 'anotherUser', fullName: 'Another User' }, + updatedBy: { + username: 'anotherUser', + fullName: 'Another User', + }, }, mapping: finalMapping, defaultPipes: ['informationUpdated'], @@ -204,7 +242,10 @@ describe('transformFields', () => { params: { ...fullParams, updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { username: 'anotherUser', fullName: 'Another User' }, + updatedBy: { + username: 'anotherUser', + fullName: 'Another User', + }, }, fields, currentIncident: { @@ -244,7 +285,10 @@ describe('transformFields', () => { }); const res = transformFields({ - params: { ...fullParams, createdBy: { fullName: null, username: 'elastic' } }, + params: { + ...fullParams, + createdBy: { fullName: '', username: 'elastic' }, + }, fields, }); @@ -259,7 +303,10 @@ describe('transformFields', () => { params: { ...fullParams, updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { username: 'anotherUser', fullName: 'Another User' }, + updatedBy: { + username: 'anotherUser', + fullName: 'Another User', + }, }, mapping: finalMapping, defaultPipes: ['informationUpdated'], @@ -269,7 +316,7 @@ describe('transformFields', () => { params: { ...fullParams, updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { username: 'anotherUser', fullName: null }, + updatedBy: { username: 'anotherUser', fullName: '' }, }, fields, }); @@ -281,60 +328,11 @@ describe('transformFields', () => { }); }); -describe('appendField', () => { - test('prefix correctly', () => { - expect('my_prefixmy_value ').toEqual(appendField({ value: 'my_value', prefix: 'my_prefix' })); - }); - - test('suffix correctly', () => { - expect('my_value my_suffix').toEqual(appendField({ value: 'my_value', suffix: 'my_suffix' })); - }); - - test('prefix and suffix correctly', () => { - expect('my_prefixmy_value my_suffix').toEqual( - appendField({ value: 'my_value', prefix: 'my_prefix', suffix: 'my_suffix' }) - ); - }); -}); - -describe('appendInformationToField', () => { - test('creation mode', () => { - const res = appendInformationToField({ - value: 'my value', - user: 'Elastic Test User', - date: '2020-03-13T08:34:53.450Z', - mode: 'create', - }); - expect(res).toEqual('my value (created at 2020-03-13T08:34:53.450Z by Elastic Test User)'); - }); - - test('update mode', () => { - const res = appendInformationToField({ - value: 'my value', - user: 'Elastic Test User', - date: '2020-03-13T08:34:53.450Z', - mode: 'update', - }); - expect(res).toEqual('my value (updated at 2020-03-13T08:34:53.450Z by Elastic Test User)'); - }); - - test('add mode', () => { - const res = appendInformationToField({ - value: 'my value', - user: 'Elastic Test User', - date: '2020-03-13T08:34:53.450Z', - mode: 'add', - }); - expect(res).toEqual('my value (added at 2020-03-13T08:34:53.450Z by Elastic Test User)'); - }); -}); - describe('transformComments', () => { test('transform creation comments', () => { const comments: Comment[] = [ { commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', comment: 'first comment', createdAt: '2020-03-13T08:34:53.450Z', createdBy: { fullName: 'Elastic User', username: 'elastic' }, @@ -342,11 +340,10 @@ describe('transformComments', () => { updatedBy: null, }, ]; - const res = transformComments(comments, fullParams, ['informationCreated']); + const res = transformComments(comments, ['informationCreated']); expect(res).toEqual([ { commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', comment: 'first comment (created at 2020-03-13T08:34:53.450Z by Elastic User)', createdAt: '2020-03-13T08:34:53.450Z', createdBy: { fullName: 'Elastic User', username: 'elastic' }, @@ -360,32 +357,36 @@ describe('transformComments', () => { const comments: Comment[] = [ { commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', comment: 'first comment', createdAt: '2020-03-13T08:34:53.450Z', createdBy: { fullName: 'Elastic User', username: 'elastic' }, updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { fullName: 'Another User', username: 'anotherUser' }, + updatedBy: { + fullName: 'Another User', + username: 'anotherUser', + }, }, ]; - const res = transformComments(comments, fullParams, ['informationUpdated']); + const res = transformComments(comments, ['informationUpdated']); expect(res).toEqual([ { commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', comment: 'first comment (updated at 2020-03-15T08:34:53.450Z by Another User)', createdAt: '2020-03-13T08:34:53.450Z', createdBy: { fullName: 'Elastic User', username: 'elastic' }, updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { fullName: 'Another User', username: 'anotherUser' }, + updatedBy: { + fullName: 'Another User', + username: 'anotherUser', + }, }, ]); }); + test('transform added comments', () => { const comments: Comment[] = [ { commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', comment: 'first comment', createdAt: '2020-03-13T08:34:53.450Z', createdBy: { fullName: 'Elastic User', username: 'elastic' }, @@ -393,11 +394,10 @@ describe('transformComments', () => { updatedBy: null, }, ]; - const res = transformComments(comments, fullParams, ['informationAdded']); + const res = transformComments(comments, ['informationAdded']); expect(res).toEqual([ { commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', comment: 'first comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', createdAt: '2020-03-13T08:34:53.450Z', createdBy: { fullName: 'Elastic User', username: 'elastic' }, @@ -406,4 +406,171 @@ describe('transformComments', () => { }, ]); }); + + test('transform comments without fullname', () => { + const comments: Comment[] = [ + { + commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', + comment: 'first comment', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: '', username: 'elastic' }, + updatedAt: null, + updatedBy: null, + }, + ]; + const res = transformComments(comments, ['informationAdded']); + expect(res).toEqual([ + { + commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', + comment: 'first comment (added at 2020-03-13T08:34:53.450Z by elastic)', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: '', username: 'elastic' }, + updatedAt: null, + updatedBy: null, + }, + ]); + }); + + test('adds update user correctly', () => { + const comments: Comment[] = [ + { + commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', + comment: 'first comment', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic', username: 'elastic' }, + updatedAt: '2020-04-13T08:34:53.450Z', + updatedBy: { fullName: 'Elastic2', username: 'elastic' }, + }, + ]; + const res = transformComments(comments, ['informationAdded']); + expect(res).toEqual([ + { + commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', + comment: 'first comment (added at 2020-04-13T08:34:53.450Z by Elastic2)', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic', username: 'elastic' }, + updatedAt: '2020-04-13T08:34:53.450Z', + updatedBy: { fullName: 'Elastic2', username: 'elastic' }, + }, + ]); + }); + + test('adds update user with empty fullname correctly', () => { + const comments: Comment[] = [ + { + commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', + comment: 'first comment', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic', username: 'elastic' }, + updatedAt: '2020-04-13T08:34:53.450Z', + updatedBy: { fullName: '', username: 'elastic2' }, + }, + ]; + const res = transformComments(comments, ['informationAdded']); + expect(res).toEqual([ + { + commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', + comment: 'first comment (added at 2020-04-13T08:34:53.450Z by elastic2)', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic', username: 'elastic' }, + updatedAt: '2020-04-13T08:34:53.450Z', + updatedBy: { fullName: '', username: 'elastic2' }, + }, + ]); + }); +}); + +describe('addTimeZoneToDate', () => { + test('adds timezone with default', () => { + const date = addTimeZoneToDate('2020-04-14T15:01:55.456Z'); + expect(date).toBe('2020-04-14T15:01:55.456Z GMT'); + }); + + test('adds timezone correctly', () => { + const date = addTimeZoneToDate('2020-04-14T15:01:55.456Z', 'PST'); + expect(date).toBe('2020-04-14T15:01:55.456Z PST'); + }); +}); + +describe('throwIfNotAlive ', () => { + test('throws correctly when status is invalid', async () => { + expect(() => { + throwIfNotAlive(404, 'application/json'); + }).toThrow('Instance is not alive.'); + }); + + test('throws correctly when content is invalid', () => { + expect(() => { + throwIfNotAlive(200, 'application/html'); + }).toThrow('Instance is not alive.'); + }); + + test('do NOT throws with custom validStatusCodes', async () => { + expect(() => { + throwIfNotAlive(404, 'application/json', [404]); + }).not.toThrow('Instance is not alive.'); + }); +}); + +describe('request', () => { + beforeEach(() => { + axiosMock.mockImplementation(() => ({ + status: 200, + headers: { 'content-type': 'application/json' }, + data: { incidentId: '123' }, + })); + }); + + test('it fetch correctly with defaults', async () => { + const res = await request({ axios, url: '/test' }); + + expect(axiosMock).toHaveBeenCalledWith('/test', { method: 'get', data: {} }); + expect(res).toEqual({ + status: 200, + headers: { 'content-type': 'application/json' }, + data: { incidentId: '123' }, + }); + }); + + test('it fetch correctly', async () => { + const res = await request({ axios, url: '/test', method: 'post', data: { id: '123' } }); + + expect(axiosMock).toHaveBeenCalledWith('/test', { method: 'post', data: { id: '123' } }); + expect(res).toEqual({ + status: 200, + headers: { 'content-type': 'application/json' }, + data: { incidentId: '123' }, + }); + }); + + test('it throws correctly', async () => { + axiosMock.mockImplementation(() => ({ + status: 404, + headers: { 'content-type': 'application/json' }, + data: { incidentId: '123' }, + })); + + await expect(request({ axios, url: '/test' })).rejects.toThrow(); + }); +}); + +describe('patch', () => { + beforeEach(() => { + axiosMock.mockImplementation(() => ({ + status: 200, + headers: { 'content-type': 'application/json' }, + })); + }); + + test('it fetch correctly', async () => { + await patch({ axios, url: '/test', data: { id: '123' } }); + expect(axiosMock).toHaveBeenCalledWith('/test', { method: 'patch', data: { id: '123' } }); + }); +}); + +describe('getErrorMessage', () => { + test('it returns the correct error message', () => { + const msg = getErrorMessage('My connector name', 'An error has occurred'); + expect(msg).toBe('[Action][My connector name]: An error has occurred'); + }); }); diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/utils.ts b/x-pack/plugins/actions/server/builtin_action_types/case/utils.ts new file mode 100644 index 0000000000000..7d69b2791f624 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/case/utils.ts @@ -0,0 +1,249 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { curry, flow, get } from 'lodash'; +import { schema } from '@kbn/config-schema'; +import { AxiosInstance, Method, AxiosResponse } from 'axios'; + +import { ActionTypeExecutorOptions, ActionTypeExecutorResult, ActionType } from '../../types'; + +import { ExecutorParamsSchema } from './schema'; + +import { + CreateExternalServiceArgs, + CreateActionTypeArgs, + ExecutorParams, + MapRecord, + AnyParams, + CreateExternalServiceBasicArgs, + PrepareFieldsForTransformArgs, + PipedField, + TransformFieldsArgs, + Comment, + ExecutorSubActionPushParams, +} from './types'; + +import { transformers, Transformer } from './transformers'; + +import { SUPPORTED_SOURCE_FIELDS } from './constants'; + +export const normalizeMapping = (supportedFields: string[], mapping: MapRecord[]): MapRecord[] => { + // Prevent prototype pollution and remove unsupported fields + return mapping.filter( + m => m.source !== '__proto__' && m.target !== '__proto__' && supportedFields.includes(m.source) + ); +}; + +export const buildMap = (mapping: MapRecord[]): Map => { + return normalizeMapping(SUPPORTED_SOURCE_FIELDS, mapping).reduce((fieldsMap, field) => { + const { source, target, actionType } = field; + fieldsMap.set(source, { target, actionType }); + fieldsMap.set(target, { target: source, actionType }); + return fieldsMap; + }, new Map()); +}; + +export const mapParams = ( + params: Partial, + mapping: Map +): AnyParams => { + return Object.keys(params).reduce((prev: AnyParams, curr: string): AnyParams => { + const field = mapping.get(curr); + if (field) { + prev[field.target] = get(params, curr); + } + return prev; + }, {}); +}; + +export const createConnectorExecutor = ({ + api, + createExternalService, +}: CreateExternalServiceBasicArgs) => async ( + execOptions: ActionTypeExecutorOptions +): Promise => { + const { actionId, config, params, secrets } = execOptions; + const { subAction, subActionParams } = params as ExecutorParams; + let data = {}; + + const res: Pick & + Pick = { + status: 'ok', + actionId, + }; + + const externalService = createExternalService({ + config, + secrets, + }); + + if (!api[subAction]) { + throw new Error('[Action][ExternalService] Unsupported subAction type.'); + } + + if (subAction !== 'pushToService') { + throw new Error('[Action][ExternalService] subAction not implemented.'); + } + + if (subAction === 'pushToService') { + const pushToServiceParams = subActionParams as ExecutorSubActionPushParams; + const { comments, externalId, ...restParams } = pushToServiceParams; + + const mapping = buildMap(config.casesConfiguration.mapping); + const externalCase = mapParams(restParams, mapping); + + data = await api.pushToService({ + externalService, + mapping, + params: { ...pushToServiceParams, externalCase }, + }); + } + + return { + ...res, + data, + }; +}; + +export const createConnector = ({ + api, + config, + validate, + createExternalService, + validationSchema, +}: CreateExternalServiceArgs) => { + return ({ + configurationUtilities, + executor = createConnectorExecutor({ api, createExternalService }), + }: CreateActionTypeArgs): ActionType => ({ + id: config.id, + name: config.name, + minimumLicenseRequired: 'platinum', + validate: { + config: schema.object(validationSchema.config, { + validate: curry(validate.config)(configurationUtilities), + }), + secrets: schema.object(validationSchema.secrets, { + validate: curry(validate.secrets)(configurationUtilities), + }), + params: ExecutorParamsSchema, + }, + executor, + }); +}; + +export const throwIfNotAlive = ( + status: number, + contentType: string, + validStatusCodes: number[] = [200, 201, 204] +) => { + if (!validStatusCodes.includes(status) || !contentType.includes('application/json')) { + throw new Error('Instance is not alive.'); + } +}; + +export const request = async ({ + axios, + url, + method = 'get', + data, +}: { + axios: AxiosInstance; + url: string; + method?: Method; + data?: T; +}): Promise => { + const res = await axios(url, { method, data: data ?? {} }); + throwIfNotAlive(res.status, res.headers['content-type']); + return res; +}; + +export const patch = async ({ + axios, + url, + data, +}: { + axios: AxiosInstance; + url: string; + data: T; +}): Promise => { + return request({ + axios, + url, + method: 'patch', + data, + }); +}; + +export const addTimeZoneToDate = (date: string, timezone = 'GMT'): string => { + return `${date} ${timezone}`; +}; + +export const prepareFieldsForTransformation = ({ + params, + mapping, + defaultPipes = ['informationCreated'], +}: PrepareFieldsForTransformArgs): PipedField[] => { + return Object.keys(params.externalCase) + .filter(p => mapping.get(p)?.actionType != null && mapping.get(p)?.actionType !== 'nothing') + .map(p => { + const actionType = mapping.get(p)?.actionType ?? 'nothing'; + return { + key: p, + value: params.externalCase[p], + actionType, + pipes: actionType === 'append' ? [...defaultPipes, 'append'] : defaultPipes, + }; + }); +}; + +export const transformFields = ({ + params, + fields, + currentIncident, +}: TransformFieldsArgs): Record => { + return fields.reduce((prev, cur) => { + const transform = flow(...cur.pipes.map(p => transformers[p])); + return { + ...prev, + [cur.key]: transform({ + value: cur.value, + date: params.updatedAt ?? params.createdAt, + user: + (params.updatedBy != null + ? params.updatedBy.fullName + ? params.updatedBy.fullName + : params.updatedBy.username + : params.createdBy.fullName + ? params.createdBy.fullName + : params.createdBy.username) ?? '', + previousValue: currentIncident ? currentIncident[cur.key] : '', + }).value, + }; + }, {}); +}; + +export const transformComments = (comments: Comment[], pipes: string[]): Comment[] => { + return comments.map(c => ({ + ...c, + comment: flow(...pipes.map(p => transformers[p]))({ + value: c.comment, + date: c.updatedAt ?? c.createdAt, + user: + (c.updatedBy != null + ? c.updatedBy.fullName + ? c.updatedBy.fullName + : c.updatedBy.username + : c.createdBy.fullName + ? c.createdBy.fullName + : c.createdBy.username) ?? '', + }).value, + })); +}; + +export const getErrorMessage = (connector: string, msg: string) => { + return `[Action][${connector}]: ${msg}`; +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/case/validators.ts b/x-pack/plugins/actions/server/builtin_action_types/case/validators.ts new file mode 100644 index 0000000000000..80e301e5be082 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/case/validators.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 { isEmpty } from 'lodash'; + +import { ActionsConfigurationUtilities } from '../../actions_config'; +import { + ExternalIncidentServiceConfiguration, + ExternalIncidentServiceSecretConfiguration, +} from './types'; + +import * as i18n from './translations'; + +export const validateCommonConfig = ( + configurationUtilities: ActionsConfigurationUtilities, + configObject: ExternalIncidentServiceConfiguration +) => { + try { + if (isEmpty(configObject.casesConfiguration.mapping)) { + return i18n.MAPPING_EMPTY; + } + + configurationUtilities.ensureWhitelistedUri(configObject.apiUrl); + } catch (whitelistError) { + return i18n.WHITE_LISTED_ERROR(whitelistError.message); + } +}; + +export const validateCommonSecrets = ( + configurationUtilities: ActionsConfigurationUtilities, + secrets: ExternalIncidentServiceSecretConfiguration +) => {}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/index.ts b/x-pack/plugins/actions/server/builtin_action_types/index.ts index a92a279d08439..6ba4d7cfc7de0 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/index.ts @@ -12,9 +12,10 @@ import { getActionType as getEmailActionType } from './email'; import { getActionType as getIndexActionType } from './es_index'; import { getActionType as getPagerDutyActionType } from './pagerduty'; import { getActionType as getServerLogActionType } from './server_log'; -import { getActionType as getServiceNowActionType } from './servicenow'; import { getActionType as getSlackActionType } from './slack'; import { getActionType as getWebhookActionType } from './webhook'; +import { getActionType as getServiceNowActionType } from './servicenow'; +import { getActionType as getJiraActionType } from './jira'; export function registerBuiltInActionTypes({ actionsConfigUtils: configurationUtilities, @@ -29,7 +30,8 @@ export function registerBuiltInActionTypes({ actionTypeRegistry.register(getIndexActionType({ logger })); actionTypeRegistry.register(getPagerDutyActionType({ logger, configurationUtilities })); actionTypeRegistry.register(getServerLogActionType({ logger })); - actionTypeRegistry.register(getServiceNowActionType({ configurationUtilities })); actionTypeRegistry.register(getSlackActionType({ configurationUtilities })); actionTypeRegistry.register(getWebhookActionType({ logger, configurationUtilities })); + actionTypeRegistry.register(getServiceNowActionType({ configurationUtilities })); + actionTypeRegistry.register(getJiraActionType({ configurationUtilities })); } diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts new file mode 100644 index 0000000000000..bcfb82077d286 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.test.ts @@ -0,0 +1,517 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { api } from '../case/api'; +import { externalServiceMock, mapping, apiParams } from './mocks'; +import { ExternalService } from '../case/types'; + +describe('api', () => { + let externalService: jest.Mocked; + + beforeEach(() => { + externalService = externalServiceMock.create(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('pushToService', () => { + describe('create incident', () => { + test('it creates an incident', async () => { + const params = { ...apiParams, externalId: null }; + const res = await api.pushToService({ externalService, mapping, params }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + comments: [ + { + commentId: 'case-comment-1', + pushedDate: '2020-04-27T10:59:46.202Z', + }, + { + commentId: 'case-comment-2', + pushedDate: '2020-04-27T10:59:46.202Z', + }, + ], + }); + }); + + test('it creates an incident without comments', async () => { + const params = { ...apiParams, externalId: null, comments: [] }; + const res = await api.pushToService({ externalService, mapping, params }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + }); + }); + + test('it calls createIncident correctly', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping, params }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + description: + 'Incident description (created at 2020-04-27T10:59:46.202Z by Elastic User)', + summary: 'Incident title (created at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + + test('it calls createComment correctly', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping, params }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + field: 'comments', + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + field: 'comments', + }); + }); + }); + + describe('update incident', () => { + test('it updates an incident', async () => { + const res = await api.pushToService({ externalService, mapping, params: apiParams }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + comments: [ + { + commentId: 'case-comment-1', + pushedDate: '2020-04-27T10:59:46.202Z', + }, + { + commentId: 'case-comment-2', + pushedDate: '2020-04-27T10:59:46.202Z', + }, + ], + }); + }); + + test('it updates an incident without comments', async () => { + const params = { ...apiParams, comments: [] }; + const res = await api.pushToService({ externalService, mapping, params }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + }); + }); + + test('it calls updateIncident correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping, params }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: + 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + expect(externalService.createIncident).not.toHaveBeenCalled(); + }); + + test('it calls createComment correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping, params }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + field: 'comments', + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment (added at 2020-04-27T10:59:46.202Z by Elastic User)', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + field: 'comments', + }); + }); + }); + + describe('mapping variations', () => { + test('overwrite & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & append', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: + 'description from jira \r\nIncident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: {}, + }); + }); + + test('overwrite & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('overwrite & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + summary: 'Incident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: + 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('nothing & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: + 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & overwrite', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + description: + 'Incident description (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('append & nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + summary: + 'title from jira \r\nIncident title (updated at 2020-04-27T10:59:46.202Z by Elastic User)', + }, + }); + }); + + test('comment nothing', async () => { + mapping.set('title', { + target: 'summary', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'nothing', + }); + + mapping.set('summary', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.createComment).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/api.ts new file mode 100644 index 0000000000000..3db66e5884af4 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/api.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 { api } from '../case/api'; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/config.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/config.ts new file mode 100644 index 0000000000000..7e415109f1bd9 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/config.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ExternalServiceConfiguration } from '../case/types'; +import * as i18n from './translations'; + +export const config: ExternalServiceConfiguration = { + id: '.jira', + name: i18n.NAME, +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/index.ts new file mode 100644 index 0000000000000..a2d7bb5930a75 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/index.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 { createConnector } from '../case/utils'; + +import { api } from './api'; +import { config } from './config'; +import { validate } from './validators'; +import { createExternalService } from './service'; +import { JiraSecretConfiguration, JiraPublicConfiguration } from './schema'; + +export const getActionType = createConnector({ + api, + config, + validate, + createExternalService, + validationSchema: { + config: JiraPublicConfiguration, + secrets: JiraSecretConfiguration, + }, +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts new file mode 100644 index 0000000000000..3ae0e9db36de0 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/mocks.ts @@ -0,0 +1,124 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + ExternalService, + PushToServiceApiParams, + ExecutorSubActionPushParams, + MapRecord, +} from '../case/types'; + +const createMock = (): jest.Mocked => { + const service = { + getIncident: jest.fn().mockImplementation(() => + Promise.resolve({ + id: 'incident-1', + key: 'CK-1', + summary: 'title from jira', + description: 'description from jira', + created: '2020-04-27T10:59:46.202Z', + updated: '2020-04-27T10:59:46.202Z', + }) + ), + createIncident: jest.fn().mockImplementation(() => + Promise.resolve({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + }) + ), + updateIncident: jest.fn().mockImplementation(() => + Promise.resolve({ + id: 'incident-1', + title: 'CK-1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + }) + ), + createComment: jest.fn(), + }; + + service.createComment.mockImplementationOnce(() => + Promise.resolve({ + commentId: 'case-comment-1', + pushedDate: '2020-04-27T10:59:46.202Z', + externalCommentId: '1', + }) + ); + + service.createComment.mockImplementationOnce(() => + Promise.resolve({ + commentId: 'case-comment-2', + pushedDate: '2020-04-27T10:59:46.202Z', + externalCommentId: '2', + }) + ); + + return service; +}; + +const externalServiceMock = { + create: createMock, +}; + +const mapping: Map> = new Map(); + +mapping.set('title', { + target: 'summary', + actionType: 'overwrite', +}); + +mapping.set('description', { + target: 'description', + actionType: 'overwrite', +}); + +mapping.set('comments', { + target: 'comments', + actionType: 'append', +}); + +mapping.set('summary', { + target: 'title', + actionType: 'overwrite', +}); + +const executorParams: ExecutorSubActionPushParams = { + caseId: 'd4387ac5-0899-4dc2-bbfa-0dd605c934aa', + externalId: 'incident-3', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { fullName: 'Elastic User', username: 'elastic' }, + title: 'Incident title', + description: 'Incident description', + comments: [ + { + commentId: 'case-comment-1', + comment: 'A comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { fullName: 'Elastic User', username: 'elastic' }, + }, + { + commentId: 'case-comment-2', + comment: 'Another comment', + createdAt: '2020-04-27T10:59:46.202Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: '2020-04-27T10:59:46.202Z', + updatedBy: { fullName: 'Elastic User', username: 'elastic' }, + }, + ], +}; + +const apiParams: PushToServiceApiParams = { + ...executorParams, + externalCase: { summary: 'Incident title', description: 'Incident description' }, +}; + +export { externalServiceMock, mapping, executorParams, apiParams }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts new file mode 100644 index 0000000000000..9c831e75d91c1 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/schema.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { ExternalIncidentServiceConfiguration } from '../case/schema'; + +export const JiraPublicConfiguration = { + projectKey: schema.string(), + ...ExternalIncidentServiceConfiguration, +}; + +export const JiraPublicConfigurationSchema = schema.object(JiraPublicConfiguration); + +export const JiraSecretConfiguration = { + email: schema.string(), + apiToken: schema.string(), +}; + +export const JiraSecretConfigurationSchema = schema.object(JiraSecretConfiguration); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts new file mode 100644 index 0000000000000..b9225b043d526 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.test.ts @@ -0,0 +1,297 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import axios from 'axios'; + +import { createExternalService } from './service'; +import * as utils from '../case/utils'; +import { ExternalService } from '../case/types'; + +jest.mock('axios'); +jest.mock('../case/utils', () => { + const originalUtils = jest.requireActual('../case/utils'); + return { + ...originalUtils, + request: jest.fn(), + }; +}); + +axios.create = jest.fn(() => axios); +const requestMock = utils.request as jest.Mock; + +describe('Jira service', () => { + let service: ExternalService; + + beforeAll(() => { + service = createExternalService({ + config: { apiUrl: 'https://siem-kibana.atlassian.net', projectKey: 'CK' }, + secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, + }); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('createExternalService', () => { + test('throws without url', () => { + expect(() => + createExternalService({ + config: { apiUrl: null, projectKey: 'CK' }, + secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, + }) + ).toThrow(); + }); + + test('throws without projectKey', () => { + expect(() => + createExternalService({ + config: { apiUrl: 'test.com', projectKey: null }, + secrets: { apiToken: 'token', email: 'elastic@elastic.com' }, + }) + ).toThrow(); + }); + + test('throws without username', () => { + expect(() => + createExternalService({ + config: { apiUrl: 'test.com' }, + secrets: { apiToken: '', email: 'elastic@elastic.com' }, + }) + ).toThrow(); + }); + + test('throws without password', () => { + expect(() => + createExternalService({ + config: { apiUrl: 'test.com' }, + secrets: { apiToken: '', email: undefined }, + }) + ).toThrow(); + }); + }); + + describe('getIncident', () => { + test('it returns the incident correctly', async () => { + requestMock.mockImplementation(() => ({ + data: { id: '1', key: 'CK-1', fields: { summary: 'title', description: 'description' } }, + })); + const res = await service.getIncident('1'); + expect(res).toEqual({ id: '1', key: 'CK-1', summary: 'title', description: 'description' }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { id: '1', key: 'CK-1' }, + })); + + await service.getIncident('1'); + expect(requestMock).toHaveBeenCalledWith({ + axios, + url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1', + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + expect(service.getIncident('1')).rejects.toThrow( + 'Unable to get incident with id 1. Error: An error has occurred' + ); + }); + }); + + describe('createIncident', () => { + test('it creates the incident correctly', async () => { + // The response from Jira when creating an issue contains only the key and the id. + // The service makes two calls when creating an issue. One to create and one to get + // the created incident with all the necessary fields. + requestMock.mockImplementationOnce(() => ({ + data: { id: '1', key: 'CK-1', fields: { summary: 'title', description: 'description' } }, + })); + + requestMock.mockImplementationOnce(() => ({ + data: { id: '1', key: 'CK-1', fields: { created: '2020-04-27T10:59:46.202Z' } }, + })); + + const res = await service.createIncident({ + incident: { summary: 'title', description: 'desc' }, + }); + + expect(res).toEqual({ + title: 'CK-1', + id: '1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { + id: '1', + key: 'CK-1', + fields: { created: '2020-04-27T10:59:46.202Z' }, + }, + })); + + await service.createIncident({ + incident: { summary: 'title', description: 'desc' }, + }); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + url: 'https://siem-kibana.atlassian.net/rest/api/2/issue', + method: 'post', + data: { + fields: { + summary: 'title', + description: 'desc', + project: { key: 'CK' }, + issuetype: { name: 'Task' }, + }, + }, + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + + expect( + service.createIncident({ + incident: { summary: 'title', description: 'desc' }, + }) + ).rejects.toThrow('[Action][Jira]: Unable to create incident. Error: An error has occurred'); + }); + }); + + describe('updateIncident', () => { + test('it updates the incident correctly', async () => { + requestMock.mockImplementation(() => ({ + data: { + id: '1', + key: 'CK-1', + fields: { updated: '2020-04-27T10:59:46.202Z' }, + }, + })); + + const res = await service.updateIncident({ + incidentId: '1', + incident: { summary: 'title', description: 'desc' }, + }); + + expect(res).toEqual({ + title: 'CK-1', + id: '1', + pushedDate: '2020-04-27T10:59:46.202Z', + url: 'https://siem-kibana.atlassian.net/browse/CK-1', + }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { + id: '1', + key: 'CK-1', + fields: { updated: '2020-04-27T10:59:46.202Z' }, + }, + })); + + await service.updateIncident({ + incidentId: '1', + incident: { summary: 'title', description: 'desc' }, + }); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + method: 'put', + url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1', + data: { fields: { summary: 'title', description: 'desc' } }, + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + + expect( + service.updateIncident({ + incidentId: '1', + incident: { summary: 'title', description: 'desc' }, + }) + ).rejects.toThrow( + '[Action][Jira]: Unable to update incident with id 1. Error: An error has occurred' + ); + }); + }); + + describe('createComment', () => { + test('it creates the comment correctly', async () => { + requestMock.mockImplementation(() => ({ + data: { + id: '1', + key: 'CK-1', + created: '2020-04-27T10:59:46.202Z', + }, + })); + + const res = await service.createComment({ + incidentId: '1', + comment: { comment: 'comment', commentId: 'comment-1' }, + field: 'comments', + }); + + expect(res).toEqual({ + commentId: 'comment-1', + pushedDate: '2020-04-27T10:59:46.202Z', + externalCommentId: '1', + }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { + id: '1', + key: 'CK-1', + created: '2020-04-27T10:59:46.202Z', + }, + })); + + await service.createComment({ + incidentId: '1', + comment: { comment: 'comment', commentId: 'comment-1' }, + field: 'my_field', + }); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + method: 'post', + url: 'https://siem-kibana.atlassian.net/rest/api/2/issue/1/comment', + data: { body: 'comment' }, + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + + expect( + service.createComment({ + incidentId: '1', + comment: { comment: 'comment', commentId: 'comment-1' }, + field: 'comments', + }) + ).rejects.toThrow( + '[Action][Jira]: Unable to create comment at incident with id 1. Error: An error has occurred' + ); + }); + }); +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/service.ts new file mode 100644 index 0000000000000..ff22b8368e7dd --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/service.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. + */ + +import axios from 'axios'; + +import { ExternalServiceCredentials, ExternalService, ExternalServiceParams } from '../case/types'; +import { + JiraPublicConfigurationType, + JiraSecretConfigurationType, + CreateIncidentRequest, + UpdateIncidentRequest, + CreateCommentRequest, +} from './types'; + +import * as i18n from './translations'; +import { getErrorMessage, request } from '../case/utils'; + +const VERSION = '2'; +const BASE_URL = `rest/api/${VERSION}`; +const INCIDENT_URL = `issue`; +const COMMENT_URL = `comment`; + +const VIEW_INCIDENT_URL = `browse`; + +export const createExternalService = ({ + config, + secrets, +}: ExternalServiceCredentials): ExternalService => { + const { apiUrl: url, projectKey } = config as JiraPublicConfigurationType; + const { apiToken, email } = secrets as JiraSecretConfigurationType; + + if (!url || !projectKey || !apiToken || !email) { + throw Error(`[Action]${i18n.NAME}: Wrong configuration.`); + } + + const incidentUrl = `${url}/${BASE_URL}/${INCIDENT_URL}`; + const commentUrl = `${incidentUrl}/{issueId}/${COMMENT_URL}`; + const axiosInstance = axios.create({ + auth: { username: email, password: apiToken }, + }); + + const getIncidentViewURL = (key: string) => { + return `${url}/${VIEW_INCIDENT_URL}/${key}`; + }; + + const getCommentsURL = (issueId: string) => { + return commentUrl.replace('{issueId}', issueId); + }; + + const getIncident = async (id: string) => { + try { + const res = await request({ + axios: axiosInstance, + url: `${incidentUrl}/${id}`, + }); + + const { fields, ...rest } = res.data; + + return { ...rest, ...fields }; + } catch (error) { + throw new Error( + getErrorMessage(i18n.NAME, `Unable to get incident with id ${id}. Error: ${error.message}`) + ); + } + }; + + const createIncident = async ({ incident }: ExternalServiceParams) => { + // The response from Jira when creating an issue contains only the key and the id. + // The function makes two calls when creating an issue. One to create the issue and one to get + // the created issue with all the necessary fields. + try { + const res = await request({ + axios: axiosInstance, + url: `${incidentUrl}`, + method: 'post', + data: { + fields: { ...incident, project: { key: projectKey }, issuetype: { name: 'Task' } }, + }, + }); + + const updatedIncident = await getIncident(res.data.id); + + return { + title: updatedIncident.key, + id: updatedIncident.id, + pushedDate: new Date(updatedIncident.created).toISOString(), + url: getIncidentViewURL(updatedIncident.key), + }; + } catch (error) { + throw new Error( + getErrorMessage(i18n.NAME, `Unable to create incident. Error: ${error.message}`) + ); + } + }; + + const updateIncident = async ({ incidentId, incident }: ExternalServiceParams) => { + try { + await request({ + axios: axiosInstance, + method: 'put', + url: `${incidentUrl}/${incidentId}`, + data: { fields: { ...incident } }, + }); + + const updatedIncident = await getIncident(incidentId); + + return { + title: updatedIncident.key, + id: updatedIncident.id, + pushedDate: new Date(updatedIncident.updated).toISOString(), + url: getIncidentViewURL(updatedIncident.key), + }; + } catch (error) { + throw new Error( + getErrorMessage( + i18n.NAME, + `Unable to update incident with id ${incidentId}. Error: ${error.message}` + ) + ); + } + }; + + const createComment = async ({ incidentId, comment, field }: ExternalServiceParams) => { + try { + const res = await request({ + axios: axiosInstance, + method: 'post', + url: getCommentsURL(incidentId), + data: { body: comment.comment }, + }); + + return { + commentId: comment.commentId, + externalCommentId: res.data.id, + pushedDate: new Date(res.data.created).toISOString(), + }; + } catch (error) { + throw new Error( + getErrorMessage( + i18n.NAME, + `Unable to create comment at incident with id ${incidentId}. Error: ${error.message}` + ) + ); + } + }; + + return { + getIncident, + createIncident, + updateIncident, + createComment, + }; +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/translations.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/translations.ts new file mode 100644 index 0000000000000..dae0d75952e11 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/translations.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 { i18n } from '@kbn/i18n'; + +export const NAME = i18n.translate('xpack.actions.builtin.case.jiraTitle', { + defaultMessage: 'Jira', +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/types.ts new file mode 100644 index 0000000000000..8d9c6b92abb3b --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/types.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 { TypeOf } from '@kbn/config-schema'; +import { JiraPublicConfigurationSchema, JiraSecretConfigurationSchema } from './schema'; + +export type JiraPublicConfigurationType = TypeOf; +export type JiraSecretConfigurationType = TypeOf; + +interface CreateIncidentBasicRequestArgs { + summary: string; + description: string; +} +interface CreateIncidentRequestArgs extends CreateIncidentBasicRequestArgs { + project: { key: string }; + issuetype: { name: string }; +} + +export interface CreateIncidentRequest { + fields: CreateIncidentRequestArgs; +} + +export interface UpdateIncidentRequest { + fields: Partial; +} + +export interface CreateCommentRequest { + body: string; +} diff --git a/x-pack/plugins/actions/server/builtin_action_types/jira/validators.ts b/x-pack/plugins/actions/server/builtin_action_types/jira/validators.ts new file mode 100644 index 0000000000000..7226071392bc6 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/jira/validators.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { validateCommonConfig, validateCommonSecrets } from '../case/validators'; +import { ExternalServiceValidation } from '../case/types'; + +export const validate: ExternalServiceValidation = { + config: validateCommonConfig, + secrets: validateCommonSecrets, +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.test.ts deleted file mode 100644 index aa9b1dcfcf239..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.test.ts +++ /dev/null @@ -1,850 +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 { - handleCreateIncident, - handleUpdateIncident, - handleIncident, - createComments, -} from './action_handlers'; -import { ServiceNow } from './lib'; -import { Mapping } from './types'; - -jest.mock('./lib'); - -const ServiceNowMock = ServiceNow as jest.Mock; - -const finalMapping: Mapping = new Map(); - -finalMapping.set('title', { - target: 'short_description', - actionType: 'overwrite', -}); - -finalMapping.set('description', { - target: 'description', - actionType: 'overwrite', -}); - -finalMapping.set('comments', { - target: 'comments', - actionType: 'append', -}); - -finalMapping.set('short_description', { - target: 'title', - actionType: 'overwrite', -}); - -const params = { - caseId: '123', - title: 'a title', - description: 'a description', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - incidentId: null, - incident: { - short_description: 'a title', - description: 'a description', - }, - comments: [ - { - commentId: '456', - version: 'WzU3LDFd', - comment: 'first comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - }, - ], -}; - -beforeAll(() => { - ServiceNowMock.mockImplementation(() => { - return { - serviceNow: { - getUserID: jest.fn().mockResolvedValue('1234'), - getIncident: jest.fn().mockResolvedValue({ - short_description: 'servicenow title', - description: 'servicenow desc', - }), - createIncident: jest.fn().mockResolvedValue({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }), - updateIncident: jest.fn().mockResolvedValue({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }), - batchCreateComments: jest - .fn() - .mockResolvedValue([{ commentId: '456', pushedDate: '2020-03-10T12:24:20.000Z' }]), - }, - }; - }); -}); - -describe('handleIncident', () => { - test('create an incident', async () => { - const { serviceNow } = new ServiceNowMock(); - - const res = await handleIncident({ - incidentId: null, - serviceNow, - params, - comments: params.comments, - mapping: finalMapping, - }); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - comments: [ - { - commentId: '456', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ], - }); - }); - test('update an incident', async () => { - const { serviceNow } = new ServiceNowMock(); - - const res = await handleIncident({ - incidentId: '123', - serviceNow, - params, - comments: params.comments, - mapping: finalMapping, - }); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - comments: [ - { - commentId: '456', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ], - }); - }); -}); - -describe('handleCreateIncident', () => { - test('create an incident without comments', async () => { - const { serviceNow } = new ServiceNowMock(); - - const res = await handleCreateIncident({ - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.createIncident).toHaveBeenCalled(); - expect(serviceNow.createIncident).toHaveBeenCalledWith({ - short_description: 'a title (created at 2020-03-13T08:34:53.450Z by Elastic User)', - description: 'a description (created at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.createIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('create an incident with comments', async () => { - const { serviceNow } = new ServiceNowMock(); - - const res = await handleCreateIncident({ - serviceNow, - params, - comments: params.comments, - mapping: finalMapping, - }); - - expect(serviceNow.createIncident).toHaveBeenCalled(); - expect(serviceNow.createIncident).toHaveBeenCalledWith({ - description: 'a description (created at 2020-03-13T08:34:53.450Z by Elastic User)', - short_description: 'a title (created at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.createIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).toHaveBeenCalled(); - expect(serviceNow.batchCreateComments).toHaveBeenCalledWith( - '123', - [ - { - comment: 'first comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', - commentId: '456', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: null, - updatedBy: null, - version: 'WzU3LDFd', - }, - ], - 'comments' - ); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - comments: [ - { - commentId: '456', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ], - }); - }); -}); - -describe('handleUpdateIncident', () => { - test('update an incident without comments', async () => { - const { serviceNow } = new ServiceNowMock(); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params: { - ...params, - updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { fullName: 'Another User', username: 'anotherUser' }, - }, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - short_description: 'a title (updated at 2020-03-15T08:34:53.450Z by Another User)', - description: 'a description (updated at 2020-03-15T08:34:53.450Z by Another User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('update an incident with comments', async () => { - const { serviceNow } = new ServiceNowMock(); - serviceNow.batchCreateComments.mockResolvedValue([ - { commentId: '456', pushedDate: '2020-03-10T12:24:20.000Z' }, - { commentId: '789', pushedDate: '2020-03-10T12:24:20.000Z' }, - ]); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params: { - ...params, - updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { fullName: 'Another User', username: 'anotherUser' }, - }, - comments: [ - { - comment: 'first comment', - commentId: '456', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: null, - updatedBy: null, - version: 'WzU3LDFd', - }, - { - comment: 'second comment', - commentId: '789', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-03-16T08:34:53.450Z', - updatedBy: { - fullName: 'Another User', - username: 'anotherUser', - }, - version: 'WzU3LDFd', - }, - ], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - description: 'a description (updated at 2020-03-15T08:34:53.450Z by Another User)', - short_description: 'a title (updated at 2020-03-15T08:34:53.450Z by Another User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).toHaveBeenCalled(); - expect(serviceNow.batchCreateComments).toHaveBeenCalledWith( - '123', - [ - { - comment: 'first comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', - commentId: '456', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: null, - updatedBy: null, - version: 'WzU3LDFd', - }, - { - comment: 'second comment (added at 2020-03-16T08:34:53.450Z by Another User)', - commentId: '789', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-03-16T08:34:53.450Z', - updatedBy: { - fullName: 'Another User', - username: 'anotherUser', - }, - version: 'WzU3LDFd', - }, - ], - 'comments' - ); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - comments: [ - { - commentId: '456', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - { - commentId: '789', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ], - }); - }); -}); - -describe('handleUpdateIncident: different action types', () => { - test('overwrite & append', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'append', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'servicenow desc \r\na description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('nothing & append', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'append', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - description: - 'servicenow desc \r\na description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('append & append', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'append', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - short_description: - 'servicenow title \r\na title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: - 'servicenow desc \r\na description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('nothing & nothing', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', {}); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('overwrite & nothing', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('overwrite & overwrite', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'overwrite', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'overwrite', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - short_description: 'a title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: 'a description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('nothing & overwrite', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'nothing', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'nothing', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - description: 'a description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('append & overwrite', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'overwrite', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - short_description: - 'servicenow title \r\na title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - description: 'a description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('append & nothing', async () => { - const { serviceNow } = new ServiceNowMock(); - finalMapping.set('title', { - target: 'short_description', - actionType: 'append', - }); - - finalMapping.set('description', { - target: 'description', - actionType: 'nothing', - }); - - finalMapping.set('comments', { - target: 'comments', - actionType: 'append', - }); - - finalMapping.set('short_description', { - target: 'title', - actionType: 'append', - }); - - const res = await handleUpdateIncident({ - incidentId: '123', - serviceNow, - params, - comments: [], - mapping: finalMapping, - }); - - expect(serviceNow.updateIncident).toHaveBeenCalled(); - expect(serviceNow.updateIncident).toHaveBeenCalledWith('123', { - short_description: - 'servicenow title \r\na title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', - }); - expect(serviceNow.updateIncident).toHaveReturned(); - expect(serviceNow.batchCreateComments).not.toHaveBeenCalled(); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); -}); - -describe('createComments', () => { - test('create comments correctly', async () => { - const { serviceNow } = new ServiceNowMock(); - serviceNow.batchCreateComments.mockResolvedValue([ - { commentId: '456', pushedDate: '2020-03-10T12:24:20.000Z' }, - { commentId: '789', pushedDate: '2020-03-10T12:24:20.000Z' }, - ]); - - const comments = [ - { - comment: 'first comment', - commentId: '456', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: null, - updatedBy: null, - version: 'WzU3LDFd', - }, - { - comment: 'second comment', - commentId: '789', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-03-13T08:34:53.450Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - version: 'WzU3LDFd', - }, - ]; - - const res = await createComments(serviceNow, '123', 'comments', comments); - - expect(serviceNow.batchCreateComments).toHaveBeenCalled(); - expect(serviceNow.batchCreateComments).toHaveBeenCalledWith( - '123', - [ - { - comment: 'first comment', - commentId: '456', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: null, - updatedBy: null, - version: 'WzU3LDFd', - }, - { - comment: 'second comment', - commentId: '789', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - updatedAt: '2020-03-13T08:34:53.450Z', - updatedBy: { - fullName: 'Elastic User', - username: 'elastic', - }, - version: 'WzU3LDFd', - }, - ], - 'comments' - ); - expect(res).toEqual([ - { - commentId: '456', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - { - commentId: '789', - pushedDate: '2020-03-10T12:24:20.000Z', - }, - ]); - }); -}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.ts deleted file mode 100644 index 9166f53cf757e..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/action_handlers.ts +++ /dev/null @@ -1,129 +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 { zipWith } from 'lodash'; -import { CommentResponse } from './lib/types'; -import { - HandlerResponse, - Comment, - SimpleComment, - CreateHandlerArguments, - UpdateHandlerArguments, - IncidentHandlerArguments, -} from './types'; -import { ServiceNow } from './lib'; -import { transformFields, prepareFieldsForTransformation, transformComments } from './helpers'; - -export const createComments = async ( - serviceNow: ServiceNow, - incidentId: string, - key: string, - comments: Comment[] -): Promise => { - const createdComments = await serviceNow.batchCreateComments(incidentId, comments, key); - - return zipWith(comments, createdComments, (a: Comment, b: CommentResponse) => ({ - commentId: a.commentId, - pushedDate: b.pushedDate, - })); -}; - -export const handleCreateIncident = async ({ - serviceNow, - params, - comments, - mapping, -}: CreateHandlerArguments): Promise => { - const fields = prepareFieldsForTransformation({ - params, - mapping, - }); - - const incident = transformFields({ - params, - fields, - }); - - const createdIncident = await serviceNow.createIncident({ - ...incident, - }); - - const res: HandlerResponse = { ...createdIncident }; - - if ( - comments && - Array.isArray(comments) && - comments.length > 0 && - mapping.get('comments')?.actionType !== 'nothing' - ) { - comments = transformComments(comments, params, ['informationAdded']); - res.comments = [ - ...(await createComments( - serviceNow, - res.incidentId, - mapping.get('comments')!.target, - comments - )), - ]; - } - - return { ...res }; -}; - -export const handleUpdateIncident = async ({ - incidentId, - serviceNow, - params, - comments, - mapping, -}: UpdateHandlerArguments): Promise => { - const currentIncident = await serviceNow.getIncident(incidentId); - const fields = prepareFieldsForTransformation({ - params, - mapping, - defaultPipes: ['informationUpdated'], - }); - - const incident = transformFields({ - params, - fields, - currentIncident, - }); - - const updatedIncident = await serviceNow.updateIncident(incidentId, { - ...incident, - }); - - const res: HandlerResponse = { ...updatedIncident }; - - if ( - comments && - Array.isArray(comments) && - comments.length > 0 && - mapping.get('comments')?.actionType !== 'nothing' - ) { - comments = transformComments(comments, params, ['informationAdded']); - res.comments = [ - ...(await createComments(serviceNow, incidentId, mapping.get('comments')!.target, comments)), - ]; - } - - return { ...res }; -}; - -export const handleIncident = async ({ - incidentId, - serviceNow, - params, - comments, - mapping, -}: IncidentHandlerArguments): Promise => { - if (!incidentId) { - return await handleCreateIncident({ serviceNow, params, comments, mapping }); - } else { - return await handleUpdateIncident({ incidentId, serviceNow, params, comments, mapping }); - } -}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts new file mode 100644 index 0000000000000..86a8318841271 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.test.ts @@ -0,0 +1,523 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { api } from '../case/api'; +import { externalServiceMock, mapping, apiParams } from './mocks'; +import { ExternalService } from '../case/types'; + +describe('api', () => { + let externalService: jest.Mocked; + + beforeEach(() => { + externalService = externalServiceMock.create(); + jest.clearAllMocks(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + describe('pushToService', () => { + describe('create incident', () => { + test('it creates an incident', async () => { + const params = { ...apiParams, externalId: null }; + const res = await api.pushToService({ externalService, mapping, params }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + comments: [ + { + commentId: 'case-comment-1', + pushedDate: '2020-03-10T12:24:20.000Z', + }, + { + commentId: 'case-comment-2', + pushedDate: '2020-03-10T12:24:20.000Z', + }, + ], + }); + }); + + test('it creates an incident without comments', async () => { + const params = { ...apiParams, externalId: null, comments: [] }; + const res = await api.pushToService({ externalService, mapping, params }); + + expect(res).toEqual({ + id: 'incident-1', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }); + }); + + test('it calls createIncident correctly', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping, params }); + + expect(externalService.createIncident).toHaveBeenCalledWith({ + incident: { + description: + 'Incident description (created at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: + 'Incident title (created at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + expect(externalService.updateIncident).not.toHaveBeenCalled(); + }); + + test('it calls createComment correctly', async () => { + const params = { ...apiParams, externalId: null }; + await api.pushToService({ externalService, mapping, params }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-1', + comment: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-03-13T08:34:53.450Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + field: 'comments', + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-1', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-03-13T08:34:53.450Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + field: 'comments', + }); + }); + }); + + describe('update incident', () => { + test('it updates an incident', async () => { + const res = await api.pushToService({ externalService, mapping, params: apiParams }); + + expect(res).toEqual({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + comments: [ + { + commentId: 'case-comment-1', + pushedDate: '2020-03-10T12:24:20.000Z', + }, + { + commentId: 'case-comment-2', + pushedDate: '2020-03-10T12:24:20.000Z', + }, + ], + }); + }); + + test('it updates an incident without comments', async () => { + const params = { ...apiParams, comments: [] }; + const res = await api.pushToService({ externalService, mapping, params }); + + expect(res).toEqual({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }); + }); + + test('it calls updateIncident correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping, params }); + + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: + 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + short_description: + 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + expect(externalService.createIncident).not.toHaveBeenCalled(); + }); + + test('it calls createComment correctly', async () => { + const params = { ...apiParams }; + await api.pushToService({ externalService, mapping, params }); + expect(externalService.createComment).toHaveBeenCalledTimes(2); + expect(externalService.createComment).toHaveBeenNthCalledWith(1, { + incidentId: 'incident-2', + comment: { + commentId: 'case-comment-1', + comment: 'A comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-03-13T08:34:53.450Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + field: 'comments', + }); + + expect(externalService.createComment).toHaveBeenNthCalledWith(2, { + incidentId: 'incident-2', + comment: { + commentId: 'case-comment-2', + comment: 'Another comment (added at 2020-03-13T08:34:53.450Z by Elastic User)', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + updatedAt: '2020-03-13T08:34:53.450Z', + updatedBy: { + fullName: 'Elastic User', + username: 'elastic', + }, + }, + field: 'comments', + }); + }); + }); + + describe('mapping variations', () => { + test('overwrite & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + short_description: + 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & append', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'append', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: + 'description from servicenow \r\nIncident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: {}, + }); + }); + + test('overwrite & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + short_description: + 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('overwrite & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + short_description: + 'Incident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: + 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('nothing & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'nothing', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'nothing', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + description: + 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & overwrite', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'overwrite', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + description: + 'Incident description (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('append & nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'append', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'append', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'append', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.updateIncident).toHaveBeenCalledWith({ + incidentId: 'incident-3', + incident: { + short_description: + 'title from servicenow \r\nIncident title (updated at 2020-03-13T08:34:53.450Z by Elastic User)', + }, + }); + }); + + test('comment nothing', async () => { + mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', + }); + + mapping.set('description', { + target: 'description', + actionType: 'nothing', + }); + + mapping.set('comments', { + target: 'comments', + actionType: 'nothing', + }); + + mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', + }); + + await api.pushToService({ externalService, mapping, params: apiParams }); + expect(externalService.createComment).not.toHaveBeenCalled(); + }); + }); + }); +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.ts new file mode 100644 index 0000000000000..3db66e5884af4 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/api.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 { api } from '../case/api'; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.ts new file mode 100644 index 0000000000000..4ad8108c3b137 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/config.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { ExternalServiceConfiguration } from '../case/types'; +import * as i18n from './translations'; + +export const config: ExternalServiceConfiguration = { + id: '.servicenow', + name: i18n.NAME, +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.ts deleted file mode 100644 index 0a26996ea8d69..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/helpers.ts +++ /dev/null @@ -1,125 +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 { flow } from 'lodash'; - -import { SUPPORTED_SOURCE_FIELDS } from './constants'; -import { - MapEntry, - Mapping, - AppendFieldArgs, - AppendInformationFieldArgs, - Params, - Comment, - TransformFieldsArgs, - PipedField, - PrepareFieldsForTransformArgs, - KeyAny, -} from './types'; -import { Incident } from './lib/types'; - -import * as transformers from './transformers'; -import * as i18n from './translations'; - -export const normalizeMapping = (supportedFields: string[], mapping: MapEntry[]): MapEntry[] => { - // Prevent prototype pollution and remove unsupported fields - return mapping.filter( - m => m.source !== '__proto__' && m.target !== '__proto__' && supportedFields.includes(m.source) - ); -}; - -export const buildMap = (mapping: MapEntry[]): Mapping => { - return normalizeMapping(SUPPORTED_SOURCE_FIELDS, mapping).reduce((fieldsMap, field) => { - const { source, target, actionType } = field; - fieldsMap.set(source, { target, actionType }); - fieldsMap.set(target, { target: source, actionType }); - return fieldsMap; - }, new Map()); -}; - -export const mapParams = (params: Record, mapping: Mapping) => { - return Object.keys(params).reduce((prev: KeyAny, curr: string): KeyAny => { - const field = mapping.get(curr); - if (field) { - prev[field.target] = params[curr]; - } - return prev; - }, {}); -}; - -export const appendField = ({ value, prefix = '', suffix = '' }: AppendFieldArgs): string => { - return `${prefix}${value} ${suffix}`; -}; - -const t = { ...transformers } as { [index: string]: Function }; // TODO: Find a better solution exists. - -export const prepareFieldsForTransformation = ({ - params, - mapping, - defaultPipes = ['informationCreated'], -}: PrepareFieldsForTransformArgs): PipedField[] => { - return Object.keys(params.incident) - .filter(p => mapping.get(p)!.actionType !== 'nothing') - .map(p => ({ - key: p, - value: params.incident[p] as string, - actionType: mapping.get(p)!.actionType, - pipes: [...defaultPipes], - })) - .map(p => ({ - ...p, - pipes: p.actionType === 'append' ? [...p.pipes, 'append'] : p.pipes, - })); -}; - -export const transformFields = ({ - params, - fields, - currentIncident, -}: TransformFieldsArgs): Incident => { - return fields.reduce((prev: Incident, cur) => { - const transform = flow(...cur.pipes.map(p => t[p])); - prev[cur.key] = transform({ - value: cur.value, - date: params.updatedAt ?? params.createdAt, - user: - params.updatedBy != null - ? params.updatedBy.fullName ?? params.updatedBy.username - : params.createdBy.fullName ?? params.createdBy.username, - previousValue: currentIncident ? currentIncident[cur.key] : '', - }).value; - return prev; - }, {} as Incident); -}; - -export const appendInformationToField = ({ - value, - user, - date, - mode = 'create', -}: AppendInformationFieldArgs): string => { - return appendField({ - value, - suffix: i18n.FIELD_INFORMATION(mode, date, user), - }); -}; - -export const transformComments = ( - comments: Comment[], - params: Params, - pipes: string[] -): Comment[] => { - return comments.map(c => ({ - ...c, - comment: flow(...pipes.map(p => t[p]))({ - value: c.comment, - date: c.updatedAt ?? c.createdAt, - user: - c.updatedBy != null - ? c.updatedBy.fullName ?? c.updatedBy.username - : c.createdBy.fullName ?? c.createdBy.username, - }).value, - })); -}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts deleted file mode 100644 index a6c3ae88765ac..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.test.ts +++ /dev/null @@ -1,268 +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 { getActionType } from '.'; -import { ActionType, Services, ActionTypeExecutorOptions } from '../../types'; -import { validateConfig, validateSecrets, validateParams } from '../../lib'; -import { createActionTypeRegistry } from '../index.test'; -import { actionsConfigMock } from '../../actions_config.mock'; -import { actionsMock } from '../../mocks'; - -import { ACTION_TYPE_ID } from './constants'; -import * as i18n from './translations'; - -import { handleIncident } from './action_handlers'; -import { incidentResponse } from './mock'; - -jest.mock('./action_handlers'); - -const handleIncidentMock = handleIncident as jest.Mock; - -const services: Services = actionsMock.createServices(); - -let actionType: ActionType; - -const mockOptions = { - name: 'servicenow-connector', - actionTypeId: '.servicenow', - secrets: { - username: 'secret-username', - password: 'secret-password', - }, - config: { - apiUrl: 'https://service-now.com', - casesConfiguration: { - mapping: [ - { - source: 'title', - target: 'short_description', - actionType: 'overwrite', - }, - { - source: 'description', - target: 'description', - actionType: 'overwrite', - }, - { - source: 'comments', - target: 'work_notes', - actionType: 'append', - }, - ], - }, - }, - params: { - caseId: 'd4387ac5-0899-4dc2-bbfa-0dd605c934aa', - incidentId: 'ceb5986e079f00100e48fbbf7c1ed06d', - title: 'Incident title', - description: 'Incident description', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - comments: [ - { - commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', - comment: 'A comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - }, - ], - }, -}; - -beforeAll(() => { - const { actionTypeRegistry } = createActionTypeRegistry(); - actionType = actionTypeRegistry.get(ACTION_TYPE_ID); -}); - -describe('get()', () => { - test('should return correct action type', () => { - expect(actionType.id).toEqual(ACTION_TYPE_ID); - expect(actionType.name).toEqual(i18n.NAME); - }); -}); - -describe('validateConfig()', () => { - test('should validate and pass when config is valid', () => { - const { config } = mockOptions; - expect(validateConfig(actionType, config)).toEqual(config); - }); - - test('should validate and throw error when config is invalid', () => { - expect(() => { - validateConfig(actionType, { shouldNotBeHere: true }); - }).toThrowErrorMatchingInlineSnapshot( - `"error validating action type config: [apiUrl]: expected value of type [string] but got [undefined]"` - ); - }); - - test('should validate and pass when the servicenow url is whitelisted', () => { - actionType = getActionType({ - configurationUtilities: { - ...actionsConfigMock.create(), - ensureWhitelistedUri: url => { - expect(url).toEqual(mockOptions.config.apiUrl); - }, - }, - }); - - expect(validateConfig(actionType, mockOptions.config)).toEqual(mockOptions.config); - }); - - test('config validation returns an error if the specified URL isnt whitelisted', () => { - actionType = getActionType({ - configurationUtilities: { - ...actionsConfigMock.create(), - ensureWhitelistedUri: _ => { - throw new Error(`target url is not whitelisted`); - }, - }, - }); - - expect(() => { - validateConfig(actionType, mockOptions.config); - }).toThrowErrorMatchingInlineSnapshot( - `"error validating action type config: error configuring servicenow action: target url is not whitelisted"` - ); - }); -}); - -describe('validateSecrets()', () => { - test('should validate and pass when secrets is valid', () => { - const { secrets } = mockOptions; - expect(validateSecrets(actionType, secrets)).toEqual(secrets); - }); - - test('should validate and throw error when secrets is invalid', () => { - expect(() => { - validateSecrets(actionType, { username: false }); - }).toThrowErrorMatchingInlineSnapshot( - `"error validating action type secrets: [password]: expected value of type [string] but got [undefined]"` - ); - - expect(() => { - validateSecrets(actionType, { username: false, password: 'hello' }); - }).toThrowErrorMatchingInlineSnapshot( - `"error validating action type secrets: [username]: expected value of type [string] but got [boolean]"` - ); - }); -}); - -describe('validateParams()', () => { - test('should validate and pass when params is valid', () => { - const { params } = mockOptions; - expect(validateParams(actionType, params)).toEqual(params); - }); - - test('should validate and throw error when params is invalid', () => { - expect(() => { - validateParams(actionType, {}); - }).toThrowErrorMatchingInlineSnapshot( - `"error validating action params: [caseId]: expected value of type [string] but got [undefined]"` - ); - }); -}); - -describe('execute()', () => { - beforeEach(() => { - handleIncidentMock.mockReset(); - }); - - test('should create an incident', async () => { - const actionId = 'some-id'; - const { incidentId, ...rest } = mockOptions.params; - - const executorOptions: ActionTypeExecutorOptions = { - actionId, - config: mockOptions.config, - params: { ...rest }, - secrets: mockOptions.secrets, - services, - }; - - handleIncidentMock.mockImplementation(() => incidentResponse); - - const actionResponse = await actionType.executor(executorOptions); - expect(actionResponse).toEqual({ actionId, status: 'ok', data: incidentResponse }); - }); - - test('should throw an error when failed to create incident', async () => { - expect.assertions(1); - const { incidentId, ...rest } = mockOptions.params; - - const actionId = 'some-id'; - const executorOptions: ActionTypeExecutorOptions = { - actionId, - config: mockOptions.config, - params: { ...rest }, - secrets: mockOptions.secrets, - services, - }; - const errorMessage = 'Failed to create incident'; - - handleIncidentMock.mockImplementation(() => { - throw new Error(errorMessage); - }); - - try { - await actionType.executor(executorOptions); - } catch (error) { - expect(error.message).toEqual(errorMessage); - } - }); - - test('should update an incident', async () => { - const actionId = 'some-id'; - const executorOptions: ActionTypeExecutorOptions = { - actionId, - config: mockOptions.config, - params: { - ...mockOptions.params, - updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { fullName: 'Another User', username: 'anotherUser' }, - }, - secrets: mockOptions.secrets, - services, - }; - - handleIncidentMock.mockImplementation(() => incidentResponse); - - const actionResponse = await actionType.executor(executorOptions); - expect(actionResponse).toEqual({ actionId, status: 'ok', data: incidentResponse }); - }); - - test('should throw an error when failed to update an incident', async () => { - expect.assertions(1); - - const actionId = 'some-id'; - const executorOptions: ActionTypeExecutorOptions = { - actionId, - config: mockOptions.config, - params: { - ...mockOptions.params, - updatedAt: '2020-03-15T08:34:53.450Z', - updatedBy: { fullName: 'Another User', username: 'anotherUser' }, - }, - secrets: mockOptions.secrets, - services, - }; - const errorMessage = 'Failed to update incident'; - - handleIncidentMock.mockImplementation(() => { - throw new Error(errorMessage); - }); - - try { - await actionType.executor(executorOptions); - } catch (error) { - expect(error.message).toEqual(errorMessage); - } - }); -}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts index 5066190d4fe56..dbb536d2fa53d 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/index.ts @@ -4,108 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import { curry, isEmpty } from 'lodash'; -import { schema } from '@kbn/config-schema'; -import { - ActionType, - ActionTypeExecutorOptions, - ActionTypeExecutorResult, - ExecutorType, -} from '../../types'; -import { ActionsConfigurationUtilities } from '../../actions_config'; -import { ServiceNow } from './lib'; - -import * as i18n from './translations'; - -import { ACTION_TYPE_ID } from './constants'; -import { ConfigType, SecretsType, Comment, ExecutorParams } from './types'; - -import { ConfigSchemaProps, SecretsSchemaProps, ParamsSchema } from './schema'; - -import { buildMap, mapParams } from './helpers'; -import { handleIncident } from './action_handlers'; - -function validateConfig( - configurationUtilities: ActionsConfigurationUtilities, - configObject: ConfigType -) { - try { - if (isEmpty(configObject.casesConfiguration.mapping)) { - return i18n.MAPPING_EMPTY; - } - - configurationUtilities.ensureWhitelistedUri(configObject.apiUrl); - } catch (whitelistError) { - return i18n.WHITE_LISTED_ERROR(whitelistError.message); - } -} - -function validateSecrets( - configurationUtilities: ActionsConfigurationUtilities, - secrets: SecretsType -) {} +import { createConnector } from '../case/utils'; -// action type definition -export function getActionType({ - configurationUtilities, - executor = serviceNowExecutor, -}: { - configurationUtilities: ActionsConfigurationUtilities; - executor?: ExecutorType; -}): ActionType { - return { - id: ACTION_TYPE_ID, - name: i18n.NAME, - minimumLicenseRequired: 'platinum', - validate: { - config: schema.object(ConfigSchemaProps, { - validate: curry(validateConfig)(configurationUtilities), - }), - secrets: schema.object(SecretsSchemaProps, { - validate: curry(validateSecrets)(configurationUtilities), - }), - params: ParamsSchema, - }, - executor, - }; -} - -// action executor - -async function serviceNowExecutor( - execOptions: ActionTypeExecutorOptions -): Promise { - const actionId = execOptions.actionId; - const { - apiUrl, - casesConfiguration: { mapping: configurationMapping }, - } = execOptions.config as ConfigType; - const { username, password } = execOptions.secrets as SecretsType; - const params = execOptions.params as ExecutorParams; - const { comments, incidentId, ...restParams } = params; - - const mapping = buildMap(configurationMapping); - const incident = mapParams((restParams as unknown) as Record, mapping); - const serviceNow = new ServiceNow({ url: apiUrl, username, password }); - - const handlerInput = { - incidentId, - serviceNow, - params: { ...params, incident }, - comments: comments as Comment[], - mapping, - }; - - const res: Pick & - Pick = { - status: 'ok', - actionId, - }; - - const data = await handleIncident(handlerInput); - - return { - ...res, - data, - }; -} +import { api } from './api'; +import { config } from './config'; +import { validate } from './validators'; +import { createExternalService } from './service'; +import { + ExternalIncidentServiceConfiguration, + ExternalIncidentServiceSecretConfiguration, +} from '../case/schema'; + +export const getActionType = createConnector({ + api, + config, + validate, + createExternalService, + validationSchema: { + config: ExternalIncidentServiceConfiguration, + secrets: ExternalIncidentServiceSecretConfiguration, + }, +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/constants.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/constants.ts deleted file mode 100644 index 3f102ae19f437..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/constants.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. - */ - -export const API_VERSION = 'v2'; -export const INCIDENT_URL = `api/now/${API_VERSION}/table/incident`; -export const USER_URL = `api/now/${API_VERSION}/table/sys_user?user_name=`; -export const COMMENT_URL = `api/now/${API_VERSION}/table/incident`; - -// Based on: https://docs.servicenow.com/bundle/orlando-platform-user-interface/page/use/navigation/reference/r_NavigatingByURLExamples.html -export const VIEW_INCIDENT_URL = `nav_to.do?uri=incident.do?sys_id=`; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.test.ts deleted file mode 100644 index 40eeb0f920f82..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.test.ts +++ /dev/null @@ -1,334 +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 axios from 'axios'; -import { ServiceNow } from '.'; -import { instance, params } from '../mock'; - -jest.mock('axios'); - -axios.create = jest.fn(() => axios); -const axiosMock = (axios as unknown) as jest.Mock; - -let serviceNow: ServiceNow; - -const testMissingConfiguration = (field: string) => { - expect.assertions(1); - try { - new ServiceNow({ ...instance, [field]: '' }); - } catch (error) { - expect(error.message).toEqual('[Action][ServiceNow]: Wrong configuration.'); - } -}; - -const prependInstanceUrl = (url: string): string => `${instance.url}/${url}`; - -describe('ServiceNow lib', () => { - beforeEach(() => { - serviceNow = new ServiceNow(instance); - }); - - afterEach(() => { - jest.clearAllMocks(); - }); - - test('should thrown an error if url is missing', () => { - testMissingConfiguration('url'); - }); - - test('should thrown an error if username is missing', () => { - testMissingConfiguration('username'); - }); - - test('should thrown an error if password is missing', () => { - testMissingConfiguration('password'); - }); - - test('get user id', async () => { - axiosMock.mockResolvedValue({ - status: 200, - headers: { - 'content-type': 'application/json', - }, - data: { result: [{ sys_id: '123' }] }, - }); - - const res = await serviceNow.getUserID(); - const [url, { method }] = axiosMock.mock.calls[0]; - - expect(url).toEqual(prependInstanceUrl('api/now/v2/table/sys_user?user_name=username')); - expect(method).toEqual('get'); - expect(res).toEqual('123'); - }); - - test('create incident', async () => { - axiosMock.mockResolvedValue({ - status: 200, - headers: { - 'content-type': 'application/json', - }, - data: { result: { sys_id: '123', number: 'INC01', sys_created_on: '2020-03-10 12:24:20' } }, - }); - - const res = await serviceNow.createIncident({ - short_description: 'A title', - description: 'A description', - caller_id: '123', - }); - const [url, { method, data }] = axiosMock.mock.calls[0]; - - expect(url).toEqual(prependInstanceUrl('api/now/v2/table/incident')); - expect(method).toEqual('post'); - expect(data).toEqual({ - short_description: 'A title', - description: 'A description', - caller_id: '123', - }); - - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('update incident', async () => { - axiosMock.mockResolvedValue({ - status: 200, - headers: { - 'content-type': 'application/json', - }, - data: { result: { sys_id: '123', number: 'INC01', sys_updated_on: '2020-03-10 12:24:20' } }, - }); - - const res = await serviceNow.updateIncident('123', { - short_description: params.title, - }); - const [url, { method, data }] = axiosMock.mock.calls[0]; - - expect(url).toEqual(prependInstanceUrl(`api/now/v2/table/incident/123`)); - expect(method).toEqual('patch'); - expect(data).toEqual({ short_description: params.title }); - expect(res).toEqual({ - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', - }); - }); - - test('create comment', async () => { - axiosMock.mockResolvedValue({ - status: 200, - headers: { - 'content-type': 'application/json', - }, - data: { result: { sys_updated_on: '2020-03-10 12:24:20' } }, - }); - - const comment = { - commentId: '456', - version: 'WzU3LDFd', - comment: 'A comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - }; - - const res = await serviceNow.createComment('123', comment, 'comments'); - - const [url, { method, data }] = axiosMock.mock.calls[0]; - - expect(url).toEqual(prependInstanceUrl(`api/now/v2/table/incident/123`)); - expect(method).toEqual('patch'); - expect(data).toEqual({ - comments: 'A comment', - }); - - expect(res).toEqual({ - commentId: '456', - pushedDate: '2020-03-10T12:24:20.000Z', - }); - }); - - test('create batch comment', async () => { - axiosMock.mockReturnValueOnce({ - status: 200, - headers: { - 'content-type': 'application/json', - }, - data: { result: { sys_updated_on: '2020-03-10 12:24:20' } }, - }); - - axiosMock.mockReturnValueOnce({ - status: 200, - headers: { - 'content-type': 'application/json', - }, - data: { result: { sys_updated_on: '2020-03-10 12:25:20' } }, - }); - - const comments = [ - { - commentId: '123', - version: 'WzU3LDFd', - comment: 'A comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - }, - { - commentId: '456', - version: 'WzU3LDFd', - comment: 'A second comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - }, - ]; - const res = await serviceNow.batchCreateComments('000', comments, 'comments'); - - comments.forEach((comment, index) => { - const [url, { method, data }] = axiosMock.mock.calls[index]; - expect(url).toEqual(prependInstanceUrl('api/now/v2/table/incident/000')); - expect(method).toEqual('patch'); - expect(data).toEqual({ - comments: comment.comment, - }); - expect(res).toEqual([ - { commentId: '123', pushedDate: '2020-03-10T12:24:20.000Z' }, - { commentId: '456', pushedDate: '2020-03-10T12:25:20.000Z' }, - ]); - }); - }); - - test('throw if not status is not ok', async () => { - expect.assertions(1); - - axiosMock.mockResolvedValue({ - status: 401, - headers: { - 'content-type': 'application/json', - }, - }); - try { - await serviceNow.getUserID(); - } catch (error) { - expect(error.message).toEqual( - '[Action][ServiceNow]: Unable to get user id. Error: [ServiceNow]: Instance is not alive.' - ); - } - }); - - test('throw if not content-type is not application/json', async () => { - expect.assertions(1); - - axiosMock.mockResolvedValue({ - status: 200, - headers: { - 'content-type': 'application/html', - }, - }); - try { - await serviceNow.getUserID(); - } catch (error) { - expect(error.message).toEqual( - '[Action][ServiceNow]: Unable to get user id. Error: [ServiceNow]: Instance is not alive.' - ); - } - }); - - test('check error when getting user', async () => { - expect.assertions(1); - - axiosMock.mockImplementationOnce(() => { - throw new Error('Bad request.'); - }); - try { - await serviceNow.getUserID(); - } catch (error) { - expect(error.message).toEqual( - '[Action][ServiceNow]: Unable to get user id. Error: Bad request.' - ); - } - }); - - test('check error when getting incident', async () => { - expect.assertions(1); - - axiosMock.mockImplementationOnce(() => { - throw new Error('Bad request.'); - }); - try { - await serviceNow.getIncident('123'); - } catch (error) { - expect(error.message).toEqual( - '[Action][ServiceNow]: Unable to get incident with id 123. Error: Bad request.' - ); - } - }); - - test('check error when creating incident', async () => { - expect.assertions(1); - - axiosMock.mockImplementationOnce(() => { - throw new Error('Bad request.'); - }); - try { - await serviceNow.createIncident({ short_description: 'title' }); - } catch (error) { - expect(error.message).toEqual( - '[Action][ServiceNow]: Unable to create incident. Error: Bad request.' - ); - } - }); - - test('check error when updating incident', async () => { - expect.assertions(1); - - axiosMock.mockImplementationOnce(() => { - throw new Error('Bad request.'); - }); - try { - await serviceNow.updateIncident('123', { short_description: 'title' }); - } catch (error) { - expect(error.message).toEqual( - '[Action][ServiceNow]: Unable to update incident with id 123. Error: Bad request.' - ); - } - }); - - test('check error when creating comment', async () => { - expect.assertions(1); - - axiosMock.mockImplementationOnce(() => { - throw new Error('Bad request.'); - }); - try { - await serviceNow.createComment( - '123', - { - commentId: '456', - version: 'WzU3LDFd', - comment: 'A second comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - }, - 'comment' - ); - } catch (error) { - expect(error.message).toEqual( - '[Action][ServiceNow]: Unable to create comment at incident with id 123. Error: Bad request.' - ); - } - }); -}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.ts deleted file mode 100644 index ed9cfe67a19a1..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/index.ts +++ /dev/null @@ -1,186 +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 axios, { AxiosInstance, Method, AxiosResponse } from 'axios'; - -import { INCIDENT_URL, USER_URL, COMMENT_URL, VIEW_INCIDENT_URL } from './constants'; -import { Instance, Incident, IncidentResponse, UpdateIncident, CommentResponse } from './types'; -import { Comment } from '../types'; - -const validStatusCodes = [200, 201]; - -class ServiceNow { - private readonly incidentUrl: string; - private readonly commentUrl: string; - private readonly userUrl: string; - private readonly axios: AxiosInstance; - - constructor(private readonly instance: Instance) { - if ( - !this.instance || - !this.instance.url || - !this.instance.username || - !this.instance.password - ) { - throw Error('[Action][ServiceNow]: Wrong configuration.'); - } - - this.incidentUrl = `${this.instance.url}/${INCIDENT_URL}`; - this.commentUrl = `${this.instance.url}/${COMMENT_URL}`; - this.userUrl = `${this.instance.url}/${USER_URL}`; - this.axios = axios.create({ - auth: { username: this.instance.username, password: this.instance.password }, - }); - } - - private _throwIfNotAlive(status: number, contentType: string) { - if (!validStatusCodes.includes(status) || !contentType.includes('application/json')) { - throw new Error('[ServiceNow]: Instance is not alive.'); - } - } - - private async _request({ - url, - method = 'get', - data = {}, - }: { - url: string; - method?: Method; - data?: unknown; - }): Promise { - const res = await this.axios(url, { method, data }); - this._throwIfNotAlive(res.status, res.headers['content-type']); - return res; - } - - private _patch({ url, data }: { url: string; data: unknown }): Promise { - return this._request({ - url, - method: 'patch', - data, - }); - } - - private _addTimeZoneToDate(date: string, timezone = 'GMT'): string { - return `${date} GMT`; - } - - private _getErrorMessage(msg: string) { - return `[Action][ServiceNow]: ${msg}`; - } - - private _getIncidentViewURL(id: string) { - return `${this.instance.url}/${VIEW_INCIDENT_URL}${id}`; - } - - async getUserID(): Promise { - try { - const res = await this._request({ url: `${this.userUrl}${this.instance.username}` }); - return res.data.result[0].sys_id; - } catch (error) { - throw new Error(this._getErrorMessage(`Unable to get user id. Error: ${error.message}`)); - } - } - - async getIncident(incidentId: string) { - try { - const res = await this._request({ - url: `${this.incidentUrl}/${incidentId}`, - }); - - return { ...res.data.result }; - } catch (error) { - throw new Error( - this._getErrorMessage( - `Unable to get incident with id ${incidentId}. Error: ${error.message}` - ) - ); - } - } - - async createIncident(incident: Incident): Promise { - try { - const res = await this._request({ - url: `${this.incidentUrl}`, - method: 'post', - data: { ...incident }, - }); - - return { - number: res.data.result.number, - incidentId: res.data.result.sys_id, - pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_created_on)).toISOString(), - url: this._getIncidentViewURL(res.data.result.sys_id), - }; - } catch (error) { - throw new Error(this._getErrorMessage(`Unable to create incident. Error: ${error.message}`)); - } - } - - async updateIncident(incidentId: string, incident: UpdateIncident): Promise { - try { - const res = await this._patch({ - url: `${this.incidentUrl}/${incidentId}`, - data: { ...incident }, - }); - - return { - number: res.data.result.number, - incidentId: res.data.result.sys_id, - pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_updated_on)).toISOString(), - url: this._getIncidentViewURL(res.data.result.sys_id), - }; - } catch (error) { - throw new Error( - this._getErrorMessage( - `Unable to update incident with id ${incidentId}. Error: ${error.message}` - ) - ); - } - } - - async batchCreateComments( - incidentId: string, - comments: Comment[], - field: string - ): Promise { - // Create comments sequentially. - const promises = comments.reduce(async (prevPromise, currentComment) => { - const totalComments = await prevPromise; - const res = await this.createComment(incidentId, currentComment, field); - return [...totalComments, res]; - }, Promise.resolve([] as CommentResponse[])); - - const res = await promises; - return res; - } - - async createComment( - incidentId: string, - comment: Comment, - field: string - ): Promise { - try { - const res = await this._patch({ - url: `${this.commentUrl}/${incidentId}`, - data: { [field]: comment.comment }, - }); - - return { - commentId: comment.commentId, - pushedDate: new Date(this._addTimeZoneToDate(res.data.result.sys_updated_on)).toISOString(), - }; - } catch (error) { - throw new Error( - this._getErrorMessage( - `Unable to create comment at incident with id ${incidentId}. Error: ${error.message}` - ) - ); - } - } -} - -export { ServiceNow }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/types.ts deleted file mode 100644 index a65e417dbc486..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/lib/types.ts +++ /dev/null @@ -1,32 +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 interface Instance { - url: string; - username: string; - password: string; -} - -export interface Incident { - short_description: string; - description?: string; - caller_id?: string; - [index: string]: string | undefined; -} - -export interface IncidentResponse { - number: string; - incidentId: string; - pushedDate: string; - url: string; -} - -export interface CommentResponse { - commentId: string; - pushedDate: string; -} - -export type UpdateIncident = Partial; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mock.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mock.ts deleted file mode 100644 index 06c006fb37825..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mock.ts +++ /dev/null @@ -1,115 +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 { MapEntry, Mapping, ExecutorParams } from './types'; -import { Incident } from './lib/types'; - -const mapping: MapEntry[] = [ - { source: 'title', target: 'short_description', actionType: 'overwrite' }, - { source: 'description', target: 'description', actionType: 'append' }, - { source: 'comments', target: 'comments', actionType: 'append' }, -]; - -const finalMapping: Mapping = new Map(); - -finalMapping.set('title', { - target: 'short_description', - actionType: 'overwrite', -}); - -finalMapping.set('description', { - target: 'description', - actionType: 'append', -}); - -finalMapping.set('comments', { - target: 'comments', - actionType: 'append', -}); - -finalMapping.set('short_description', { - target: 'title', - actionType: 'overwrite', -}); - -const params: ExecutorParams = { - caseId: 'd4387ac5-0899-4dc2-bbfa-0dd605c934aa', - incidentId: 'ceb5986e079f00100e48fbbf7c1ed06d', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: '2020-03-13T08:34:53.450Z', - updatedBy: { fullName: 'Elastic User', username: 'elastic' }, - title: 'Incident title', - description: 'Incident description', - comments: [ - { - commentId: 'b5b4c4d0-574e-11ea-9e2e-21b90f8a9631', - version: 'WzU3LDFd', - comment: 'A comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: '2020-03-13T08:34:53.450Z', - updatedBy: { fullName: 'Elastic User', username: 'elastic' }, - }, - { - commentId: 'e3db587f-ca27-4ae9-ad2e-31f2dcc9bd0d', - version: 'WlK3LDFd', - comment: 'Another comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: '2020-03-13T08:34:53.450Z', - updatedBy: { fullName: 'Elastic User', username: 'elastic' }, - }, - ], -}; - -const incidentResponse = { - incidentId: 'c816f79cc0a8016401c5a33be04be441', - number: 'INC0010001', - pushedDate: '2020-03-13T08:34:53.450Z', - url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', -}; - -const userId = '2e9a0a5e2f79001016ab51172799b670'; - -const axiosResponse = { - status: 200, - headers: { - 'content-type': 'application/json', - }, -}; -const userIdResponse = { - result: [{ sys_id: userId }], -}; - -const incidentAxiosResponse = { - result: { sys_id: incidentResponse.incidentId, number: incidentResponse.number }, -}; - -const instance = { - url: 'https://instance.service-now.com', - username: 'username', - password: 'password', -}; - -const incident: Incident = { - short_description: params.title, - description: params.description, - caller_id: userId, -}; - -export { - mapping, - finalMapping, - params, - incidentResponse, - incidentAxiosResponse, - userId, - userIdResponse, - axiosResponse, - instance, - incident, -}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts new file mode 100644 index 0000000000000..37228380910b3 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/mocks.ts @@ -0,0 +1,117 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + ExternalService, + PushToServiceApiParams, + ExecutorSubActionPushParams, + MapRecord, +} from '../case/types'; + +const createMock = (): jest.Mocked => { + const service = { + getIncident: jest.fn().mockImplementation(() => + Promise.resolve({ + short_description: 'title from servicenow', + description: 'description from servicenow', + }) + ), + createIncident: jest.fn().mockImplementation(() => + Promise.resolve({ + id: 'incident-1', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }) + ), + updateIncident: jest.fn().mockImplementation(() => + Promise.resolve({ + id: 'incident-2', + title: 'INC02', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://instance.service-now.com/nav_to.do?uri=incident.do?sys_id=123', + }) + ), + createComment: jest.fn(), + }; + + service.createComment.mockImplementationOnce(() => + Promise.resolve({ + commentId: 'case-comment-1', + pushedDate: '2020-03-10T12:24:20.000Z', + }) + ); + + service.createComment.mockImplementationOnce(() => + Promise.resolve({ + commentId: 'case-comment-2', + pushedDate: '2020-03-10T12:24:20.000Z', + }) + ); + return service; +}; + +const externalServiceMock = { + create: createMock, +}; + +const mapping: Map> = new Map(); + +mapping.set('title', { + target: 'short_description', + actionType: 'overwrite', +}); + +mapping.set('description', { + target: 'description', + actionType: 'overwrite', +}); + +mapping.set('comments', { + target: 'comments', + actionType: 'append', +}); + +mapping.set('short_description', { + target: 'title', + actionType: 'overwrite', +}); + +const executorParams: ExecutorSubActionPushParams = { + caseId: 'd4387ac5-0899-4dc2-bbfa-0dd605c934aa', + externalId: 'incident-3', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: '2020-03-13T08:34:53.450Z', + updatedBy: { fullName: 'Elastic User', username: 'elastic' }, + title: 'Incident title', + description: 'Incident description', + comments: [ + { + commentId: 'case-comment-1', + comment: 'A comment', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: '2020-03-13T08:34:53.450Z', + updatedBy: { fullName: 'Elastic User', username: 'elastic' }, + }, + { + commentId: 'case-comment-2', + comment: 'Another comment', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: '2020-03-13T08:34:53.450Z', + updatedBy: { fullName: 'Elastic User', username: 'elastic' }, + }, + ], +}; + +const apiParams: PushToServiceApiParams = { + ...executorParams, + externalCase: { short_description: 'Incident title', description: 'Incident description' }, +}; + +export { externalServiceMock, mapping, executorParams, apiParams }; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts deleted file mode 100644 index 889b57c8e92e2..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/schema.ts +++ /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 { schema } from '@kbn/config-schema'; - -export const MapEntrySchema = schema.object({ - source: schema.string(), - target: schema.string(), - actionType: schema.oneOf([ - schema.literal('nothing'), - schema.literal('overwrite'), - schema.literal('append'), - ]), -}); - -export const CasesConfigurationSchema = schema.object({ - mapping: schema.arrayOf(MapEntrySchema), -}); - -export const ConfigSchemaProps = { - apiUrl: schema.string(), - casesConfiguration: CasesConfigurationSchema, -}; - -export const ConfigSchema = schema.object(ConfigSchemaProps); - -export const SecretsSchemaProps = { - password: schema.string(), - username: schema.string(), -}; - -export const SecretsSchema = schema.object(SecretsSchemaProps); - -export const UserSchema = schema.object({ - fullName: schema.nullable(schema.string()), - username: schema.string(), -}); - -const EntityInformationSchemaProps = { - createdAt: schema.string(), - createdBy: UserSchema, - updatedAt: schema.nullable(schema.string()), - updatedBy: schema.nullable(UserSchema), -}; - -export const EntityInformationSchema = schema.object(EntityInformationSchemaProps); - -export const CommentSchema = schema.object({ - commentId: schema.string(), - comment: schema.string(), - version: schema.maybe(schema.string()), - ...EntityInformationSchemaProps, -}); - -export const ExecutorAction = schema.oneOf([ - schema.literal('newIncident'), - schema.literal('updateIncident'), -]); - -export const ParamsSchema = schema.object({ - caseId: schema.string(), - title: schema.string(), - comments: schema.maybe(schema.arrayOf(CommentSchema)), - description: schema.maybe(schema.string()), - incidentId: schema.nullable(schema.string()), - ...EntityInformationSchemaProps, -}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts new file mode 100644 index 0000000000000..f65cd5430560e --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.test.ts @@ -0,0 +1,255 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import axios from 'axios'; + +import { createExternalService } from './service'; +import * as utils from '../case/utils'; +import { ExternalService } from '../case/types'; + +jest.mock('axios'); +jest.mock('../case/utils', () => { + const originalUtils = jest.requireActual('../case/utils'); + return { + ...originalUtils, + request: jest.fn(), + patch: jest.fn(), + }; +}); + +axios.create = jest.fn(() => axios); +const requestMock = utils.request as jest.Mock; +const patchMock = utils.patch as jest.Mock; + +describe('ServiceNow service', () => { + let service: ExternalService; + + beforeAll(() => { + service = createExternalService({ + config: { apiUrl: 'https://dev102283.service-now.com' }, + secrets: { username: 'admin', password: 'admin' }, + }); + }); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + describe('createExternalService', () => { + test('throws without url', () => { + expect(() => + createExternalService({ + config: { apiUrl: null }, + secrets: { username: 'admin', password: 'admin' }, + }) + ).toThrow(); + }); + + test('throws without username', () => { + expect(() => + createExternalService({ + config: { apiUrl: 'test.com' }, + secrets: { username: '', password: 'admin' }, + }) + ).toThrow(); + }); + + test('throws without password', () => { + expect(() => + createExternalService({ + config: { apiUrl: 'test.com' }, + secrets: { username: '', password: undefined }, + }) + ).toThrow(); + }); + }); + + describe('getIncident', () => { + test('it returns the incident correctly', async () => { + requestMock.mockImplementation(() => ({ + data: { result: { sys_id: '1', number: 'INC01' } }, + })); + const res = await service.getIncident('1'); + expect(res).toEqual({ sys_id: '1', number: 'INC01' }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { result: { sys_id: '1', number: 'INC01' } }, + })); + + await service.getIncident('1'); + expect(requestMock).toHaveBeenCalledWith({ + axios, + url: 'https://dev102283.service-now.com/api/now/v2/table/incident/1', + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + expect(service.getIncident('1')).rejects.toThrow( + 'Unable to get incident with id 1. Error: An error has occurred' + ); + }); + }); + + describe('createIncident', () => { + test('it creates the incident correctly', async () => { + requestMock.mockImplementation(() => ({ + data: { result: { sys_id: '1', number: 'INC01', sys_created_on: '2020-03-10 12:24:20' } }, + })); + + const res = await service.createIncident({ + incident: { short_description: 'title', description: 'desc' }, + }); + + expect(res).toEqual({ + title: 'INC01', + id: '1', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://dev102283.service-now.com/nav_to.do?uri=incident.do?sys_id=1', + }); + }); + + test('it should call request with correct arguments', async () => { + requestMock.mockImplementation(() => ({ + data: { result: { sys_id: '1', number: 'INC01', sys_created_on: '2020-03-10 12:24:20' } }, + })); + + await service.createIncident({ + incident: { short_description: 'title', description: 'desc' }, + }); + + expect(requestMock).toHaveBeenCalledWith({ + axios, + url: 'https://dev102283.service-now.com/api/now/v2/table/incident', + method: 'post', + data: { short_description: 'title', description: 'desc' }, + }); + }); + + test('it should throw an error', async () => { + requestMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + + expect( + service.createIncident({ + incident: { short_description: 'title', description: 'desc' }, + }) + ).rejects.toThrow( + '[Action][ServiceNow]: Unable to create incident. Error: An error has occurred' + ); + }); + }); + + describe('updateIncident', () => { + test('it updates the incident correctly', async () => { + patchMock.mockImplementation(() => ({ + data: { result: { sys_id: '1', number: 'INC01', sys_updated_on: '2020-03-10 12:24:20' } }, + })); + + const res = await service.updateIncident({ + incidentId: '1', + incident: { short_description: 'title', description: 'desc' }, + }); + + expect(res).toEqual({ + title: 'INC01', + id: '1', + pushedDate: '2020-03-10T12:24:20.000Z', + url: 'https://dev102283.service-now.com/nav_to.do?uri=incident.do?sys_id=1', + }); + }); + + test('it should call request with correct arguments', async () => { + patchMock.mockImplementation(() => ({ + data: { result: { sys_id: '1', number: 'INC01', sys_updated_on: '2020-03-10 12:24:20' } }, + })); + + await service.updateIncident({ + incidentId: '1', + incident: { short_description: 'title', description: 'desc' }, + }); + + expect(patchMock).toHaveBeenCalledWith({ + axios, + url: 'https://dev102283.service-now.com/api/now/v2/table/incident/1', + data: { short_description: 'title', description: 'desc' }, + }); + }); + + test('it should throw an error', async () => { + patchMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + + expect( + service.updateIncident({ + incidentId: '1', + incident: { short_description: 'title', description: 'desc' }, + }) + ).rejects.toThrow( + '[Action][ServiceNow]: Unable to update incident with id 1. Error: An error has occurred' + ); + }); + }); + + describe('createComment', () => { + test('it creates the comment correctly', async () => { + patchMock.mockImplementation(() => ({ + data: { result: { sys_id: '1', number: 'INC01', sys_updated_on: '2020-03-10 12:24:20' } }, + })); + + const res = await service.createComment({ + incidentId: '1', + comment: { comment: 'comment', commentId: 'comment-1' }, + field: 'comments', + }); + + expect(res).toEqual({ + commentId: 'comment-1', + pushedDate: '2020-03-10T12:24:20.000Z', + }); + }); + + test('it should call request with correct arguments', async () => { + patchMock.mockImplementation(() => ({ + data: { result: { sys_id: '1', number: 'INC01', sys_updated_on: '2020-03-10 12:24:20' } }, + })); + + await service.createComment({ + incidentId: '1', + comment: { comment: 'comment', commentId: 'comment-1' }, + field: 'my_field', + }); + + expect(patchMock).toHaveBeenCalledWith({ + axios, + url: 'https://dev102283.service-now.com/api/now/v2/table/incident/1', + data: { my_field: 'comment' }, + }); + }); + + test('it should throw an error', async () => { + patchMock.mockImplementation(() => { + throw new Error('An error has occurred'); + }); + + expect( + service.createComment({ + incidentId: '1', + comment: { comment: 'comment', commentId: 'comment-1' }, + field: 'comments', + }) + ).rejects.toThrow( + '[Action][ServiceNow]: Unable to create comment at incident with id 1. Error: An error has occurred' + ); + }); + }); +}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts new file mode 100644 index 0000000000000..541fefce2f2ff --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/service.ts @@ -0,0 +1,138 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import axios from 'axios'; + +import { ExternalServiceCredentials, ExternalService, ExternalServiceParams } from '../case/types'; +import { addTimeZoneToDate, patch, request, getErrorMessage } from '../case/utils'; + +import * as i18n from './translations'; +import { + ServiceNowPublicConfigurationType, + ServiceNowSecretConfigurationType, + CreateIncidentRequest, + UpdateIncidentRequest, + CreateCommentRequest, +} from './types'; + +const API_VERSION = 'v2'; +const INCIDENT_URL = `api/now/${API_VERSION}/table/incident`; +const COMMENT_URL = `api/now/${API_VERSION}/table/incident`; + +// Based on: https://docs.servicenow.com/bundle/orlando-platform-user-interface/page/use/navigation/reference/r_NavigatingByURLExamples.html +const VIEW_INCIDENT_URL = `nav_to.do?uri=incident.do?sys_id=`; + +export const createExternalService = ({ + config, + secrets, +}: ExternalServiceCredentials): ExternalService => { + const { apiUrl: url } = config as ServiceNowPublicConfigurationType; + const { username, password } = secrets as ServiceNowSecretConfigurationType; + + if (!url || !username || !password) { + throw Error(`[Action]${i18n.NAME}: Wrong configuration.`); + } + + const incidentUrl = `${url}/${INCIDENT_URL}`; + const commentUrl = `${url}/${COMMENT_URL}`; + const axiosInstance = axios.create({ + auth: { username, password }, + }); + + const getIncidentViewURL = (id: string) => { + return `${url}/${VIEW_INCIDENT_URL}${id}`; + }; + + const getIncident = async (id: string) => { + try { + const res = await request({ + axios: axiosInstance, + url: `${incidentUrl}/${id}`, + }); + + return { ...res.data.result }; + } catch (error) { + throw new Error( + getErrorMessage(i18n.NAME, `Unable to get incident with id ${id}. Error: ${error.message}`) + ); + } + }; + + const createIncident = async ({ incident }: ExternalServiceParams) => { + try { + const res = await request({ + axios: axiosInstance, + url: `${incidentUrl}`, + method: 'post', + data: { ...incident }, + }); + + return { + title: res.data.result.number, + id: res.data.result.sys_id, + pushedDate: new Date(addTimeZoneToDate(res.data.result.sys_created_on)).toISOString(), + url: getIncidentViewURL(res.data.result.sys_id), + }; + } catch (error) { + throw new Error( + getErrorMessage(i18n.NAME, `Unable to create incident. Error: ${error.message}`) + ); + } + }; + + const updateIncident = async ({ incidentId, incident }: ExternalServiceParams) => { + try { + const res = await patch({ + axios: axiosInstance, + url: `${incidentUrl}/${incidentId}`, + data: { ...incident }, + }); + + return { + title: res.data.result.number, + id: res.data.result.sys_id, + pushedDate: new Date(addTimeZoneToDate(res.data.result.sys_updated_on)).toISOString(), + url: getIncidentViewURL(res.data.result.sys_id), + }; + } catch (error) { + throw new Error( + getErrorMessage( + i18n.NAME, + `Unable to update incident with id ${incidentId}. Error: ${error.message}` + ) + ); + } + }; + + const createComment = async ({ incidentId, comment, field }: ExternalServiceParams) => { + try { + const res = await patch({ + axios: axiosInstance, + url: `${commentUrl}/${incidentId}`, + data: { [field]: comment.comment }, + }); + + return { + commentId: comment.commentId, + pushedDate: new Date(addTimeZoneToDate(res.data.result.sys_updated_on)).toISOString(), + }; + } catch (error) { + throw new Error( + getErrorMessage( + i18n.NAME, + `Unable to create comment at incident with id ${incidentId}. Error: ${error.message}` + ) + ); + } + }; + + return { + getIncident, + createIncident, + updateIncident, + createComment, + }; +}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/transformers.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/transformers.ts deleted file mode 100644 index dc0a03fab8c71..0000000000000 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/transformers.ts +++ /dev/null @@ -1,43 +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 { TransformerArgs } from './types'; -import * as i18n from './translations'; - -export const informationCreated = ({ - value, - date, - user, - ...rest -}: TransformerArgs): TransformerArgs => ({ - value: `${value} ${i18n.FIELD_INFORMATION('create', date, user)}`, - ...rest, -}); - -export const informationUpdated = ({ - value, - date, - user, - ...rest -}: TransformerArgs): TransformerArgs => ({ - value: `${value} ${i18n.FIELD_INFORMATION('update', date, user)}`, - ...rest, -}); - -export const informationAdded = ({ - value, - date, - user, - ...rest -}: TransformerArgs): TransformerArgs => ({ - value: `${value} ${i18n.FIELD_INFORMATION('add', date, user)}`, - ...rest, -}); - -export const append = ({ value, previousValue, ...rest }: TransformerArgs): TransformerArgs => ({ - value: previousValue ? `${previousValue} \r\n${value}` : `${value}`, - ...rest, -}); diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts index 3b216a6c3260a..3d6138169c4cc 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/translations.ts @@ -6,77 +6,6 @@ import { i18n } from '@kbn/i18n'; -export const API_URL_REQUIRED = i18n.translate( - 'xpack.actions.builtin.servicenow.servicenowApiNullError', - { - defaultMessage: 'ServiceNow [apiUrl] is required', - } -); - -export const WHITE_LISTED_ERROR = (message: string) => - i18n.translate('xpack.actions.builtin.servicenow.servicenowApiWhitelistError', { - defaultMessage: 'error configuring servicenow action: {message}', - values: { - message, - }, - }); - -export const NAME = i18n.translate('xpack.actions.builtin.servicenowTitle', { +export const NAME = i18n.translate('xpack.actions.builtin.case.servicenowTitle', { defaultMessage: 'ServiceNow', }); - -export const MAPPING_EMPTY = i18n.translate('xpack.actions.builtin.servicenow.emptyMapping', { - defaultMessage: '[casesConfiguration.mapping]: expected non-empty but got empty', -}); - -export const ERROR_POSTING = i18n.translate( - 'xpack.actions.builtin.servicenow.postingErrorMessage', - { - defaultMessage: 'error posting servicenow event', - } -); - -export const RETRY_POSTING = (status: number) => - i18n.translate('xpack.actions.builtin.servicenow.postingRetryErrorMessage', { - defaultMessage: 'error posting servicenow event: http status {status}, retry later', - values: { - status, - }, - }); - -export const UNEXPECTED_STATUS = (status: number) => - i18n.translate('xpack.actions.builtin.servicenow.postingUnexpectedErrorMessage', { - defaultMessage: 'error posting servicenow event: unexpected status {status}', - values: { - status, - }, - }); - -export const FIELD_INFORMATION = ( - mode: string, - date: string | undefined, - user: string | undefined -) => { - switch (mode) { - case 'create': - return i18n.translate('xpack.actions.builtin.servicenow.informationCreated', { - values: { date, user }, - defaultMessage: '(created at {date} by {user})', - }); - case 'update': - return i18n.translate('xpack.actions.builtin.servicenow.informationUpdated', { - values: { date, user }, - defaultMessage: '(updated at {date} by {user})', - }); - case 'add': - return i18n.translate('xpack.actions.builtin.servicenow.informationAdded', { - values: { date, user }, - defaultMessage: '(added at {date} by {user})', - }); - default: - return i18n.translate('xpack.actions.builtin.servicenow.informationDefault', { - values: { date, user }, - defaultMessage: '(created at {date} by {user})', - }); - } -}; diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts index c5ef282aeffa7..d8476b7dca54a 100644 --- a/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/types.ts @@ -4,100 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { TypeOf } from '@kbn/config-schema'; +export { + ExternalIncidentServiceConfiguration as ServiceNowPublicConfigurationType, + ExternalIncidentServiceSecretConfiguration as ServiceNowSecretConfigurationType, +} from '../case/types'; -import { - ConfigSchema, - SecretsSchema, - ParamsSchema, - CasesConfigurationSchema, - MapEntrySchema, - CommentSchema, -} from './schema'; - -import { ServiceNow } from './lib'; -import { Incident, IncidentResponse } from './lib/types'; - -// config definition -export type ConfigType = TypeOf; - -// secrets definition -export type SecretsType = TypeOf; - -export type ExecutorParams = TypeOf; - -export type CasesConfigurationType = TypeOf; -export type MapEntry = TypeOf; -export type Comment = TypeOf; - -export type Mapping = Map>; - -export interface Params extends ExecutorParams { - incident: Record; +export interface CreateIncidentRequest { + summary: string; + description: string; } -export interface CreateHandlerArguments { - serviceNow: ServiceNow; - params: Params; - comments: Comment[]; - mapping: Mapping; -} - -export type UpdateHandlerArguments = CreateHandlerArguments & { - incidentId: string; -}; - -export type IncidentHandlerArguments = CreateHandlerArguments & { - incidentId: string | null; -}; -export interface HandlerResponse extends IncidentResponse { - comments?: SimpleComment[]; -} - -export interface SimpleComment { - commentId: string; - pushedDate: string; -} - -export interface AppendFieldArgs { - value: string; - prefix?: string; - suffix?: string; -} - -export interface KeyAny { - [index: string]: unknown; -} - -export interface AppendInformationFieldArgs { - value: string; - user: string; - date: string; - mode: string; -} - -export interface TransformerArgs { - value: string; - date?: string; - user?: string; - previousValue?: string; -} - -export interface PrepareFieldsForTransformArgs { - params: Params; - mapping: Mapping; - defaultPipes?: string[]; -} - -export interface PipedField { - key: string; - value: string; - actionType: string; - pipes: string[]; -} +export type UpdateIncidentRequest = Partial; -export interface TransformFieldsArgs { - params: Params; - fields: PipedField[]; - currentIncident?: Incident; +export interface CreateCommentRequest { + [key: string]: string; } diff --git a/x-pack/plugins/actions/server/builtin_action_types/servicenow/validators.ts b/x-pack/plugins/actions/server/builtin_action_types/servicenow/validators.ts new file mode 100644 index 0000000000000..7226071392bc6 --- /dev/null +++ b/x-pack/plugins/actions/server/builtin_action_types/servicenow/validators.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { validateCommonConfig, validateCommonSecrets } from '../case/validators'; +import { ExternalServiceValidation } from '../case/types'; + +export const validate: ExternalServiceValidation = { + config: validateCommonConfig, + secrets: validateCommonSecrets, +}; diff --git a/x-pack/plugins/case/common/api/cases/case.ts b/x-pack/plugins/case/common/api/cases/case.ts index 1f08a41024905..d1bcae549805e 100644 --- a/x-pack/plugins/case/common/api/cases/case.ts +++ b/x-pack/plugins/case/common/api/cases/case.ts @@ -127,35 +127,34 @@ export const ServiceConnectorCommentParamsRt = rt.type({ updatedBy: rt.union([ServiceConnectorUserParams, rt.null]), }); -export const ServiceConnectorCaseParamsRt = rt.intersection([ - rt.type({ - caseId: rt.string, - createdAt: rt.string, - createdBy: ServiceConnectorUserParams, - incidentId: rt.union([rt.string, rt.null]), - title: rt.string, - updatedAt: rt.union([rt.string, rt.null]), - updatedBy: rt.union([ServiceConnectorUserParams, rt.null]), - }), - rt.partial({ - description: rt.string, - comments: rt.array(ServiceConnectorCommentParamsRt), - }), -]); +export const ServiceConnectorCaseParamsRt = rt.type({ + caseId: rt.string, + createdAt: rt.string, + createdBy: ServiceConnectorUserParams, + externalId: rt.union([rt.string, rt.null]), + title: rt.string, + updatedAt: rt.union([rt.string, rt.null]), + updatedBy: rt.union([ServiceConnectorUserParams, rt.null]), + description: rt.union([rt.string, rt.null]), + comments: rt.union([rt.array(ServiceConnectorCommentParamsRt), rt.null]), +}); export const ServiceConnectorCaseResponseRt = rt.intersection([ rt.type({ - number: rt.string, - incidentId: rt.string, + title: rt.string, + id: rt.string, pushedDate: rt.string, url: rt.string, }), rt.partial({ comments: rt.array( - rt.type({ - commentId: rt.string, - pushedDate: rt.string, - }) + rt.intersection([ + rt.type({ + commentId: rt.string, + pushedDate: rt.string, + }), + rt.partial({ externalCommentId: rt.string }), + ]) ), }), ]); diff --git a/x-pack/plugins/case/common/constants.ts b/x-pack/plugins/case/common/constants.ts index dcfa46bfa6019..855a5c3d63507 100644 --- a/x-pack/plugins/case/common/constants.ts +++ b/x-pack/plugins/case/common/constants.ts @@ -27,3 +27,5 @@ export const CASE_USER_ACTIONS_URL = `${CASE_DETAILS_URL}/user_actions`; export const ACTION_URL = '/api/action'; export const ACTION_TYPES_URL = '/api/action/types'; + +export const SUPPORTED_CONNECTORS = ['.servicenow', '.jira']; diff --git a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts index 00575655d4c42..43167d56de015 100644 --- a/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts +++ b/x-pack/plugins/case/server/routes/api/cases/configure/get_connectors.ts @@ -8,14 +8,15 @@ import Boom from 'boom'; import { RouteDeps } from '../../types'; import { wrapError } from '../../utils'; -import { CASE_CONFIGURE_CONNECTORS_URL } from '../../../../../common/constants'; +import { + CASE_CONFIGURE_CONNECTORS_URL, + SUPPORTED_CONNECTORS, +} from '../../../../../common/constants'; /* * Be aware that this api will only return 20 connectors */ -const CASE_SERVICE_NOW_ACTION = '.servicenow'; - export function initCaseConfigureGetActionConnector({ caseService, router }: RouteDeps) { router.get( { @@ -30,8 +31,8 @@ export function initCaseConfigureGetActionConnector({ caseService, router }: Rou throw Boom.notFound('Action client have not been found'); } - const results = (await actionsClient.getAll()).filter( - action => action.actionTypeId === CASE_SERVICE_NOW_ACTION + const results = (await actionsClient.getAll()).filter(action => + SUPPORTED_CONNECTORS.includes(action.actionTypeId) ); return response.ok({ body: results }); } catch (error) { diff --git a/x-pack/plugins/siem/public/containers/case/api.test.tsx b/x-pack/plugins/siem/public/containers/case/api.test.tsx index ad61e2b46f6c5..174738098fa10 100644 --- a/x-pack/plugins/siem/public/containers/case/api.test.tsx +++ b/x-pack/plugins/siem/public/containers/case/api.test.tsx @@ -418,7 +418,9 @@ describe('Case Configuration API', () => { await pushToService(connectorId, casePushParams, abortCtrl.signal); expect(fetchMock).toHaveBeenCalledWith(`/api/action/${connectorId}/_execute`, { method: 'POST', - body: JSON.stringify({ params: casePushParams }), + body: JSON.stringify({ + params: { subAction: 'pushToService', subActionParams: casePushParams }, + }), signal: abortCtrl.signal, }); }); diff --git a/x-pack/plugins/siem/public/containers/case/api.ts b/x-pack/plugins/siem/public/containers/case/api.ts index b97f94a5a6b59..438eae9d88a44 100644 --- a/x-pack/plugins/siem/public/containers/case/api.ts +++ b/x-pack/plugins/siem/public/containers/case/api.ts @@ -245,7 +245,9 @@ export const pushToService = async ( `${ACTION_URL}/${connectorId}/_execute`, { method: 'POST', - body: JSON.stringify({ params: casePushParams }), + body: JSON.stringify({ + params: { subAction: 'pushToService', subActionParams: casePushParams }, + }), signal, } ); diff --git a/x-pack/plugins/siem/public/containers/case/mock.ts b/x-pack/plugins/siem/public/containers/case/mock.ts index 0f44b3a1594ba..a3a8db2c40950 100644 --- a/x-pack/plugins/siem/public/containers/case/mock.ts +++ b/x-pack/plugins/siem/public/containers/case/mock.ts @@ -103,8 +103,8 @@ export const pushedCase: Case = { }; export const serviceConnector: ServiceConnectorCaseResponse = { - number: '123', - incidentId: '444', + title: '123', + id: '444', pushedDate: basicUpdatedAt, url: 'connector.com', comments: [ @@ -129,12 +129,13 @@ export const casePushParams = { caseId: basicCaseId, createdAt: basicCreatedAt, createdBy: elasticUser, - incidentId: null, + externalId: null, title: 'what a cool value', commentId: null, updatedAt: basicCreatedAt, updatedBy: elasticUser, description: 'nice', + comments: null, }; export const actionTypeExecutorResult = { actionId: 'string', diff --git a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.test.tsx b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.test.tsx index b07a346a8da46..b9698c3e864e3 100644 --- a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.test.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.test.tsx @@ -55,8 +55,8 @@ describe('usePostPushToService', () => { { connector_id: samplePush.connectorId, connector_name: samplePush.connectorName, - external_id: serviceConnector.incidentId, - external_title: serviceConnector.number, + external_id: serviceConnector.id, + external_title: serviceConnector.title, external_url: serviceConnector.url, }, abortCtrl.signal diff --git a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx index acd4b92ee430d..c9d1b963f411a 100644 --- a/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx +++ b/x-pack/plugins/siem/public/containers/case/use_post_push_to_service.tsx @@ -98,8 +98,8 @@ export const usePostPushToService = (): UsePostPushToService => { { connector_id: connectorId, connector_name: connectorName, - external_id: responseService.incidentId, - external_title: responseService.number, + external_id: responseService.id, + external_title: responseService.title, external_url: responseService.url, }, abortCtrl.signal @@ -180,7 +180,7 @@ export const formatServiceRequestData = (myCase: Case): ServiceConnectorCasePara : null, })), description, - incidentId: externalService?.externalId ?? null, + externalId: externalService?.externalId ?? null, title, updatedAt, updatedBy: diff --git a/x-pack/plugins/siem/public/lib/connectors/components/connector_flyout/index.tsx b/x-pack/plugins/siem/public/lib/connectors/components/connector_flyout/index.tsx new file mode 100644 index 0000000000000..c5a35da56284d --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/components/connector_flyout/index.tsx @@ -0,0 +1,148 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useCallback, useEffect } from 'react'; +import { EuiFieldText, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiSpacer } from '@elastic/eui'; + +import { isEmpty, get } from 'lodash/fp'; + +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ActionConnectorFieldsProps } from '../../../../../../triggers_actions_ui/public/types'; +import { FieldMapping } from '../../../../pages/case/components/configure_cases/field_mapping'; + +import { defaultMapping } from '../../config'; +import { CasesConfigurationMapping } from '../../../../containers/case/configure/types'; + +import * as i18n from '../../translations'; +import { ActionConnector, ConnectorFlyoutHOCProps } from '../../types'; + +export const withConnectorFlyout = ({ + ConnectorFormComponent, + secretKeys = [], + configKeys = [], +}: ConnectorFlyoutHOCProps) => { + const ConnectorFlyout: React.FC> = ({ + action, + editActionConfig, + editActionSecrets, + errors, + }) => { + /* We do not provide defaults values to the fields (like empty string for apiUrl) intentionally. + * If we do, errors will be shown the first time the flyout is open even though the user did not + * interact with the form. Also, we would like to show errors for empty fields provided by the user. + /*/ + const { apiUrl, casesConfiguration: { mapping = [] } = {} } = action.config; + const configKeysWithDefault = [...configKeys, 'apiUrl']; + + const isApiUrlInvalid: boolean = errors.apiUrl.length > 0 && apiUrl != null; + + /** + * We need to distinguish between the add flyout and the edit flyout. + * useEffect will run only once on component mount. + * This guarantees that the function below will run only once. + * On the first render of the component the apiUrl can be either undefined or filled. + * If it is filled then we are on the edit flyout. Otherwise we are on the add flyout. + */ + + useEffect(() => { + if (!isEmpty(apiUrl)) { + secretKeys.forEach((key: string) => editActionSecrets(key, '')); + } + }, []); + + if (isEmpty(mapping)) { + editActionConfig('casesConfiguration', { + ...action.config.casesConfiguration, + mapping: defaultMapping, + }); + } + + const handleOnChangeActionConfig = useCallback( + (key: string, value: string) => editActionConfig(key, value), + [] + ); + + const handleOnBlurActionConfig = useCallback( + (key: string) => { + if (configKeysWithDefault.includes(key) && get(key, action.config) == null) { + editActionConfig(key, ''); + } + }, + [action.config] + ); + + const handleOnChangeSecretConfig = useCallback( + (key: string, value: string) => editActionSecrets(key, value), + [] + ); + + const handleOnBlurSecretConfig = useCallback( + (key: string) => { + if (secretKeys.includes(key) && get(key, action.secrets) == null) { + editActionSecrets(key, ''); + } + }, + [action.secrets] + ); + + const handleOnChangeMappingConfig = useCallback( + (newMapping: CasesConfigurationMapping[]) => + editActionConfig('casesConfiguration', { + ...action.config.casesConfiguration, + mapping: newMapping, + }), + [action.config] + ); + + return ( + <> + + + + handleOnChangeActionConfig('apiUrl', evt.target.value)} + onBlur={handleOnBlurActionConfig.bind(null, 'apiUrl')} + /> + + + + + + + + + + + + + ); + }; + + return ConnectorFlyout; +}; diff --git a/x-pack/plugins/siem/public/lib/connectors/config.ts b/x-pack/plugins/siem/public/lib/connectors/config.ts index baeb69b3f6943..98473e49622a9 100644 --- a/x-pack/plugins/siem/public/lib/connectors/config.ts +++ b/x-pack/plugins/siem/public/lib/connectors/config.ts @@ -5,17 +5,17 @@ */ import { CasesConfigurationMapping } from '../../containers/case/configure/types'; -import serviceNowLogo from './logos/servicenow.svg'; + import { Connector } from './types'; +import { connector as serviceNowConnectorConfig } from './servicenow/config'; +import { connector as jiraConnectorConfig } from './jira/config'; -const connectors: Record = { - '.servicenow': { - actionTypeId: '.servicenow', - logo: serviceNowLogo, - }, +export const connectorsConfiguration: Record = { + '.servicenow': serviceNowConnectorConfig, + '.jira': jiraConnectorConfig, }; -const defaultMapping: CasesConfigurationMapping[] = [ +export const defaultMapping: CasesConfigurationMapping[] = [ { source: 'title', target: 'short_description', @@ -32,5 +32,3 @@ const defaultMapping: CasesConfigurationMapping[] = [ actionType: 'append', }, ]; - -export { connectors, defaultMapping }; diff --git a/x-pack/plugins/siem/public/lib/connectors/index.ts b/x-pack/plugins/siem/public/lib/connectors/index.ts index fdf337b5ef120..2ce61bef49c5e 100644 --- a/x-pack/plugins/siem/public/lib/connectors/index.ts +++ b/x-pack/plugins/siem/public/lib/connectors/index.ts @@ -5,3 +5,4 @@ */ export { getActionType as serviceNowActionType } from './servicenow'; +export { getActionType as jiraActionType } from './jira'; diff --git a/x-pack/plugins/siem/public/lib/connectors/jira/config.ts b/x-pack/plugins/siem/public/lib/connectors/jira/config.ts new file mode 100644 index 0000000000000..42bd1b9cdc191 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/jira/config.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 { Connector } from '../types'; + +import { JIRA_TITLE } from './translations'; +import logo from './logo.svg'; + +export const connector: Connector = { + id: '.jira', + name: JIRA_TITLE, + logo, + enabled: true, + enabledInConfig: true, + enabledInLicense: true, + minimumLicenseRequired: 'platinum', +}; diff --git a/x-pack/plugins/siem/public/lib/connectors/jira/flyout.tsx b/x-pack/plugins/siem/public/lib/connectors/jira/flyout.tsx new file mode 100644 index 0000000000000..482808fca53b1 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/jira/flyout.tsx @@ -0,0 +1,110 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import React from 'react'; +import { + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiFieldPassword, + EuiSpacer, +} from '@elastic/eui'; + +import * as i18n from './translations'; +import { ConnectorFlyoutFormProps } from '../types'; +import { JiraActionConnector } from './types'; +import { withConnectorFlyout } from '../components/connector_flyout'; + +const JiraConnectorForm: React.FC> = ({ + errors, + action, + onChangeSecret, + onBlurSecret, + onChangeConfig, + onBlurConfig, +}) => { + const { projectKey } = action.config; + const { email, apiToken } = action.secrets; + const isProjectKeyInvalid: boolean = errors.projectKey.length > 0 && projectKey != null; + const isEmailInvalid: boolean = errors.email.length > 0 && email != null; + const isApiTokenInvalid: boolean = errors.apiToken.length > 0 && apiToken != null; + + return ( + <> + + + + onChangeConfig('projectKey', evt.target.value)} + onBlur={() => onBlurConfig('projectKey')} + /> + + + + + + + + onChangeSecret('email', evt.target.value)} + onBlur={() => onBlurSecret('email')} + /> + + + + + + + + onChangeSecret('apiToken', evt.target.value)} + onBlur={() => onBlurSecret('apiToken')} + /> + + + + + ); +}; + +export const JiraConnectorFlyout = withConnectorFlyout({ + ConnectorFormComponent: JiraConnectorForm, + secretKeys: ['email', 'apiToken'], + configKeys: ['projectKey'], +}); diff --git a/x-pack/plugins/siem/public/lib/connectors/jira/index.tsx b/x-pack/plugins/siem/public/lib/connectors/jira/index.tsx new file mode 100644 index 0000000000000..ada9608e37c98 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/jira/index.tsx @@ -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 { + ValidationResult, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../triggers_actions_ui/public/types'; + +import { connector } from './config'; +import { createActionType } from '../utils'; +import logo from './logo.svg'; +import { JiraActionConnector } from './types'; +import { JiraConnectorFlyout } from './flyout'; +import * as i18n from './translations'; + +interface Errors { + projectKey: string[]; + email: string[]; + apiToken: string[]; +} + +const validateConnector = (action: JiraActionConnector): ValidationResult => { + const errors: Errors = { + projectKey: [], + email: [], + apiToken: [], + }; + + if (!action.config.projectKey) { + errors.projectKey = [...errors.projectKey, i18n.JIRA_PROJECT_KEY_REQUIRED]; + } + + if (!action.secrets.email) { + errors.email = [...errors.email, i18n.EMAIL_REQUIRED]; + } + + if (!action.secrets.apiToken) { + errors.apiToken = [...errors.apiToken, i18n.API_TOKEN_REQUIRED]; + } + + return { errors }; +}; + +export const getActionType = createActionType({ + id: connector.id, + iconClass: logo, + selectMessage: i18n.JIRA_DESC, + actionTypeTitle: connector.name, + validateConnector, + actionConnectorFields: JiraConnectorFlyout, +}); diff --git a/x-pack/plugins/siem/public/lib/connectors/logos/servicenow.svg b/x-pack/plugins/siem/public/lib/connectors/jira/logo.svg old mode 100755 new mode 100644 similarity index 100% rename from x-pack/plugins/siem/public/lib/connectors/logos/servicenow.svg rename to x-pack/plugins/siem/public/lib/connectors/jira/logo.svg diff --git a/x-pack/plugins/siem/public/lib/connectors/jira/translations.ts b/x-pack/plugins/siem/public/lib/connectors/jira/translations.ts new file mode 100644 index 0000000000000..751aaecdad964 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/jira/translations.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 { i18n } from '@kbn/i18n'; + +export * from '../translations'; + +export const JIRA_DESC = i18n.translate('xpack.siem.case.connectors.jira.selectMessageText', { + defaultMessage: 'Push or update SIEM case data to a new issue in Jira', +}); + +export const JIRA_TITLE = i18n.translate('xpack.siem.case.connectors.jira.actionTypeTitle', { + defaultMessage: 'Jira', +}); + +export const JIRA_PROJECT_KEY_LABEL = i18n.translate('xpack.siem.case.connectors.jira.projectKey', { + defaultMessage: 'Project key', +}); + +export const JIRA_PROJECT_KEY_REQUIRED = i18n.translate( + 'xpack.siem.case.connectors.jira.requiredProjectKeyTextField', + { + defaultMessage: 'Project key is required', + } +); diff --git a/x-pack/plugins/siem/public/lib/connectors/jira/types.ts b/x-pack/plugins/siem/public/lib/connectors/jira/types.ts new file mode 100644 index 0000000000000..13e4e8f6a289e --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/jira/types.ts @@ -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. + */ + +/* eslint-disable no-restricted-imports */ +/* eslint-disable @kbn/eslint/no-restricted-paths */ + +import { + JiraPublicConfigurationType, + JiraSecretConfigurationType, +} from '../../../../../actions/server/builtin_action_types/jira/types'; + +export interface JiraActionConnector { + config: JiraPublicConfigurationType; + secrets: JiraSecretConfigurationType; +} diff --git a/x-pack/plugins/siem/public/lib/connectors/servicenow.tsx b/x-pack/plugins/siem/public/lib/connectors/servicenow.tsx deleted file mode 100644 index 9fe0b4a957ceb..0000000000000 --- a/x-pack/plugins/siem/public/lib/connectors/servicenow.tsx +++ /dev/null @@ -1,246 +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, { useCallback, ChangeEvent, useEffect } from 'react'; -import { - EuiFieldText, - EuiFlexGroup, - EuiFlexItem, - EuiFormRow, - EuiFieldPassword, - EuiSpacer, -} from '@elastic/eui'; - -import { isEmpty, get } from 'lodash/fp'; - -import { - ActionConnectorFieldsProps, - ActionTypeModel, - ValidationResult, - ActionParamsProps, - // eslint-disable-next-line @kbn/eslint/no-restricted-paths -} from '../../../../triggers_actions_ui/public/types'; - -import { FieldMapping } from '../../pages/case/components/configure_cases/field_mapping'; - -import * as i18n from './translations'; - -import { ServiceNowActionConnector } from './types'; -import { isUrlInvalid } from './validators'; - -import { connectors, defaultMapping } from './config'; -import { CasesConfigurationMapping } from '../../containers/case/configure/types'; - -const serviceNowDefinition = connectors['.servicenow']; - -interface ServiceNowActionParams { - message: string; -} - -interface Errors { - apiUrl: string[]; - username: string[]; - password: string[]; -} - -export function getActionType(): ActionTypeModel { - return { - id: serviceNowDefinition.actionTypeId, - iconClass: serviceNowDefinition.logo, - selectMessage: i18n.SERVICENOW_DESC, - actionTypeTitle: i18n.SERVICENOW_TITLE, - validateConnector: (action: ServiceNowActionConnector): ValidationResult => { - const errors: Errors = { - apiUrl: [], - username: [], - password: [], - }; - - if (!action.config.apiUrl) { - errors.apiUrl = [...errors.apiUrl, i18n.SERVICENOW_API_URL_REQUIRED]; - } - - if (isUrlInvalid(action.config.apiUrl)) { - errors.apiUrl = [...errors.apiUrl, i18n.SERVICENOW_API_URL_INVALID]; - } - - if (!action.secrets.username) { - errors.username = [...errors.username, i18n.SERVICENOW_USERNAME_REQUIRED]; - } - - if (!action.secrets.password) { - errors.password = [...errors.password, i18n.SERVICENOW_PASSWORD_REQUIRED]; - } - - return { errors }; - }, - validateParams: (actionParams: ServiceNowActionParams): ValidationResult => { - return { errors: {} }; - }, - actionConnectorFields: ServiceNowConnectorFields, - actionParamsFields: ServiceNowParamsFields, - }; -} - -const ServiceNowConnectorFields: React.FunctionComponent> = ({ action, editActionConfig, editActionSecrets, errors }) => { - /* We do not provide defaults values to the fields (like empty string for apiUrl) intentionally. - * If we do, errors will be shown the first time the flyout is open even though the user did not - * interact with the form. Also, we would like to show errors for empty fields provided by the user. - /*/ - const { apiUrl, casesConfiguration: { mapping = [] } = {} } = action.config; - const { username, password } = action.secrets; - - const isApiUrlInvalid: boolean = errors.apiUrl.length > 0 && apiUrl != null; - const isUsernameInvalid: boolean = errors.username.length > 0 && username != null; - const isPasswordInvalid: boolean = errors.password.length > 0 && password != null; - - /** - * We need to distinguish between the add flyout and the edit flyout. - * useEffect will run only once on component mount. - * This guarantees that the function below will run only once. - * On the first render of the component the apiUrl can be either undefined or filled. - * If it is filled then we are on the edit flyout. Otherwise we are on the add flyout. - */ - - useEffect(() => { - if (!isEmpty(apiUrl)) { - editActionSecrets('username', ''); - editActionSecrets('password', ''); - } - }, []); - - if (isEmpty(mapping)) { - editActionConfig('casesConfiguration', { - ...action.config.casesConfiguration, - mapping: defaultMapping, - }); - } - - const handleOnChangeActionConfig = useCallback( - (key: string, evt: ChangeEvent) => editActionConfig(key, evt.target.value), - [] - ); - - const handleOnBlurActionConfig = useCallback( - (key: string) => { - if (key === 'apiUrl' && action.config[key] == null) { - editActionConfig(key, ''); - } - }, - [action.config] - ); - - const handleOnChangeSecretConfig = useCallback( - (key: string, evt: ChangeEvent) => editActionSecrets(key, evt.target.value), - [] - ); - - const handleOnBlurSecretConfig = useCallback( - (key: string) => { - if (['username', 'password'].includes(key) && get(key, action.secrets) == null) { - editActionSecrets(key, ''); - } - }, - [action.secrets] - ); - - const handleOnChangeMappingConfig = useCallback( - (newMapping: CasesConfigurationMapping[]) => - editActionConfig('casesConfiguration', { - ...action.config.casesConfiguration, - mapping: newMapping, - }), - [action.config] - ); - - return ( - <> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); -}; - -const ServiceNowParamsFields: React.FunctionComponent> = ({ actionParams, editAction, index, errors }) => { - return null; -}; diff --git a/x-pack/plugins/siem/public/lib/connectors/servicenow/config.ts b/x-pack/plugins/siem/public/lib/connectors/servicenow/config.ts new file mode 100644 index 0000000000000..7bc1b117b3422 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/servicenow/config.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 { Connector } from '../types'; + +import { SERVICENOW_TITLE } from './translations'; +import logo from './logo.svg'; + +export const connector: Connector = { + id: '.servicenow', + name: SERVICENOW_TITLE, + logo, + enabled: true, + enabledInConfig: true, + enabledInLicense: true, + minimumLicenseRequired: 'platinum', +}; diff --git a/x-pack/plugins/siem/public/lib/connectors/servicenow/flyout.tsx b/x-pack/plugins/siem/public/lib/connectors/servicenow/flyout.tsx new file mode 100644 index 0000000000000..bcde802e7bd1e --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/servicenow/flyout.tsx @@ -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 React from 'react'; +import { + EuiFieldText, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiFieldPassword, + EuiSpacer, +} from '@elastic/eui'; + +import * as i18n from './translations'; +import { ConnectorFlyoutFormProps } from '../types'; +import { ServiceNowActionConnector } from './types'; +import { withConnectorFlyout } from '../components/connector_flyout'; + +const ServiceNowConnectorForm: React.FC> = ({ + errors, + action, + onChangeSecret, + onBlurSecret, +}) => { + const { username, password } = action.secrets; + const isUsernameInvalid: boolean = errors.username.length > 0 && username != null; + const isPasswordInvalid: boolean = errors.password.length > 0 && password != null; + + return ( + <> + + + + onChangeSecret('username', evt.target.value)} + onBlur={() => onBlurSecret('username')} + /> + + + + + + + + onChangeSecret('password', evt.target.value)} + onBlur={() => onBlurSecret('password')} + /> + + + + + ); +}; + +export const ServiceNowConnectorFlyout = withConnectorFlyout({ + ConnectorFormComponent: ServiceNowConnectorForm, + secretKeys: ['username', 'password'], +}); diff --git a/x-pack/plugins/siem/public/lib/connectors/servicenow/index.tsx b/x-pack/plugins/siem/public/lib/connectors/servicenow/index.tsx new file mode 100644 index 0000000000000..1f8e61b6d3ea7 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/servicenow/index.tsx @@ -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 { + ValidationResult, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../triggers_actions_ui/public/types'; + +import { connector } from './config'; +import { createActionType } from '../utils'; +import logo from './logo.svg'; +import { ServiceNowActionConnector } from './types'; +import { ServiceNowConnectorFlyout } from './flyout'; +import * as i18n from './translations'; + +interface Errors { + username: string[]; + password: string[]; +} + +const validateConnector = (action: ServiceNowActionConnector): ValidationResult => { + const errors: Errors = { + username: [], + password: [], + }; + + if (!action.secrets.username) { + errors.username = [...errors.username, i18n.USERNAME_REQUIRED]; + } + + if (!action.secrets.password) { + errors.password = [...errors.password, i18n.PASSWORD_REQUIRED]; + } + + return { errors }; +}; + +export const getActionType = createActionType({ + id: connector.id, + iconClass: logo, + selectMessage: i18n.SERVICENOW_DESC, + actionTypeTitle: connector.name, + validateConnector, + actionConnectorFields: ServiceNowConnectorFlyout, +}); diff --git a/x-pack/plugins/siem/public/lib/connectors/servicenow/logo.svg b/x-pack/plugins/siem/public/lib/connectors/servicenow/logo.svg new file mode 100644 index 0000000000000..dcd022a8dca18 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/servicenow/logo.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/x-pack/plugins/siem/public/lib/connectors/servicenow/translations.ts b/x-pack/plugins/siem/public/lib/connectors/servicenow/translations.ts new file mode 100644 index 0000000000000..5dac9eddd1536 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/servicenow/translations.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 { i18n } from '@kbn/i18n'; + +export * from '../translations'; + +export const SERVICENOW_DESC = i18n.translate( + 'xpack.siem.case.connectors.servicenow.selectMessageText', + { + defaultMessage: 'Push or update SIEM case data to a new incident in ServiceNow', + } +); + +export const SERVICENOW_TITLE = i18n.translate( + 'xpack.siem.case.connectors.servicenow.actionTypeTitle', + { + defaultMessage: 'ServiceNow', + } +); diff --git a/x-pack/plugins/siem/public/lib/connectors/servicenow/types.ts b/x-pack/plugins/siem/public/lib/connectors/servicenow/types.ts new file mode 100644 index 0000000000000..b7f0e79eb37e3 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/servicenow/types.ts @@ -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. + */ + +/* eslint-disable no-restricted-imports */ +/* eslint-disable @kbn/eslint/no-restricted-paths */ + +import { + ServiceNowPublicConfigurationType, + ServiceNowSecretConfigurationType, +} from '../../../../../actions/server/builtin_action_types/servicenow/types'; + +export interface ServiceNowActionConnector { + config: ServiceNowPublicConfigurationType; + secrets: ServiceNowSecretConfigurationType; +} diff --git a/x-pack/plugins/siem/public/lib/connectors/translations.ts b/x-pack/plugins/siem/public/lib/connectors/translations.ts index ae2084120255c..b9c1d0fa2a17f 100644 --- a/x-pack/plugins/siem/public/lib/connectors/translations.ts +++ b/x-pack/plugins/siem/public/lib/connectors/translations.ts @@ -6,65 +6,76 @@ import { i18n } from '@kbn/i18n'; -export const SERVICENOW_DESC = i18n.translate( - 'xpack.siem.case.connectors.servicenow.selectMessageText', +export const API_URL_LABEL = i18n.translate( + 'xpack.siem.case.connectors.common.apiUrlTextFieldLabel', { - defaultMessage: 'Push or update SIEM case data to a new incident in ServiceNow', + defaultMessage: 'URL', } ); -export const SERVICENOW_TITLE = i18n.translate( - 'xpack.siem.case.connectors.servicenow.actionTypeTitle', +export const API_URL_REQUIRED = i18n.translate( + 'xpack.siem.case.connectors.common.requiredApiUrlTextField', { - defaultMessage: 'ServiceNow', + defaultMessage: 'URL is required', } ); -export const SERVICENOW_API_URL_LABEL = i18n.translate( - 'xpack.siem.case.connectors.servicenow.apiUrlTextFieldLabel', +export const API_URL_INVALID = i18n.translate( + 'xpack.siem.case.connectors.common.invalidApiUrlTextField', { - defaultMessage: 'URL', + defaultMessage: 'URL is invalid', } ); -export const SERVICENOW_API_URL_REQUIRED = i18n.translate( - 'xpack.siem.case.connectors.servicenow.requiredApiUrlTextField', +export const USERNAME_LABEL = i18n.translate( + 'xpack.siem.case.connectors.common.usernameTextFieldLabel', { - defaultMessage: 'URL is required', + defaultMessage: 'Username', } ); -export const SERVICENOW_API_URL_INVALID = i18n.translate( - 'xpack.siem.case.connectors.servicenow.invalidApiUrlTextField', +export const USERNAME_REQUIRED = i18n.translate( + 'xpack.siem.case.connectors.common.requiredUsernameTextField', { - defaultMessage: 'URL is invalid', + defaultMessage: 'Username is required', } ); -export const SERVICENOW_USERNAME_LABEL = i18n.translate( - 'xpack.siem.case.connectors.servicenow.usernameTextFieldLabel', +export const PASSWORD_LABEL = i18n.translate( + 'xpack.siem.case.connectors.common.passwordTextFieldLabel', { - defaultMessage: 'Username', + defaultMessage: 'Password', } ); -export const SERVICENOW_USERNAME_REQUIRED = i18n.translate( - 'xpack.siem.case.connectors.servicenow.requiredUsernameTextField', +export const PASSWORD_REQUIRED = i18n.translate( + 'xpack.siem.case.connectors.common.requiredPasswordTextField', { - defaultMessage: 'Username is required', + defaultMessage: 'Password is required', } ); -export const SERVICENOW_PASSWORD_LABEL = i18n.translate( - 'xpack.siem.case.connectors.servicenow.passwordTextFieldLabel', +export const API_TOKEN_LABEL = i18n.translate( + 'xpack.siem.case.connectors.common.apiTokenTextFieldLabel', { - defaultMessage: 'Password', + defaultMessage: 'Api token', } ); -export const SERVICENOW_PASSWORD_REQUIRED = i18n.translate( - 'xpack.siem.case.connectors.servicenow.requiredPasswordTextField', +export const API_TOKEN_REQUIRED = i18n.translate( + 'xpack.siem.case.connectors.common.requiredApiTokenTextField', { - defaultMessage: 'Password is required', + defaultMessage: 'Api token is required', + } +); + +export const EMAIL_LABEL = i18n.translate('xpack.siem.case.connectors.common.emailTextFieldLabel', { + defaultMessage: 'Email', +}); + +export const EMAIL_REQUIRED = i18n.translate( + 'xpack.siem.case.connectors.common.requiredEmailTextField', + { + defaultMessage: 'Email is required', } ); diff --git a/x-pack/plugins/siem/public/lib/connectors/types.ts b/x-pack/plugins/siem/public/lib/connectors/types.ts index 2def4b5107aee..9af60f4995e54 100644 --- a/x-pack/plugins/siem/public/lib/connectors/types.ts +++ b/x-pack/plugins/siem/public/lib/connectors/types.ts @@ -7,17 +7,39 @@ /* eslint-disable no-restricted-imports */ /* eslint-disable @kbn/eslint/no-restricted-paths */ -import { - ConfigType, - SecretsType, -} from '../../../../actions/server/builtin_action_types/servicenow/types'; - -export interface ServiceNowActionConnector { - config: ConfigType; - secrets: SecretsType; -} +import { ActionType } from '../../../../triggers_actions_ui/public'; +import { ExternalIncidentServiceConfiguration } from '../../../../actions/server/builtin_action_types/case/types'; -export interface Connector { - actionTypeId: string; +export interface Connector extends ActionType { logo: string; } + +export interface ActionConnector { + config: ExternalIncidentServiceConfiguration; + secrets: {}; +} + +export interface ActionConnectorParams { + message: string; +} + +export interface ActionConnectorValidationErrors { + apiUrl: string[]; +} + +export type Optional = Omit & Partial; + +export interface ConnectorFlyoutFormProps { + errors: { [key: string]: string[] }; + action: T; + onChangeSecret: (key: string, value: string) => void; + onBlurSecret: (key: string) => void; + onChangeConfig: (key: string, value: string) => void; + onBlurConfig: (key: string) => void; +} + +export interface ConnectorFlyoutHOCProps { + ConnectorFormComponent: React.FC>; + configKeys?: string[]; + secretKeys?: string[]; +} diff --git a/x-pack/plugins/siem/public/lib/connectors/utils.ts b/x-pack/plugins/siem/public/lib/connectors/utils.ts new file mode 100644 index 0000000000000..5b5270ade5a65 --- /dev/null +++ b/x-pack/plugins/siem/public/lib/connectors/utils.ts @@ -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 { + ActionTypeModel, + ValidationResult, + ActionParamsProps, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../triggers_actions_ui/public/types'; + +import { + ActionConnector, + ActionConnectorParams, + ActionConnectorValidationErrors, + Optional, +} from './types'; +import { isUrlInvalid } from './validators'; + +import * as i18n from './translations'; + +export const createActionType = ({ + id, + actionTypeTitle, + selectMessage, + iconClass, + validateConnector, + validateParams = connectorParamsValidator, + actionConnectorFields, + actionParamsFields = ConnectorParamsFields, +}: Optional) => (): ActionTypeModel => { + return { + id, + iconClass, + selectMessage, + actionTypeTitle, + validateConnector: (action: ActionConnector): ValidationResult => { + const errors: ActionConnectorValidationErrors = { + apiUrl: [], + }; + + if (!action.config.apiUrl) { + errors.apiUrl = [...errors.apiUrl, i18n.API_URL_REQUIRED]; + } + + if (isUrlInvalid(action.config.apiUrl)) { + errors.apiUrl = [...errors.apiUrl, i18n.API_URL_INVALID]; + } + + return { errors: { ...errors, ...validateConnector(action).errors } }; + }, + validateParams, + actionConnectorFields, + actionParamsFields, + }; +}; + +const ConnectorParamsFields: React.FunctionComponent> = ({ + actionParams, + editAction, + index, + errors, +}) => { + return null; +}; + +const connectorParamsValidator = (actionParams: ActionConnectorParams): ValidationResult => { + return { errors: {} }; +}; diff --git a/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors_dropdown.tsx b/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors_dropdown.tsx index 15066e73eee82..d5575f3bac4c8 100644 --- a/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors_dropdown.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/configure_cases/connectors_dropdown.tsx @@ -9,7 +9,7 @@ import { EuiIcon, EuiSuperSelect } from '@elastic/eui'; import styled from 'styled-components'; import { Connector } from '../../../../containers/case/configure/types'; -import { connectors as connectorsDefinition } from '../../../../lib/connectors/config'; +import { connectorsConfiguration } from '../../../../lib/connectors/config'; import * as i18n from './translations'; export interface Props { @@ -54,7 +54,7 @@ const ConnectorsDropdownComponent: React.FC = ({ inputDisplay: ( <> {connector.name} diff --git a/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx b/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx index 545eceb0f73a1..fde179f3d25fc 100644 --- a/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.test.tsx @@ -186,6 +186,16 @@ describe('ConfigureCases', () => { id: '.servicenow', name: 'ServiceNow', enabled: true, + logo: 'test-file-stub', + enabledInConfig: true, + enabledInLicense: true, + minimumLicenseRequired: 'platinum', + }, + { + id: '.jira', + name: 'Jira', + logo: 'test-file-stub', + enabled: true, enabledInConfig: true, enabledInLicense: true, minimumLicenseRequired: 'platinum', diff --git a/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.tsx b/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.tsx index a970fe895eb71..66eef9e3ec7bf 100644 --- a/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.tsx +++ b/x-pack/plugins/siem/public/pages/case/components/configure_cases/index.tsx @@ -32,6 +32,8 @@ import { ActionConnectorTableItem } from '../../../../../../triggers_actions_ui/ import { getCaseUrl } from '../../../../components/link_to'; import { useGetUrlSearch } from '../../../../components/navigation/use_get_url_search'; import { CCMapsCombinedActionAttributes } from '../../../../containers/case/configure/types'; +import { connectorsConfiguration } from '../../../../lib/connectors/config'; + import { Connectors } from '../configure_cases/connectors'; import { ClosureOptions } from '../configure_cases/closure_options'; import { Mapping } from '../configure_cases/mapping'; @@ -54,16 +56,7 @@ const FormWrapper = styled.div` `} `; -const actionTypes: ActionType[] = [ - { - id: '.servicenow', - name: 'ServiceNow', - enabled: true, - enabledInConfig: true, - enabledInLicense: true, - minimumLicenseRequired: 'platinum', - }, -]; +const actionTypes: ActionType[] = Object.values(connectorsConfiguration); interface ConfigureCasesComponentProps { userCanCrud: boolean; diff --git a/x-pack/plugins/siem/public/plugin.tsx b/x-pack/plugins/siem/public/plugin.tsx index f9c44bd341fac..2f2bd70569dcd 100644 --- a/x-pack/plugins/siem/public/plugin.tsx +++ b/x-pack/plugins/siem/public/plugin.tsx @@ -31,7 +31,7 @@ import { SecurityPluginSetup } from '../../security/public'; import { APP_ID, APP_NAME, APP_PATH, APP_ICON } from '../common/constants'; import { initTelemetry } from './lib/telemetry'; import { KibanaServices } from './lib/kibana/services'; -import { serviceNowActionType } from './lib/connectors'; +import { serviceNowActionType, jiraActionType } from './lib/connectors'; export interface SetupPlugins { home: HomePublicPluginSetup; @@ -84,6 +84,7 @@ export class Plugin implements IPlugin getExternalServiceSimulatorPath(service) ); + allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.SERVICENOW}/api/now/v2/table/incident`); + allPaths.push(`/api/_${NAME}/${ExternalServiceSimulator.JIRA}/rest/api/2/issue`); return allPaths; } @@ -78,9 +82,10 @@ export default function(kibana: any) { }); initPagerduty(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.PAGERDUTY)); - initServiceNow(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.SERVICENOW)); initSlack(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.SLACK)); initWebhook(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.WEBHOOK)); + initServiceNow(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.SERVICENOW)); + initJira(server, getExternalServiceSimulatorPath(ExternalServiceSimulator.JIRA)); }, }); } diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/jira_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/jira_simulation.ts new file mode 100644 index 0000000000000..629d0197b2292 --- /dev/null +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/jira_simulation.ts @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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'; + +interface JiraRequest extends Hapi.Request { + payload: { + summary: string; + description?: string; + comments?: string; + }; +} +export function initPlugin(server: Hapi.Server, path: string) { + server.route({ + method: 'POST', + path: `${path}/rest/api/2/issue`, + options: { + auth: false, + }, + handler: createHandler as Hapi.Lifecycle.Method, + }); + + server.route({ + method: 'PUT', + path: `${path}/rest/api/2/issue/{id}`, + options: { + auth: false, + }, + handler: updateHandler as Hapi.Lifecycle.Method, + }); + + server.route({ + method: 'GET', + path: `${path}/rest/api/2/issue/{id}`, + options: { + auth: false, + }, + handler: getHandler as Hapi.Lifecycle.Method, + }); + + server.route({ + method: 'POST', + path: `${path}/rest/api/2/issue/{id}/comment`, + options: { + auth: false, + }, + handler: createCommentHanlder as Hapi.Lifecycle.Method, + }); +} + +// ServiceNow simulator: create a servicenow action pointing here, and you can get +// different responses based on the message posted. See the README.md for +// more info. +function createHandler(request: JiraRequest, h: any) { + return jsonResponse(h, 200, { + id: '123', + key: 'CK-1', + created: '2020-04-27T14:17:45.490Z', + }); +} + +function updateHandler(request: JiraRequest, h: any) { + return jsonResponse(h, 200, { + id: '123', + key: 'CK-1', + created: '2020-04-27T14:17:45.490Z', + updated: '2020-04-27T14:17:45.490Z', + }); +} + +function getHandler(request: JiraRequest, h: any) { + return jsonResponse(h, 200, { + id: '123', + key: 'CK-1', + created: '2020-04-27T14:17:45.490Z', + updated: '2020-04-27T14:17:45.490Z', + summary: 'title', + description: 'description', + }); +} + +function createCommentHanlder(request: JiraRequest, h: any) { + return jsonResponse(h, 200, { + id: '123', + created: '2020-04-27T14:17:45.490Z', + }); +} + +function jsonResponse(h: any, code: number, object?: any) { + if (object == null) { + return h.response('').code(code); + } + + return h + .response(JSON.stringify(object)) + .type('application/json') + .code(code); +} diff --git a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts index a58738e387aeb..cc9521369a47d 100644 --- a/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts +++ b/x-pack/test/alerting_api_integration/common/fixtures/plugins/actions_simulators/servicenow_simulation.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import Joi from 'joi'; import Hapi from 'hapi'; interface ServiceNowRequest extends Hapi.Request { @@ -29,18 +28,13 @@ export function initPlugin(server: Hapi.Server, path: string) { path: `${path}/api/now/v2/table/incident/{id}`, options: { auth: false, - validate: { - params: Joi.object({ - id: Joi.string(), - }), - }, }, handler: updateHandler as Hapi.Lifecycle.Method, }); server.route({ method: 'GET', - path: `${path}/api/now/v2/table/incident`, + path: `${path}/api/now/v2/table/incident/{id}`, options: { auth: false, }, diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts new file mode 100644 index 0000000000000..ed63d25d86aca --- /dev/null +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/jira.ts @@ -0,0 +1,549 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { FtrProviderContext } from '../../../../common/ftr_provider_context'; + +import { + getExternalServiceSimulatorPath, + ExternalServiceSimulator, +} from '../../../../common/fixtures/plugins/actions_simulators'; + +const mapping = [ + { + source: 'title', + target: 'summary', + actionType: 'overwrite', + }, + { + source: 'description', + target: 'description', + actionType: 'overwrite', + }, + { + source: 'comments', + target: 'comments', + actionType: 'append', + }, +]; + +// eslint-disable-next-line import/no-default-export +export default function jiraTest({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); + + const mockJira = { + config: { + apiUrl: 'www.jiraisinkibanaactions.com', + projectKey: 'CK', + casesConfiguration: { mapping }, + }, + secrets: { + apiToken: 'elastic', + email: 'elastic@elastic.co', + }, + params: { + subAction: 'pushToService', + subActionParams: { + caseId: '123', + title: 'a title', + description: 'a description', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: null, + updatedBy: null, + externalId: null, + comments: [ + { + commentId: '456', + version: 'WzU3LDFd', + comment: 'first comment', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: null, + updatedBy: null, + }, + ], + }, + }, + }; + + let jiraSimulatorURL: string = ''; + + describe('Jira', () => { + before(() => { + jiraSimulatorURL = kibanaServer.resolveUrl( + getExternalServiceSimulatorPath(ExternalServiceSimulator.JIRA) + ); + }); + + after(() => esArchiver.unload('empty_kibana')); + + describe('Jira - Action Creation', () => { + it('should return 200 when creating a jira action successfully', async () => { + const { body: createdAction } = await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { + ...mockJira.config, + apiUrl: jiraSimulatorURL, + }, + secrets: mockJira.secrets, + }) + .expect(200); + + expect(createdAction).to.eql({ + id: createdAction.id, + isPreconfigured: false, + name: 'A jira action', + actionTypeId: '.jira', + config: { + apiUrl: jiraSimulatorURL, + projectKey: mockJira.config.projectKey, + casesConfiguration: mockJira.config.casesConfiguration, + }, + }); + + const { body: fetchedAction } = await supertest + .get(`/api/action/${createdAction.id}`) + .expect(200); + + expect(fetchedAction).to.eql({ + id: fetchedAction.id, + isPreconfigured: false, + name: 'A jira action', + actionTypeId: '.jira', + config: { + apiUrl: jiraSimulatorURL, + projectKey: mockJira.config.projectKey, + casesConfiguration: mockJira.config.casesConfiguration, + }, + }); + }); + + it('should respond with a 400 Bad Request when creating a jira action with no apiUrl', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { projectKey: 'CK' }, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: [apiUrl]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should respond with a 400 Bad Request when creating a jira action with no projectKey', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { apiUrl: jiraSimulatorURL }, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: [projectKey]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should respond with a 400 Bad Request when creating a jira action with a non whitelisted apiUrl', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { + apiUrl: 'http://jira.mynonexistent.com', + projectKey: mockJira.config.projectKey, + casesConfiguration: mockJira.config.casesConfiguration, + }, + secrets: mockJira.secrets, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: error configuring connector action: target url "http://jira.mynonexistent.com" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts', + }); + }); + }); + + it('should respond with a 400 Bad Request when creating a jira action without secrets', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { + apiUrl: jiraSimulatorURL, + projectKey: mockJira.config.projectKey, + casesConfiguration: mockJira.config.casesConfiguration, + }, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type secrets: [email]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should respond with a 400 Bad Request when creating a jira action without casesConfiguration', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { + apiUrl: jiraSimulatorURL, + projectKey: mockJira.config.projectKey, + }, + secrets: mockJira.secrets, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: [casesConfiguration.mapping]: expected value of type [array] but got [undefined]', + }); + }); + }); + + it('should respond with a 400 Bad Request when creating a jira action with empty mapping', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { + apiUrl: jiraSimulatorURL, + projectKey: mockJira.config.projectKey, + casesConfiguration: { mapping: [] }, + }, + secrets: mockJira.secrets, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: [casesConfiguration.mapping]: expected non-empty but got empty', + }); + }); + }); + + it('should respond with a 400 Bad Request when creating a jira action with wrong actionType', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira action', + actionTypeId: '.jira', + config: { + apiUrl: jiraSimulatorURL, + projectKey: mockJira.config.projectKey, + casesConfiguration: { + mapping: [ + { + source: 'title', + target: 'description', + actionType: 'non-supported', + }, + ], + }, + }, + secrets: mockJira.secrets, + }) + .expect(400); + }); + }); + + describe('Jira - Executor', () => { + let simulatedActionId: string; + before(async () => { + const { body } = await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A jira simulator', + actionTypeId: '.jira', + config: { + apiUrl: jiraSimulatorURL, + projectKey: mockJira.config.projectKey, + casesConfiguration: mockJira.config.casesConfiguration, + }, + secrets: mockJira.secrets, + }); + simulatedActionId = body.id; + }); + + describe('Validation', () => { + it('should handle failing with a simulated success without action', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: {}, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: `error validating action params: Cannot read property 'Symbol(Symbol.iterator)' of undefined`, + }); + }); + }); + + it('should handle failing with a simulated success without unsupported action', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { subAction: 'non-supported' }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]', + }); + }); + }); + + it('should handle failing with a simulated success without subActionParams', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { subAction: 'pushToService' }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.caseId]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should handle failing with a simulated success without caseId', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { subAction: 'pushToService', subActionParams: {} }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.caseId]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should handle failing with a simulated success without title', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockJira.params, + subActionParams: { + caseId: 'success', + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should handle failing with a simulated success without createdAt', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockJira.params, + subActionParams: { + caseId: 'success', + title: 'success', + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.createdAt]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should handle failing with a simulated success without commentId', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockJira.params, + subActionParams: { + ...mockJira.params.subActionParams, + caseId: 'success', + title: 'success', + createdAt: 'success', + createdBy: { username: 'elastic' }, + comments: [{}], + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', + }); + }); + }); + + it('should handle failing with a simulated success without comment message', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockJira.params, + subActionParams: { + ...mockJira.params.subActionParams, + caseId: 'success', + title: 'success', + createdAt: 'success', + createdBy: { username: 'elastic' }, + comments: [{ commentId: 'success' }], + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', + }); + }); + }); + + it('should handle failing with a simulated success without comment.createdAt', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockJira.params, + subActionParams: { + ...mockJira.params.subActionParams, + caseId: 'success', + title: 'success', + createdAt: 'success', + createdBy: { username: 'elastic' }, + comments: [{ commentId: 'success', comment: 'success' }], + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.createdAt]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', + }); + }); + }); + }); + + describe('Execution', () => { + it('should handle creating an incident without comments', async () => { + const { body } = await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockJira.params, + subActionParams: { + ...mockJira.params.subActionParams, + comments: [], + }, + }, + }) + .expect(200); + + expect(body).to.eql({ + status: 'ok', + actionId: simulatedActionId, + data: { + id: '123', + title: 'CK-1', + pushedDate: '2020-04-27T14:17:45.490Z', + url: `${jiraSimulatorURL}/browse/CK-1`, + }, + }); + }); + }); + }); + }); +} diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts index 399ae0f27f5b1..04cd06999f432 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/builtin_action_types/servicenow.ts @@ -13,8 +13,6 @@ import { ExternalServiceSimulator, } from '../../../../common/fixtures/plugins/actions_simulators'; -// node ../scripts/functional_test_runner.js --grep "servicenow" --config=test/alerting_api_integration/security_and_spaces/config.ts - const mapping = [ { source: 'title', @@ -24,7 +22,7 @@ const mapping = [ { source: 'description', target: 'description', - actionType: 'append', + actionType: 'overwrite', }, { source: 'comments', @@ -42,40 +40,41 @@ export default function servicenowTest({ getService }: FtrProviderContext) { const mockServiceNow = { config: { apiUrl: 'www.servicenowisinkibanaactions.com', - casesConfiguration: { mapping: [...mapping] }, + casesConfiguration: { mapping }, }, secrets: { password: 'elastic', username: 'changeme', }, params: { - caseId: '123', - title: 'a title', - description: 'a description', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - incidentId: null, - comments: [ - { - commentId: '456', - version: 'WzU3LDFd', - comment: 'first comment', - createdAt: '2020-03-13T08:34:53.450Z', - createdBy: { fullName: 'Elastic User', username: 'elastic' }, - updatedAt: null, - updatedBy: null, - }, - ], + subAction: 'pushToService', + subActionParams: { + caseId: '123', + title: 'a title', + description: 'a description', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: null, + updatedBy: null, + externalId: null, + comments: [ + { + commentId: '456', + version: 'WzU3LDFd', + comment: 'first comment', + createdAt: '2020-03-13T08:34:53.450Z', + createdBy: { fullName: 'Elastic User', username: 'elastic' }, + updatedAt: null, + updatedBy: null, + }, + ], + }, }, }; - describe('servicenow', () => { - let simulatedActionId = ''; - let servicenowSimulatorURL: string = ''; + let servicenowSimulatorURL: string = ''; - // need to wait for kibanaServer to settle ... + describe('ServiceNow', () => { before(() => { servicenowSimulatorURL = kibanaServer.resolveUrl( getExternalServiceSimulatorPath(ExternalServiceSimulator.SERVICENOW) @@ -84,351 +83,438 @@ export default function servicenowTest({ getService }: FtrProviderContext) { after(() => esArchiver.unload('empty_kibana')); - it('should return 200 when creating a servicenow action successfully', async () => { - const { body: createdAction } = await supertest - .post('/api/action') - .set('kbn-xsrf', 'foo') - .send({ + describe('ServiceNow - Action Creation', () => { + it('should return 200 when creating a servicenow action successfully', async () => { + const { body: createdAction } = await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A servicenow action', + actionTypeId: '.servicenow', + config: { + apiUrl: servicenowSimulatorURL, + casesConfiguration: mockServiceNow.config.casesConfiguration, + }, + secrets: mockServiceNow.secrets, + }) + .expect(200); + + expect(createdAction).to.eql({ + id: createdAction.id, + isPreconfigured: false, name: 'A servicenow action', actionTypeId: '.servicenow', config: { apiUrl: servicenowSimulatorURL, - casesConfiguration: { ...mockServiceNow.config.casesConfiguration }, + casesConfiguration: mockServiceNow.config.casesConfiguration, }, - secrets: { ...mockServiceNow.secrets }, - }) - .expect(200); - - expect(createdAction).to.eql({ - id: createdAction.id, - isPreconfigured: false, - name: 'A servicenow action', - actionTypeId: '.servicenow', - config: { - apiUrl: servicenowSimulatorURL, - casesConfiguration: { ...mockServiceNow.config.casesConfiguration }, - }, - }); - - expect(typeof createdAction.id).to.be('string'); - - const { body: fetchedAction } = await supertest - .get(`/api/action/${createdAction.id}`) - .expect(200); - - expect(fetchedAction).to.eql({ - id: fetchedAction.id, - isPreconfigured: false, - name: 'A servicenow action', - actionTypeId: '.servicenow', - config: { - apiUrl: servicenowSimulatorURL, - casesConfiguration: { ...mockServiceNow.config.casesConfiguration }, - }, - }); - }); - - it('should respond with a 400 Bad Request when creating a servicenow action with no apiUrl', async () => { - await supertest - .post('/api/action') - .set('kbn-xsrf', 'foo') - .send({ - name: 'A servicenow action', - actionTypeId: '.servicenow', - config: {}, - }) - .expect(400) - .then((resp: any) => { - expect(resp.body).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: - 'error validating action type config: [apiUrl]: expected value of type [string] but got [undefined]', - }); }); - }); - it('should respond with a 400 Bad Request when creating a servicenow action with a non whitelisted apiUrl', async () => { - await supertest - .post('/api/action') - .set('kbn-xsrf', 'foo') - .send({ - name: 'A servicenow action', - actionTypeId: '.servicenow', - config: { - apiUrl: 'http://servicenow.mynonexistent.com', - casesConfiguration: { ...mockServiceNow.config.casesConfiguration }, - }, - secrets: { ...mockServiceNow.secrets }, - }) - .expect(400) - .then((resp: any) => { - expect(resp.body).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: - 'error validating action type config: error configuring servicenow action: target url "http://servicenow.mynonexistent.com" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts', - }); - }); - }); + const { body: fetchedAction } = await supertest + .get(`/api/action/${createdAction.id}`) + .expect(200); - it('should respond with a 400 Bad Request when creating a servicenow action without secrets', async () => { - await supertest - .post('/api/action') - .set('kbn-xsrf', 'foo') - .send({ + expect(fetchedAction).to.eql({ + id: fetchedAction.id, + isPreconfigured: false, name: 'A servicenow action', actionTypeId: '.servicenow', config: { apiUrl: servicenowSimulatorURL, - casesConfiguration: { ...mockServiceNow.config.casesConfiguration }, + casesConfiguration: mockServiceNow.config.casesConfiguration, }, - }) - .expect(400) - .then((resp: any) => { - expect(resp.body).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: - 'error validating action type secrets: [password]: expected value of type [string] but got [undefined]', - }); }); - }); + }); - it('should respond with a 400 Bad Request when creating a servicenow action without casesConfiguration', async () => { - await supertest - .post('/api/action') - .set('kbn-xsrf', 'foo') - .send({ - name: 'A servicenow action', - actionTypeId: '.servicenow', - config: { - apiUrl: servicenowSimulatorURL, - }, - secrets: { ...mockServiceNow.secrets }, - }) - .expect(400) - .then((resp: any) => { - expect(resp.body).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: - 'error validating action type config: [casesConfiguration.mapping]: expected value of type [array] but got [undefined]', + it('should respond with a 400 Bad Request when creating a servicenow action with no apiUrl', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A servicenow action', + actionTypeId: '.servicenow', + config: {}, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: [apiUrl]: expected value of type [string] but got [undefined]', + }); }); - }); - }); + }); - it('should respond with a 400 Bad Request when creating a servicenow action with empty mapping', async () => { - await supertest - .post('/api/action') - .set('kbn-xsrf', 'foo') - .send({ - name: 'A servicenow action', - actionTypeId: '.servicenow', - config: { - apiUrl: servicenowSimulatorURL, - casesConfiguration: { mapping: [] }, - }, - secrets: { ...mockServiceNow.secrets }, - }) - .expect(400) - .then((resp: any) => { - expect(resp.body).to.eql({ - statusCode: 400, - error: 'Bad Request', - message: - 'error validating action type config: [casesConfiguration.mapping]: expected non-empty but got empty', + it('should respond with a 400 Bad Request when creating a servicenow action with a non whitelisted apiUrl', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A servicenow action', + actionTypeId: '.servicenow', + config: { + apiUrl: 'http://servicenow.mynonexistent.com', + casesConfiguration: mockServiceNow.config.casesConfiguration, + }, + secrets: mockServiceNow.secrets, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: error configuring connector action: target url "http://servicenow.mynonexistent.com" is not whitelisted in the Kibana config xpack.actions.whitelistedHosts', + }); }); - }); - }); + }); - it('should respond with a 400 Bad Request when creating a servicenow action with wrong actionType', async () => { - await supertest - .post('/api/action') - .set('kbn-xsrf', 'foo') - .send({ - name: 'A servicenow action', - actionTypeId: '.servicenow', - config: { - apiUrl: servicenowSimulatorURL, - casesConfiguration: { - mapping: [ - { - source: 'title', - target: 'description', - actionType: 'non-supported', - }, - ], + it('should respond with a 400 Bad Request when creating a servicenow action without secrets', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A servicenow action', + actionTypeId: '.servicenow', + config: { + apiUrl: servicenowSimulatorURL, + casesConfiguration: mockServiceNow.config.casesConfiguration, }, - }, - secrets: { ...mockServiceNow.secrets }, - }) - .expect(400); - }); - - it('should create our servicenow simulator action successfully', async () => { - const { body: createdSimulatedAction } = await supertest - .post('/api/action') - .set('kbn-xsrf', 'foo') - .send({ - name: 'A servicenow simulator', - actionTypeId: '.servicenow', - config: { - apiUrl: servicenowSimulatorURL, - casesConfiguration: { ...mockServiceNow.config.casesConfiguration }, - }, - secrets: { ...mockServiceNow.secrets }, - }) - .expect(200); + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type secrets: [password]: expected value of type [string] but got [undefined]', + }); + }); + }); - simulatedActionId = createdSimulatedAction.id; - }); + it('should respond with a 400 Bad Request when creating a servicenow action without casesConfiguration', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A servicenow action', + actionTypeId: '.servicenow', + config: { + apiUrl: servicenowSimulatorURL, + }, + secrets: mockServiceNow.secrets, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: [casesConfiguration.mapping]: expected value of type [array] but got [undefined]', + }); + }); + }); - it('should handle executing with a simulated success', async () => { - const { body: result } = await supertest - .post(`/api/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: { ...mockServiceNow.params, title: 'success', comments: [] }, - }) - .expect(200); + it('should respond with a 400 Bad Request when creating a servicenow action with empty mapping', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A servicenow action', + actionTypeId: '.servicenow', + config: { + apiUrl: servicenowSimulatorURL, + casesConfiguration: { mapping: [] }, + }, + secrets: mockServiceNow.secrets, + }) + .expect(400) + .then((resp: any) => { + expect(resp.body).to.eql({ + statusCode: 400, + error: 'Bad Request', + message: + 'error validating action type config: [casesConfiguration.mapping]: expected non-empty but got empty', + }); + }); + }); - expect(result).to.eql({ - status: 'ok', - actionId: simulatedActionId, - data: { - incidentId: '123', - number: 'INC01', - pushedDate: '2020-03-10T12:24:20.000Z', - url: `${servicenowSimulatorURL}/nav_to.do?uri=incident.do?sys_id=123`, - }, + it('should respond with a 400 Bad Request when creating a servicenow action with wrong actionType', async () => { + await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A servicenow action', + actionTypeId: '.servicenow', + config: { + apiUrl: servicenowSimulatorURL, + casesConfiguration: { + mapping: [ + { + source: 'title', + target: 'description', + actionType: 'non-supported', + }, + ], + }, + }, + secrets: mockServiceNow.secrets, + }) + .expect(400); }); }); - it('should handle failing with a simulated success without caseId', async () => { - await supertest - .post(`/api/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: {}, - }) - .then((resp: any) => { - expect(resp.body).to.eql({ - actionId: simulatedActionId, - status: 'error', - retry: false, - message: - 'error validating action params: [caseId]: expected value of type [string] but got [undefined]', + describe('ServiceNow - Executor', () => { + let simulatedActionId: string; + before(async () => { + const { body } = await supertest + .post('/api/action') + .set('kbn-xsrf', 'foo') + .send({ + name: 'A servicenow simulator', + actionTypeId: '.servicenow', + config: { + apiUrl: servicenowSimulatorURL, + casesConfiguration: mockServiceNow.config.casesConfiguration, + }, + secrets: mockServiceNow.secrets, }); + simulatedActionId = body.id; + }); + + describe('Validation', () => { + it('should handle failing with a simulated success without action', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: {}, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: `error validating action params: Cannot read property 'Symbol(Symbol.iterator)' of undefined`, + }); + }); }); - }); - it('should handle failing with a simulated success without title', async () => { - await supertest - .post(`/api/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: { caseId: 'success' }, - }) - .then((resp: any) => { - expect(resp.body).to.eql({ - actionId: simulatedActionId, - status: 'error', - retry: false, - message: - 'error validating action params: [title]: expected value of type [string] but got [undefined]', - }); + it('should handle failing with a simulated success without unsupported action', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { subAction: 'non-supported' }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subAction]: expected value to equal [pushToService]', + }); + }); }); - }); - it('should handle failing with a simulated success without createdAt', async () => { - await supertest - .post(`/api/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: { caseId: 'success', title: 'success' }, - }) - .then((resp: any) => { - expect(resp.body).to.eql({ - actionId: simulatedActionId, - status: 'error', - retry: false, - message: - 'error validating action params: [createdAt]: expected value of type [string] but got [undefined]', - }); + it('should handle failing with a simulated success without subActionParams', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { subAction: 'pushToService' }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.caseId]: expected value of type [string] but got [undefined]', + }); + }); }); - }); - it('should handle failing with a simulated success without commentId', async () => { - await supertest - .post(`/api/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: { - caseId: 'success', - title: 'success', - createdAt: 'success', - createdBy: { username: 'elastic' }, - comments: [{}], - }, - }) - .then((resp: any) => { - expect(resp.body).to.eql({ - actionId: simulatedActionId, - status: 'error', - retry: false, - message: - 'error validating action params: [comments.0.commentId]: expected value of type [string] but got [undefined]', - }); + it('should handle failing with a simulated success without caseId', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { subAction: 'pushToService', subActionParams: {} }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.caseId]: expected value of type [string] but got [undefined]', + }); + }); }); - }); - it('should handle failing with a simulated success without comment message', async () => { - await supertest - .post(`/api/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: { - caseId: 'success', - title: 'success', - createdAt: 'success', - createdBy: { username: 'elastic' }, - comments: [{ commentId: 'success' }], - }, - }) - .then((resp: any) => { - expect(resp.body).to.eql({ - actionId: simulatedActionId, - status: 'error', - retry: false, - message: - 'error validating action params: [comments.0.comment]: expected value of type [string] but got [undefined]', - }); + it('should handle failing with a simulated success without title', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockServiceNow.params, + subActionParams: { + caseId: 'success', + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.title]: expected value of type [string] but got [undefined]', + }); + }); }); - }); - it('should handle failing with a simulated success without comment.createdAt', async () => { - await supertest - .post(`/api/action/${simulatedActionId}/_execute`) - .set('kbn-xsrf', 'foo') - .send({ - params: { - caseId: 'success', - title: 'success', - createdAt: 'success', - createdBy: { username: 'elastic' }, - comments: [{ commentId: 'success', comment: 'success' }], - }, - }) - .then((resp: any) => { - expect(resp.body).to.eql({ + it('should handle failing with a simulated success without createdAt', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockServiceNow.params, + subActionParams: { + caseId: 'success', + title: 'success', + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.createdAt]: expected value of type [string] but got [undefined]', + }); + }); + }); + + it('should handle failing with a simulated success without commentId', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockServiceNow.params, + subActionParams: { + ...mockServiceNow.params.subActionParams, + caseId: 'success', + title: 'success', + createdAt: 'success', + createdBy: { username: 'elastic' }, + comments: [{}], + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.commentId]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', + }); + }); + }); + + it('should handle failing with a simulated success without comment message', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockServiceNow.params, + subActionParams: { + ...mockServiceNow.params.subActionParams, + caseId: 'success', + title: 'success', + createdAt: 'success', + createdBy: { username: 'elastic' }, + comments: [{ commentId: 'success' }], + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.comment]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', + }); + }); + }); + + it('should handle failing with a simulated success without comment.createdAt', async () => { + await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockServiceNow.params, + subActionParams: { + ...mockServiceNow.params.subActionParams, + caseId: 'success', + title: 'success', + createdAt: 'success', + createdBy: { username: 'elastic' }, + comments: [{ commentId: 'success', comment: 'success' }], + }, + }, + }) + .then((resp: any) => { + expect(resp.body).to.eql({ + actionId: simulatedActionId, + status: 'error', + retry: false, + message: + 'error validating action params: types that failed validation:\n- [0.subAction]: expected value to equal [getIncident]\n- [1.subAction]: expected value to equal [handshake]\n- [2.subActionParams.comments]: types that failed validation:\n - [subActionParams.comments.0.0.createdAt]: expected value of type [string] but got [undefined]\n - [subActionParams.comments.1]: expected value to equal [null]', + }); + }); + }); + }); + + describe('Execution', () => { + it('should handle creating an incident without comments', async () => { + const { body: result } = await supertest + .post(`/api/action/${simulatedActionId}/_execute`) + .set('kbn-xsrf', 'foo') + .send({ + params: { + ...mockServiceNow.params, + subActionParams: { + ...mockServiceNow.params.subActionParams, + comments: [], + }, + }, + }) + .expect(200); + + expect(result).to.eql({ + status: 'ok', actionId: simulatedActionId, - status: 'error', - retry: false, - message: - 'error validating action params: [comments.0.createdAt]: expected value of type [string] but got [undefined]', + data: { + id: '123', + title: 'INC01', + pushedDate: '2020-03-10T12:24:20.000Z', + url: `${servicenowSimulatorURL}/nav_to.do?uri=incident.do?sys_id=123`, + }, }); }); + }); }); }); } diff --git a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/index.ts b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/index.ts index 8e002bcc8d3da..18b1714582d13 100644 --- a/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/index.ts +++ b/x-pack/test/alerting_api_integration/security_and_spaces/tests/actions/index.ts @@ -15,6 +15,7 @@ export default function actionsTests({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./builtin_action_types/pagerduty')); loadTestFile(require.resolve('./builtin_action_types/server_log')); loadTestFile(require.resolve('./builtin_action_types/servicenow')); + loadTestFile(require.resolve('./builtin_action_types/jira')); loadTestFile(require.resolve('./builtin_action_types/slack')); loadTestFile(require.resolve('./builtin_action_types/webhook')); loadTestFile(require.resolve('./create')); From c4e6789c28dd0c8fdd00810537b2687a6e94b760 Mon Sep 17 00:00:00 2001 From: Marta Bondyra Date: Thu, 30 Apr 2020 23:44:16 +0200 Subject: [PATCH 06/10] [Lens] Trigger a filter action on click in datatable visualization (#63840) * wip: datatable * fix: empty values * fix: empty values * translations * using dataPlugin to get buckets * one more time, passing aggs data * tests: added * feat: new design applied * remove icon * feat: old design * CR corrections * better name * Fix merge issue * fix: design changes * feat: correction * fix: copy changes * Update x-pack/plugins/lens/public/datatable_visualization/_visualization.scss Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> * Update _visualization.scss Co-authored-by: Elastic Machine Co-authored-by: Wylie Conlon Co-authored-by: Caroline Horn <549577+cchaos@users.noreply.github.com> --- .../__snapshots__/expression.test.tsx.snap | 41 +++++ .../_visualization.scss | 10 ++ .../expression.test.tsx | 156 ++++++++++++++++++ .../datatable_visualization/expression.tsx | 146 +++++++++++++--- .../public/datatable_visualization/index.ts | 23 ++- x-pack/plugins/lens/public/plugin.tsx | 1 + .../test/functional/apps/lens/smokescreen.ts | 25 ++- 7 files changed, 373 insertions(+), 29 deletions(-) create mode 100644 x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap create mode 100644 x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx diff --git a/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap b/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap new file mode 100644 index 0000000000000..76063d230bdb6 --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/__snapshots__/expression.test.tsx.snap @@ -0,0 +1,41 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`datatable_expression DatatableComponent it renders the title and value 1`] = ` + + + +`; diff --git a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss index e36326d710f72..7d95d73143870 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss +++ b/x-pack/plugins/lens/public/datatable_visualization/_visualization.scss @@ -1,3 +1,13 @@ .lnsDataTable { align-self: flex-start; } + +.lnsDataTable__filter { + opacity: 0; + transition: opacity $euiAnimSpeedNormal ease-in-out; +} + +.lnsDataTable__cell:hover .lnsDataTable__filter, +.lnsDataTable__filter:focus-within { + opacity: 1; +} diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.test.tsx new file mode 100644 index 0000000000000..6d5b1153ad1bc --- /dev/null +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.test.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 from 'react'; +import { shallow } from 'enzyme'; +import { mountWithIntl } from 'test_utils/enzyme_helpers'; +import { datatable, DatatableComponent } from './expression'; +import { LensMultiTable } from '../types'; +import { DatatableProps } from './expression'; +import { createMockExecutionContext } from '../../../../../src/plugins/expressions/common/mocks'; +import { IFieldFormat } from '../../../../../src/plugins/data/public'; +import { IAggType } from 'src/plugins/data/public'; +const executeTriggerActions = jest.fn(); + +function sampleArgs() { + const data: LensMultiTable = { + type: 'lens_multitable', + tables: { + l1: { + type: 'kibana_datatable', + columns: [ + { id: 'a', name: 'a', meta: { type: 'count' } }, + { id: 'b', name: 'b', meta: { type: 'date_histogram', aggConfigParams: { field: 'b' } } }, + { id: 'c', name: 'c', meta: { type: 'cardinality' } }, + ], + rows: [{ a: 10110, b: 1588024800000, c: 3 }], + }, + }, + }; + + const args: DatatableProps['args'] = { + title: 'My fanci metric chart', + columns: { + columnIds: ['a', 'b', 'c'], + type: 'lens_datatable_columns', + }, + }; + + return { data, args }; +} + +describe('datatable_expression', () => { + describe('datatable renders', () => { + test('it renders with the specified data and args', () => { + const { data, args } = sampleArgs(); + const result = datatable.fn(data, args, createMockExecutionContext()); + + expect(result).toEqual({ + type: 'render', + as: 'lens_datatable_renderer', + value: { data, args }, + }); + }); + }); + + describe('DatatableComponent', () => { + test('it renders the title and value', () => { + const { data, args } = sampleArgs(); + + expect( + shallow( + x as IFieldFormat} + executeTriggerActions={executeTriggerActions} + getType={jest.fn()} + /> + ) + ).toMatchSnapshot(); + }); + + test('it invokes executeTriggerActions with correct context on click on top value', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + x as IFieldFormat} + executeTriggerActions={executeTriggerActions} + getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} + /> + ); + + wrapper + .find('[data-test-subj="lensDatatableFilterOut"]') + .first() + .simulate('click'); + + expect(executeTriggerActions).toHaveBeenCalledWith('VALUE_CLICK_TRIGGER', { + data: { + data: [ + { + column: 0, + row: 0, + table: data.tables.l1, + value: 10110, + }, + ], + negate: true, + }, + timeFieldName: undefined, + }); + }); + + test('it invokes executeTriggerActions with correct context on click on timefield', () => { + const { args, data } = sampleArgs(); + + const wrapper = mountWithIntl( + x as IFieldFormat} + executeTriggerActions={executeTriggerActions} + getType={jest.fn(() => ({ type: 'buckets' } as IAggType))} + /> + ); + + wrapper + .find('[data-test-subj="lensDatatableFilterFor"]') + .at(3) + .simulate('click'); + + expect(executeTriggerActions).toHaveBeenCalledWith('VALUE_CLICK_TRIGGER', { + data: { + data: [ + { + column: 1, + row: 0, + table: data.tables.l1, + value: 1588024800000, + }, + ], + negate: false, + }, + timeFieldName: 'b', + }); + }); + }); +}); diff --git a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx index 772ee13168d02..71d29be1744bb 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/expression.tsx +++ b/x-pack/plugins/lens/public/datatable_visualization/expression.tsx @@ -7,7 +7,9 @@ import React from 'react'; import ReactDOM from 'react-dom'; import { i18n } from '@kbn/i18n'; -import { EuiBasicTable } from '@elastic/eui'; +import { I18nProvider } from '@kbn/i18n/react'; +import { EuiBasicTable, EuiFlexGroup, EuiButtonIcon, EuiFlexItem, EuiToolTip } from '@elastic/eui'; +import { IAggType } from 'src/plugins/data/public'; import { FormatFactory, LensMultiTable } from '../types'; import { ExpressionFunctionDefinition, @@ -15,7 +17,10 @@ import { IInterpreterRenderHandlers, } from '../../../../../src/plugins/expressions/public'; import { VisualizationContainer } from '../visualization_container'; - +import { ValueClickTriggerContext } from '../../../../../src/plugins/embeddable/public'; +import { VIS_EVENT_TO_TRIGGER } from '../../../../../src/plugins/visualizations/public'; +import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import { getExecuteTriggerActions } from '../services'; export interface DatatableColumns { columnIds: string[]; } @@ -30,6 +35,12 @@ export interface DatatableProps { args: Args; } +type DatatableRenderProps = DatatableProps & { + formatFactory: FormatFactory; + executeTriggerActions: UiActionsStart['executeTriggerActions']; + getType: (name: string) => IAggType; +}; + export interface DatatableRender { type: 'render'; as: 'lens_datatable_renderer'; @@ -100,9 +111,10 @@ export const datatableColumns: ExpressionFunctionDefinition< }, }; -export const getDatatableRenderer = ( - formatFactory: Promise -): ExpressionRenderDefinition => ({ +export const getDatatableRenderer = (dependencies: { + formatFactory: Promise; + getType: Promise<(name: string) => IAggType>; +}): ExpressionRenderDefinition => ({ name: 'lens_datatable_renderer', displayName: i18n.translate('xpack.lens.datatable.visualizationName', { defaultMessage: 'Datatable', @@ -115,9 +127,18 @@ export const getDatatableRenderer = ( config: DatatableProps, handlers: IInterpreterRenderHandlers ) => { - const resolvedFormatFactory = await formatFactory; + const resolvedFormatFactory = await dependencies.formatFactory; + const executeTriggerActions = getExecuteTriggerActions(); + const resolvedGetType = await dependencies.getType; ReactDOM.render( - , + + + , domNode, () => { handlers.done(); @@ -127,7 +148,7 @@ export const getDatatableRenderer = ( }, }); -function DatatableComponent(props: DatatableProps & { formatFactory: FormatFactory }) { +export function DatatableComponent(props: DatatableRenderProps) { const [firstTable] = Object.values(props.data.tables); const formatters: Record> = {}; @@ -135,6 +156,29 @@ function DatatableComponent(props: DatatableProps & { formatFactory: FormatFacto formatters[column.id] = props.formatFactory(column.formatHint); }); + const handleFilterClick = (field: string, value: unknown, colIndex: number, negate = false) => { + const col = firstTable.columns[colIndex]; + const isDateHistogram = col.meta?.type === 'date_histogram'; + const timeFieldName = negate && isDateHistogram ? undefined : col?.meta?.aggConfigParams?.field; + const rowIndex = firstTable.rows.findIndex(row => row[field] === value); + + const context: ValueClickTriggerContext = { + data: { + negate, + data: [ + { + row: rowIndex, + column: colIndex, + value, + table: firstTable, + }, + ], + }, + timeFieldName, + }; + props.executeTriggerActions(VIS_EVENT_TO_TRIGGER.filter, context); + }; + return ( { const col = firstTable.columns.find(c => c.id === field); + const colIndex = firstTable.columns.findIndex(c => c.id === field); + + const filterable = col?.meta?.type && props.getType(col.meta.type)?.type === 'buckets'; return { field, name: (col && col.name) || '', + render: (value: unknown) => { + const formattedValue = formatters[field]?.convert(value); + const fieldName = col?.meta?.aggConfigParams?.field; + + if (filterable) { + return ( + + {formattedValue} + + + + handleFilterClick(field, value, colIndex)} + /> + + + + handleFilterClick(field, value, colIndex, true)} + /> + + + + + + ); + } + return {formattedValue}; + }, }; }) .filter(({ field }) => !!field)} - items={ - firstTable - ? firstTable.rows.map(row => { - const formattedRow: Record = {}; - Object.entries(formatters).forEach(([columnId, formatter]) => { - formattedRow[columnId] = formatter.convert(row[columnId]); - }); - return formattedRow; - }) - : [] - } + items={firstTable ? firstTable.rows : []} /> ); diff --git a/x-pack/plugins/lens/public/datatable_visualization/index.ts b/x-pack/plugins/lens/public/datatable_visualization/index.ts index ff036aadfd4cf..44894d31da51d 100644 --- a/x-pack/plugins/lens/public/datatable_visualization/index.ts +++ b/x-pack/plugins/lens/public/datatable_visualization/index.ts @@ -4,12 +4,19 @@ * you may not use this file except in compliance with the Elastic License. */ -import { CoreSetup } from 'kibana/public'; +import { CoreSetup, CoreStart } from 'kibana/public'; import { datatableVisualization } from './visualization'; import { ExpressionsSetup } from '../../../../../src/plugins/expressions/public'; import { datatable, datatableColumns, getDatatableRenderer } from './expression'; import { EditorFrameSetup, FormatFactory } from '../types'; +import { setExecuteTriggerActions } from '../services'; +import { UiActionsStart } from '../../../../../src/plugins/ui_actions/public'; +import { DataPublicPluginStart } from '../../../../../src/plugins/data/public'; +interface DatatableVisualizationPluginStartPlugins { + uiActions: UiActionsStart; + data: DataPublicPluginStart; +} export interface DatatableVisualizationPluginSetupPlugins { expressions: ExpressionsSetup; formatFactory: Promise; @@ -20,12 +27,22 @@ export class DatatableVisualization { constructor() {} setup( - _core: CoreSetup | null, + core: CoreSetup, { expressions, formatFactory, editorFrame }: DatatableVisualizationPluginSetupPlugins ) { expressions.registerFunction(() => datatableColumns); expressions.registerFunction(() => datatable); - expressions.registerRenderer(() => getDatatableRenderer(formatFactory)); + expressions.registerRenderer(() => + getDatatableRenderer({ + formatFactory, + getType: core + .getStartServices() + .then(([_, { data: dataStart }]) => dataStart.search.aggs.types.get), + }) + ); editorFrame.registerVisualization(datatableVisualization); } + start(core: CoreStart, { uiActions }: DatatableVisualizationPluginStartPlugins) { + setExecuteTriggerActions(uiActions.executeTriggerActions); + } } diff --git a/x-pack/plugins/lens/public/plugin.tsx b/x-pack/plugins/lens/public/plugin.tsx index 8d760eb0df501..fe0e81177e259 100644 --- a/x-pack/plugins/lens/public/plugin.tsx +++ b/x-pack/plugins/lens/public/plugin.tsx @@ -200,6 +200,7 @@ export class LensPlugin { start(core: CoreStart, startDependencies: LensPluginStartDependencies) { this.createEditorFrame = this.editorFrameService.start(core, startDependencies).createInstance; this.xyVisualization.start(core, startDependencies); + this.datatableVisualization.start(core, startDependencies); } stop() { diff --git a/x-pack/test/functional/apps/lens/smokescreen.ts b/x-pack/test/functional/apps/lens/smokescreen.ts index be7a2faae6711..082008bccddd1 100644 --- a/x-pack/test/functional/apps/lens/smokescreen.ts +++ b/x-pack/test/functional/apps/lens/smokescreen.ts @@ -26,12 +26,12 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const filterBar = getService('filterBar'); - async function assertExpectedMetric() { + async function assertExpectedMetric(metricCount: string = '19,986') { await PageObjects.lens.assertExactText( '[data-test-subj="lns_metric_title"]', 'Maximum of bytes' ); - await PageObjects.lens.assertExactText('[data-test-subj="lns_metric_value"]', '19,986'); + await PageObjects.lens.assertExactText('[data-test-subj="lns_metric_value"]', metricCount); } async function assertExpectedTable() { @@ -40,8 +40,12 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { 'Maximum of bytes' ); await PageObjects.lens.assertExactText( - '[data-test-subj="lnsDataTable"] tbody .euiTableCellContent__text', - '19,986' + '[data-test-subj="lnsDataTable"] [data-test-subj="lnsDataTableCellValue"]', + '19,985' + ); + await PageObjects.lens.assertExactText( + '[data-test-subj="lnsDataTable"] [data-test-subj="lnsDataTableCellValueFilterable"]', + 'IN' ); } @@ -86,7 +90,7 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { await assertExpectedMetric(); }); - it('click on the bar in XYChart adds proper filters/timerange', async () => { + it('click on the bar in XYChart adds proper filters/timerange in dashboard', async () => { await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.clickNewDashboard(); await dashboardAddPanel.clickOpenAddPanel(); @@ -102,15 +106,22 @@ export default function({ getService, getPageObjects }: FtrProviderContext) { expect(hasIpFilter).to.be(true); }); - it('should allow seamless transition to and from table view', async () => { + it('should allow seamless transition to and from table view and add a filter', async () => { await PageObjects.visualize.gotoVisualizationLandingPage(); await PageObjects.lens.clickVisualizeListItemTitle('Artistpreviouslyknownaslens'); await PageObjects.lens.goToTimeRange(); await assertExpectedMetric(); await PageObjects.lens.switchToVisualization('lnsChartSwitchPopover_lnsDatatable'); + await PageObjects.lens.configureDimension({ + dimension: '[data-test-subj="lnsDatatable_column"] [data-test-subj="lns-empty-dimension"]', + operation: 'terms', + field: 'geo.dest', + }); + await PageObjects.lens.save('Artistpreviouslyknownaslens'); + await find.clickByCssSelector('[data-test-subj="lensDatatableFilterOut"]'); await assertExpectedTable(); await PageObjects.lens.switchToVisualization('lnsChartSwitchPopover_lnsMetric'); - await assertExpectedMetric(); + await assertExpectedMetric('19,985'); }); it('should allow creation of lens visualizations', async () => { From 127b324a5f400b9e26357529930879e24d5e9770 Mon Sep 17 00:00:00 2001 From: Catherine Liu Date: Thu, 30 Apr 2020 14:45:50 -0700 Subject: [PATCH 07/10] [Canvas] Adds refresh and autoplay options to view menu (#64375) --- .../legacy/plugins/canvas/i18n/components.ts | 22 +++- .../control_settings/control_settings.scss | 7 - .../control_settings/control_settings.tsx | 84 ------------ .../workpad_header/control_settings/index.ts | 35 ----- .../refresh_control/refresh_control.tsx | 1 + .../__snapshots__/view_menu.stories.storyshot | 66 ++++++++++ .../__examples__/view_menu.stories.tsx | 58 ++++++--- .../auto_refresh_controls.tsx | 36 +---- .../custom_interval.tsx | 0 .../workpad_header/view_menu/index.ts | 39 ++++-- .../kiosk_controls.tsx | 26 +--- .../workpad_header/view_menu/view_menu.scss | 4 + .../workpad_header/view_menu/view_menu.tsx | 123 ++++++++++++++++-- .../workpad_header/workpad_header.tsx | 6 +- .../plugins/canvas/public/style/index.scss | 2 +- .../footer/settings/autoplay_settings.tsx | 2 +- .../functional/page_objects/canvas_page.ts | 10 +- 17 files changed, 289 insertions(+), 232 deletions(-) delete mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/control_settings.scss delete mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/control_settings.tsx delete mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/index.ts rename x-pack/legacy/plugins/canvas/public/components/workpad_header/{control_settings => view_menu}/auto_refresh_controls.tsx (83%) rename x-pack/legacy/plugins/canvas/public/components/workpad_header/{control_settings => view_menu}/custom_interval.tsx (100%) rename x-pack/legacy/plugins/canvas/public/components/workpad_header/{control_settings => view_menu}/kiosk_controls.tsx (86%) create mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/view_menu.scss diff --git a/x-pack/legacy/plugins/canvas/i18n/components.ts b/x-pack/legacy/plugins/canvas/i18n/components.ts index 7bd16c4933ce1..b1c2b41f062f1 100644 --- a/x-pack/legacy/plugins/canvas/i18n/components.ts +++ b/x-pack/legacy/plugins/canvas/i18n/components.ts @@ -1079,12 +1079,6 @@ export const ComponentStrings = { defaultMessage: 'Refresh elements', }), }, - WorkpadHeaderControlSettings: { - getButtonLabel: () => - i18n.translate('xpack.canvas.workpadHeaderControlSettings.buttonLabel', { - defaultMessage: 'Options', - }), - }, WorkpadHeaderCustomInterval: { getButtonLabel: () => i18n.translate('xpack.canvas.workpadHeaderCustomInterval.confirmButtonLabel', { @@ -1305,6 +1299,18 @@ export const ComponentStrings = { }), }, WorkpadHeaderViewMenu: { + getAutoplayOffMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.autoplayOffMenuItemLabel', { + defaultMessage: 'Turn autoplay off', + }), + getAutoplayOnMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.autoplayOnMenuItemLabel', { + defaultMessage: 'Turn autoplay on', + }), + getAutoplaySettingsMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.autoplaySettingsMenuItemLabel', { + defaultMessage: 'Autoplay settings', + }), getFullscreenMenuItemLabel: () => i18n.translate('xpack.canvas.workpadHeaderViewMenu.fullscreenMenuLabel', { defaultMessage: 'Enter fullscreen mode', @@ -1317,6 +1323,10 @@ export const ComponentStrings = { i18n.translate('xpack.canvas.workpadHeaderViewMenu.refreshMenuItemLabel', { defaultMessage: 'Refresh data', }), + getRefreshSettingsMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderViewMenu.refreshSettingsMenuItemLabel', { + defaultMessage: 'Auto refresh settings', + }), getShowEditModeLabel: () => i18n.translate('xpack.canvas.workpadHeaderViewMenu.showEditModeLabel', { defaultMessage: 'Show editing controls', diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/control_settings.scss b/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/control_settings.scss deleted file mode 100644 index 3d217dd1fc180..0000000000000 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/control_settings.scss +++ /dev/null @@ -1,7 +0,0 @@ -.canvasControlSettings__popover { - width: 600px; -} - -.canvasControlSettings__list { - columns: 2; -} diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/control_settings.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/control_settings.tsx deleted file mode 100644 index adc57ff4f815a..0000000000000 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/control_settings.tsx +++ /dev/null @@ -1,84 +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, { MouseEventHandler } from 'react'; -import PropTypes from 'prop-types'; -import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; -// @ts-ignore untyped local -import { Popover } from '../../popover'; -import { AutoRefreshControls } from './auto_refresh_controls'; -import { KioskControls } from './kiosk_controls'; - -import { ComponentStrings } from '../../../../i18n'; -const { WorkpadHeaderControlSettings: strings } = ComponentStrings; - -interface Props { - refreshInterval: number; - setRefreshInterval: (interval: number | undefined) => void; - autoplayEnabled: boolean; - autoplayInterval: number; - enableAutoplay: (enable: boolean) => void; - setAutoplayInterval: (interval: number | undefined) => void; -} - -export const ControlSettings = ({ - setRefreshInterval, - refreshInterval, - autoplayEnabled, - autoplayInterval, - enableAutoplay, - setAutoplayInterval, -}: Props) => { - const setRefresh = (val: number | undefined) => setRefreshInterval(val); - - const disableInterval = () => { - setRefresh(0); - }; - - const popoverButton = (handleClick: MouseEventHandler) => ( - - {strings.getButtonLabel()} - - ); - - return ( - - {() => ( - - - setRefresh(val)} - disableInterval={() => disableInterval()} - /> - - - - - - )} - - ); -}; - -ControlSettings.propTypes = { - refreshInterval: PropTypes.number, - setRefreshInterval: PropTypes.func.isRequired, - autoplayEnabled: PropTypes.bool, - autoplayInterval: PropTypes.number, - enableAutoplay: PropTypes.func.isRequired, - setAutoplayInterval: PropTypes.func.isRequired, -}; diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/index.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/index.ts deleted file mode 100644 index 316a49c85c09d..0000000000000 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/index.ts +++ /dev/null @@ -1,35 +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 { - setRefreshInterval, - enableAutoplay, - setAutoplayInterval, - // @ts-ignore untyped local -} from '../../../state/actions/workpad'; -// @ts-ignore untyped local -import { getRefreshInterval, getAutoplay } from '../../../state/selectors/workpad'; -import { State } from '../../../../types'; -import { ControlSettings as Component } from './control_settings'; - -const mapStateToProps = (state: State) => { - const { enabled, interval } = getAutoplay(state); - - return { - refreshInterval: getRefreshInterval(state), - autoplayEnabled: enabled, - autoplayInterval: interval, - }; -}; - -const mapDispatchToProps = { - setRefreshInterval, - enableAutoplay, - setAutoplayInterval, -}; - -export const ControlSettings = connect(mapStateToProps, mapDispatchToProps)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/refresh_control/refresh_control.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/refresh_control/refresh_control.tsx index 1768adf9be79d..d651e649128f9 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/refresh_control/refresh_control.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/refresh_control/refresh_control.tsx @@ -32,6 +32,7 @@ export const RefreshControl = ({ doRefresh, inFlight }: Props) => ( iconType="refresh" aria-label={strings.getRefreshAriaLabel()} onClick={doRefresh} + data-test-subj="canvas-refresh-control" /> ); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/__examples__/__snapshots__/view_menu.stories.storyshot b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/__examples__/__snapshots__/view_menu.stories.storyshot index e1ecee0e152be..eb45f97452ae1 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/__examples__/__snapshots__/view_menu.stories.storyshot +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/__examples__/__snapshots__/view_menu.stories.storyshot @@ -65,3 +65,69 @@ exports[`Storyshots components/WorkpadHeader/ViewMenu read only mode 1`] = `
`; + +exports[`Storyshots components/WorkpadHeader/ViewMenu with autoplay enabled 1`] = ` +
+
+ +
+
+`; + +exports[`Storyshots components/WorkpadHeader/ViewMenu with refresh enabled 1`] = ` +
+
+ +
+
+`; diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/__examples__/view_menu.stories.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/__examples__/view_menu.stories.tsx index 60837ac1218e6..5b4de05da3a3d 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/__examples__/view_menu.stories.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/__examples__/view_menu.stories.tsx @@ -8,32 +8,58 @@ import { action } from '@storybook/addon-actions'; import React from 'react'; import { ViewMenu } from '../view_menu'; +const handlers = { + setZoomScale: action('setZoomScale'), + zoomIn: action('zoomIn'), + zoomOut: action('zoomOut'), + toggleWriteable: action('toggleWriteable'), + resetZoom: action('resetZoom'), + enterFullscreen: action('enterFullscreen'), + doRefresh: action('doRefresh'), + fitToWindow: action('fitToWindow'), + setRefreshInterval: action('setRefreshInterval'), + setAutoplayInterval: action('setAutoplayInterval'), + enableAutoplay: action('enableAutoplay'), +}; + storiesOf('components/WorkpadHeader/ViewMenu', module) .add('edit mode', () => ( )) .add('read only mode', () => ( + )) + .add('with refresh enabled', () => ( + + )) + .add('with autoplay enabled', () => ( + )); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/auto_refresh_controls.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/auto_refresh_controls.tsx similarity index 83% rename from x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/auto_refresh_controls.tsx rename to x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/auto_refresh_controls.tsx index 97d8920d50dd3..cfd599b1d9f3f 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/auto_refresh_controls.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/auto_refresh_controls.tsx @@ -22,7 +22,6 @@ import { htmlIdGenerator, } from '@elastic/eui'; import { timeDuration } from '../../../lib/time_duration'; -import { RefreshControl } from '../refresh_control'; import { CustomInterval } from './custom_interval'; import { ComponentStrings, UnitStrings } from '../../../../i18n'; @@ -69,7 +68,11 @@ export const AutoRefreshControls = ({ refreshInterval, setRefresh, disableInterv const intervalTitleId = generateId(); return ( - + @@ -97,9 +100,6 @@ export const AutoRefreshControls = ({ refreshInterval, setRefresh, disableInterv ) : null} - - - @@ -112,16 +112,6 @@ export const AutoRefreshControls = ({ refreshInterval, setRefresh, disableInterv - - - - - - setRefresh(value)} /> diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/custom_interval.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/custom_interval.tsx similarity index 100% rename from x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/custom_interval.tsx rename to x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/custom_interval.tsx diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/index.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/index.ts index eee613183639c..e1ad9782c8aef 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/index.ts +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/index.ts @@ -15,13 +15,21 @@ import { fetchAllRenderables } from '../../../state/actions/elements'; // @ts-ignore Untyped local import { setZoomScale, setFullscreen, selectToplevelNodes } from '../../../state/actions/transient'; // @ts-ignore Untyped local -import { setWriteable } from '../../../state/actions/workpad'; +import { + setWriteable, + setRefreshInterval, + enableAutoplay, + setAutoplayInterval, + // @ts-ignore Untyped local +} from '../../../state/actions/workpad'; import { getZoomScale, canUserWrite } from '../../../state/selectors/app'; import { getWorkpadBoundingBox, getWorkpadWidth, getWorkpadHeight, isWriteable, + getRefreshInterval, + getAutoplay, } from '../../../state/selectors/workpad'; import { ViewMenu as Component, Props as ComponentProps } from './view_menu'; import { getFitZoomScale } from './lib/get_fit_zoom_scale'; @@ -40,24 +48,35 @@ interface DispatchProps { setFullscreen: (showFullscreen: boolean) => void; } -const mapStateToProps = (state: State) => ({ - zoomScale: getZoomScale(state), - boundingBox: getWorkpadBoundingBox(state), - workpadWidth: getWorkpadWidth(state), - workpadHeight: getWorkpadHeight(state), - isWriteable: isWriteable(state) && canUserWrite(state), -}); +const mapStateToProps = (state: State) => { + const { enabled, interval } = getAutoplay(state); + + return { + zoomScale: getZoomScale(state), + boundingBox: getWorkpadBoundingBox(state), + workpadWidth: getWorkpadWidth(state), + workpadHeight: getWorkpadHeight(state), + isWriteable: isWriteable(state) && canUserWrite(state), + refreshInterval: getRefreshInterval(state), + autoplayEnabled: enabled, + autoplayInterval: interval, + }; +}; const mapDispatchToProps = (dispatch: Dispatch) => ({ setZoomScale: (scale: number) => dispatch(setZoomScale(scale)), setWriteable: (isWorkpadWriteable: boolean) => dispatch(setWriteable(isWorkpadWriteable)), setFullscreen: (value: boolean) => { dispatch(setFullscreen(value)); + if (value) { dispatch(selectToplevelNodes([])); } }, doRefresh: () => dispatch(fetchAllRenderables()), + setRefreshInterval: (interval: number) => dispatch(setRefreshInterval(interval)), + enableAutoplay: (autoplay: number) => dispatch(enableAutoplay(autoplay)), + setAutoplayInterval: (interval: number) => dispatch(setAutoplayInterval(interval)), }); const mergeProps = ( @@ -66,13 +85,15 @@ const mergeProps = ( ownProps: ComponentProps ): ComponentProps => { const { boundingBox, workpadWidth, workpadHeight, ...remainingStateProps } = stateProps; + return { ...remainingStateProps, ...dispatchProps, ...ownProps, toggleWriteable: () => dispatchProps.setWriteable(!stateProps.isWriteable), enterFullscreen: () => dispatchProps.setFullscreen(true), - fitToWindow: () => getFitZoomScale(boundingBox, workpadWidth, workpadHeight), + fitToWindow: () => + dispatchProps.setZoomScale(getFitZoomScale(boundingBox, workpadWidth, workpadHeight)), }; }; diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/kiosk_controls.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/kiosk_controls.tsx similarity index 86% rename from x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/kiosk_controls.tsx rename to x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/kiosk_controls.tsx index 9e6f0a91c6120..e63eed9f9df53 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/control_settings/kiosk_controls.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/kiosk_controls.tsx @@ -14,7 +14,6 @@ import { EuiHorizontalRule, EuiLink, EuiSpacer, - EuiSwitch, EuiText, EuiFlexItem, EuiFlexGroup, @@ -29,9 +28,7 @@ const { time: timeStrings } = UnitStrings; const { getSecondsText, getMinutesText } = timeStrings; interface Props { - autoplayEnabled: boolean; autoplayInterval: number; - onSetEnabled: (enabled: boolean) => void; onSetInterval: (interval: number | undefined) => void; } @@ -54,12 +51,7 @@ const ListGroup = ({ children, ...rest }: ListGroupProps) => ( const generateId = htmlIdGenerator(); -export const KioskControls = ({ - autoplayEnabled, - autoplayInterval, - onSetEnabled, - onSetInterval, -}: Props) => { +export const KioskControls = ({ autoplayInterval, onSetInterval }: Props) => { const RefreshItem = ({ duration, label, descriptionId }: RefreshItemProps) => (
  • onSetInterval(duration)} aria-describedby={descriptionId}> @@ -72,7 +64,11 @@ export const KioskControls = ({ const intervalTitleId = generateId(); return ( - + {strings.getTitle()} @@ -81,14 +77,6 @@ export const KioskControls = ({ - - onSetEnabled(ev.target.checked)} - /> - -

    {strings.getCycleFormLabel()}

    @@ -137,8 +125,6 @@ export const KioskControls = ({ }; KioskControls.propTypes = { - autoplayEnabled: PropTypes.bool.isRequired, autoplayInterval: PropTypes.number.isRequired, - onSetEnabled: PropTypes.func.isRequired, onSetInterval: PropTypes.func.isRequired, }; diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/view_menu.scss b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/view_menu.scss new file mode 100644 index 0000000000000..c4e06881981c7 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/view_menu.scss @@ -0,0 +1,4 @@ +.canvasViewMenu__kioskSettings, +.canvasViewMenu__refreshSettings { + padding: $euiSize; +} \ No newline at end of file diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/view_menu.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/view_menu.tsx index d1e08c5809579..b6f108cda37f6 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/view_menu.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/view_menu/view_menu.tsx @@ -12,10 +12,16 @@ import { EuiIcon, EuiContextMenuPanelItemDescriptor, } from '@elastic/eui'; -import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL } from '../../../../common/lib/constants'; +import { + MAX_ZOOM_LEVEL, + MIN_ZOOM_LEVEL, + CONTEXT_MENU_TOP_BORDER_CLASSNAME, +} from '../../../../common/lib/constants'; import { ComponentStrings } from '../../../../i18n/components'; import { flattenPanelTree } from '../../../lib/flatten_panel_tree'; import { Popover, ClosePopoverFn } from '../../popover'; +import { AutoRefreshControls } from './auto_refresh_controls'; +import { KioskControls } from './kiosk_controls'; const { WorkpadHeaderViewMenu: strings } = ComponentStrings; @@ -62,10 +68,33 @@ export interface Props { * triggers a refresh of the workpad */ doRefresh: () => void; + /** + * Current auto refresh interval + */ + refreshInterval: number; + /** + * Sets auto refresh interval + */ + setRefreshInterval: (interval?: number) => void; + /** + * Is autoplay enabled? + */ + autoplayEnabled: boolean; + /** + * Current autoplay interval + */ + autoplayInterval: number; + /** + * Enables autoplay + */ + enableAutoplay: (autoplay: boolean) => void; + /** + * Sets autoplay interval + */ + setAutoplayInterval: (interval?: number) => void; } export const ViewMenu: FunctionComponent = ({ - doRefresh, enterFullscreen, fitToWindow, isWriteable, @@ -75,7 +104,20 @@ export const ViewMenu: FunctionComponent = ({ zoomIn, zoomOut, zoomScale, + doRefresh, + refreshInterval, + setRefreshInterval, + autoplayEnabled, + autoplayInterval, + enableAutoplay, + setAutoplayInterval, }) => { + const setRefresh = (val: number | undefined) => setRefreshInterval(val); + + const disableInterval = () => { + setRefresh(0); + }; + const viewControl = (togglePopover: React.MouseEventHandler) => ( {strings.getViewMenuButtonLabel()} @@ -121,36 +163,76 @@ export const ViewMenu: FunctionComponent = ({ const getPanelTree = (closePopover: ClosePopoverFn) => ({ id: 0, - title: strings.getViewMenuLabel(), items: [ + { + name: strings.getRefreshMenuItemLabel(), + icon: 'refresh', + onClick: () => { + doRefresh(); + }, + }, + { + name: strings.getRefreshSettingsMenuItemLabel(), + icon: 'empty', + panel: { + id: 1, + title: strings.getRefreshSettingsMenuItemLabel(), + content: ( + setRefresh(val)} + disableInterval={() => disableInterval()} + /> + ), + }, + }, { name: strings.getFullscreenMenuItemLabel(), icon: , + className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, onClick: () => { enterFullscreen(); closePopover(); }, }, { - name: isWriteable ? strings.getHideEditModeLabel() : strings.getShowEditModeLabel(), - icon: , + name: autoplayEnabled + ? strings.getAutoplayOffMenuItemLabel() + : strings.getAutoplayOnMenuItemLabel(), + icon: autoplayEnabled ? 'stop' : 'play', onClick: () => { - toggleWriteable(); + enableAutoplay(!autoplayEnabled); closePopover(); }, }, { - name: strings.getRefreshMenuItemLabel(), - icon: 'refresh', + name: strings.getAutoplaySettingsMenuItemLabel(), + icon: 'empty', + panel: { + id: 2, + title: strings.getAutoplaySettingsMenuItemLabel(), + content: ( + + ), + }, + }, + { + name: isWriteable ? strings.getHideEditModeLabel() : strings.getShowEditModeLabel(), + icon: , + className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, onClick: () => { - doRefresh(); + toggleWriteable(); + closePopover(); }, }, { name: strings.getZoomMenuItemLabel(), icon: 'magnifyWithPlus', panel: { - id: 1, + id: 3, title: strings.getZoomMenuItemLabel(), items: getZoomMenuItems(), }, @@ -161,7 +243,11 @@ export const ViewMenu: FunctionComponent = ({ return ( {({ closePopover }: { closePopover: ClosePopoverFn }) => ( - + )} ); @@ -169,4 +255,19 @@ export const ViewMenu: FunctionComponent = ({ ViewMenu.propTypes = { isWriteable: PropTypes.bool.isRequired, + zoomScale: PropTypes.number.isRequired, + fitToWindow: PropTypes.func.isRequired, + setZoomScale: PropTypes.func.isRequired, + zoomIn: PropTypes.func.isRequired, + zoomOut: PropTypes.func.isRequired, + resetZoom: PropTypes.func.isRequired, + toggleWriteable: PropTypes.func.isRequired, + enterFullscreen: PropTypes.func.isRequired, + doRefresh: PropTypes.func.isRequired, + refreshInterval: PropTypes.number.isRequired, + setRefreshInterval: PropTypes.func.isRequired, + autoplayEnabled: PropTypes.bool.isRequired, + autoplayInterval: PropTypes.number.isRequired, + enableAutoplay: PropTypes.func.isRequired, + setAutoplayInterval: PropTypes.func.isRequired, }; diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_header.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_header.tsx index 253e6c68cfc9e..1f8e47b556771 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_header.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_header.tsx @@ -11,7 +11,6 @@ import { Shortcuts } from 'react-shortcuts'; import { EuiFlexItem, EuiFlexGroup, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import { ComponentStrings } from '../../../i18n'; import { ToolTipShortcut } from '../tool_tip_shortcut/'; -import { ControlSettings } from './control_settings'; // @ts-ignore untyped local import { RefreshControl } from './refresh_control'; // @ts-ignore untyped local @@ -103,9 +102,6 @@ export const WorkpadHeader: FunctionComponent = ({ - - -
    @@ -122,7 +118,7 @@ export const WorkpadHeader: FunctionComponent = ({ )} void; export type onSetIntervalFn = (interval: string) => void; diff --git a/x-pack/test/functional/page_objects/canvas_page.ts b/x-pack/test/functional/page_objects/canvas_page.ts index 94ad393ead3a3..ce36385a2f9df 100644 --- a/x-pack/test/functional/page_objects/canvas_page.ts +++ b/x-pack/test/functional/page_objects/canvas_page.ts @@ -65,14 +65,12 @@ export function CanvasPageProvider({ getService }: FtrProviderContext) { async expectNoAddElementButton() { // Ensure page is fully loaded first by waiting for the refresh button - const refreshPopoverExists = await find.existsByCssSelector('#auto-refresh-popover', 20000); + const refreshPopoverExists = await testSubjects.exists('canvas-refresh-control', { + timeout: 20000, + }); expect(refreshPopoverExists).to.be(true); - const addElementButtonExists = await find.existsByCssSelector( - 'button[data-test-subj=add-element-button]', - 10 // don't need much of a wait at all here, because we already waited for refresh button above - ); - expect(addElementButtonExists).to.be(false); + await testSubjects.missingOrFail('add-element-button'); }, }; } From f9c1033d41aac8dd86b05ca2ad01cd12b51cca69 Mon Sep 17 00:00:00 2001 From: Catherine Liu Date: Thu, 30 Apr 2020 14:51:24 -0700 Subject: [PATCH 08/10] [Canvas] Adds edit menu (#64738) --- .../legacy/plugins/canvas/i18n/components.ts | 162 ++--- .../legacy/plugins/canvas/i18n/shortcuts.ts | 4 +- .../apps/workpad/workpad_app/workpad_app.js | 4 +- .../keyboard_shortcuts_doc.stories.storyshot | 4 +- .../components/sidebar/sidebar_content.js | 40 +- .../sidebar_header.stories.storyshot | 140 ---- .../__examples__/sidebar_header.stories.tsx | 16 - .../sidebar_header/sidebar_header.tsx | 627 +++--------------- .../edit_menu.examples.storyshot | 205 ++++++ .../__examples__/edit_menu.examples.tsx | 69 ++ .../workpad_header/edit_menu/edit_menu.tsx | 448 +++++++++++++ .../workpad_header/edit_menu/index.ts | 123 ++++ .../element_menu/element_menu.tsx | 1 - .../workpad_header/share_menu/share_menu.tsx | 1 - .../workpad_header/workpad_header.tsx | 6 + .../canvas/public/state/selectors/workpad.ts | 6 +- .../legacy/plugins/canvas/types/elements.ts | 6 +- .../translations/translations/ja-JP.json | 28 +- .../translations/translations/zh-CN.json | 31 +- .../functional/apps/canvas/custom_elements.ts | 5 +- 20 files changed, 1100 insertions(+), 826 deletions(-) create mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/__examples__/__snapshots__/edit_menu.examples.storyshot create mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/__examples__/edit_menu.examples.tsx create mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/edit_menu.tsx create mode 100644 x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/index.ts diff --git a/x-pack/legacy/plugins/canvas/i18n/components.ts b/x-pack/legacy/plugins/canvas/i18n/components.ts index b1c2b41f062f1..de16bc2101e8c 100644 --- a/x-pack/legacy/plugins/canvas/i18n/components.ts +++ b/x-pack/legacy/plugins/canvas/i18n/components.ts @@ -804,17 +804,6 @@ export const ComponentStrings = { }), }, SidebarHeader: { - getAlignmentMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.alignmentMenuItemLabel', { - defaultMessage: 'Alignment', - description: - 'This refers to the vertical (i.e. left, center, right) and horizontal (i.e. top, middle, bottom) ' + - 'alignment options of the selected elements', - }), - getBottomAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.bottomAlignMenuItemLabel', { - defaultMessage: 'Bottom', - }), getBringForwardAriaLabel: () => i18n.translate('xpack.canvas.sidebarHeader.bringForwardArialLabel', { defaultMessage: 'Move element up one layer', @@ -823,56 +812,6 @@ export const ComponentStrings = { i18n.translate('xpack.canvas.sidebarHeader.bringToFrontArialLabel', { defaultMessage: 'Move element to top layer', }), - getCenterAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.centerAlignMenuItemLabel', { - defaultMessage: 'Center', - description: 'This refers to alignment centered horizontally.', - }), - getContextMenuTitle: () => - i18n.translate('xpack.canvas.sidebarHeader.contextMenuAriaLabel', { - defaultMessage: 'Element options', - }), - getCreateElementModalTitle: () => - i18n.translate('xpack.canvas.sidebarHeader.createElementModalTitle', { - defaultMessage: 'Create new element', - }), - getDistributionMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.distributionMenutItemLabel', { - defaultMessage: 'Distribution', - description: - 'This refers to the options to evenly spacing the selected elements horizontall or vertically.', - }), - getGroupMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.groupMenuItemLabel', { - defaultMessage: 'Group', - description: 'This refers to grouping multiple selected elements.', - }), - getHorizontalDistributionMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.horizontalDistributionMenutItemLabel', { - defaultMessage: 'Horizontal', - }), - getLeftAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.leftAlignMenuItemLabel', { - defaultMessage: 'Left', - }), - getMiddleAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.middleAlignMenuItemLabel', { - defaultMessage: 'Middle', - description: 'This refers to alignment centered vertically.', - }), - getOrderMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.orderMenuItemLabel', { - defaultMessage: 'Order', - description: 'Refers to the order of the elements displayed on the page from front to back', - }), - getRightAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.rightAlignMenuItemLabel', { - defaultMessage: 'Right', - }), - getSaveElementMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.savedElementMenuItemLabel', { - defaultMessage: 'Save as new element', - }), getSendBackwardAriaLabel: () => i18n.translate('xpack.canvas.sidebarHeader.sendBackwardArialLabel', { defaultMessage: 'Move element down one layer', @@ -881,19 +820,6 @@ export const ComponentStrings = { i18n.translate('xpack.canvas.sidebarHeader.sendToBackArialLabel', { defaultMessage: 'Move element to bottom layer', }), - getTopAlignMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.topAlignMenuItemLabel', { - defaultMessage: 'Top', - }), - getUngroupMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.ungroupMenuItemLabel', { - defaultMessage: 'Ungroup', - description: 'This refers to ungrouping a grouped element', - }), - getVerticalDistributionMenuItemLabel: () => - i18n.translate('xpack.canvas.sidebarHeader.verticalDistributionMenutItemLabel', { - defaultMessage: 'Vertical', - }), }, TextStylePicker: { getAlignCenterOption: () => @@ -1099,6 +1025,94 @@ export const ComponentStrings = { defaultMessage: 'Set a custom interval', }), }, + WorkpadHeaderEditMenu: { + getAlignmentMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.alignmentMenuItemLabel', { + defaultMessage: 'Alignment', + description: + 'This refers to the vertical (i.e. left, center, right) and horizontal (i.e. top, middle, bottom) ' + + 'alignment options of the selected elements', + }), + getBottomAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.bottomAlignMenuItemLabel', { + defaultMessage: 'Bottom', + }), + getCenterAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.centerAlignMenuItemLabel', { + defaultMessage: 'Center', + description: 'This refers to alignment centered horizontally.', + }), + getCreateElementModalTitle: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.createElementModalTitle', { + defaultMessage: 'Create new element', + }), + getDistributionMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.distributionMenutItemLabel', { + defaultMessage: 'Distribution', + description: + 'This refers to the options to evenly spacing the selected elements horizontall or vertically.', + }), + getEditMenuButtonLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.editMenuButtonLabel', { + defaultMessage: 'Edit', + }), + getEditMenuLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.editMenuLabel', { + defaultMessage: 'Edit options', + }), + getGroupMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.groupMenuItemLabel', { + defaultMessage: 'Group', + description: 'This refers to grouping multiple selected elements.', + }), + getHorizontalDistributionMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.horizontalDistributionMenutItemLabel', { + defaultMessage: 'Horizontal', + }), + getLeftAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.leftAlignMenuItemLabel', { + defaultMessage: 'Left', + }), + getMiddleAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.middleAlignMenuItemLabel', { + defaultMessage: 'Middle', + description: 'This refers to alignment centered vertically.', + }), + getOrderMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.orderMenuItemLabel', { + defaultMessage: 'Order', + description: 'Refers to the order of the elements displayed on the page from front to back', + }), + getRedoMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.redoMenuItemLabel', { + defaultMessage: 'Redo', + }), + getRightAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.rightAlignMenuItemLabel', { + defaultMessage: 'Right', + }), + getSaveElementMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.savedElementMenuItemLabel', { + defaultMessage: 'Save as new element', + }), + getTopAlignMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.topAlignMenuItemLabel', { + defaultMessage: 'Top', + }), + getUndoMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.undoMenuItemLabel', { + defaultMessage: 'Undo', + }), + getUngroupMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.ungroupMenuItemLabel', { + defaultMessage: 'Ungroup', + description: 'This refers to ungrouping a grouped element', + }), + getVerticalDistributionMenuItemLabel: () => + i18n.translate('xpack.canvas.workpadHeaderEditMenu.verticalDistributionMenutItemLabel', { + defaultMessage: 'Vertical', + }), + }, WorkpadHeaderElementMenu: { getAssetsMenuItemLabel: () => i18n.translate('xpack.canvas.workpadHeaderElementMenu.manageAssetsMenuItemLabel', { diff --git a/x-pack/legacy/plugins/canvas/i18n/shortcuts.ts b/x-pack/legacy/plugins/canvas/i18n/shortcuts.ts index 32b07a45c17db..124d70ff3095f 100644 --- a/x-pack/legacy/plugins/canvas/i18n/shortcuts.ts +++ b/x-pack/legacy/plugins/canvas/i18n/shortcuts.ts @@ -42,10 +42,10 @@ export const ShortcutStrings = { defaultMessage: 'Delete', }), BRING_FORWARD: i18n.translate('xpack.canvas.keyboardShortcuts.bringFowardShortcutHelpText', { - defaultMessage: 'Bring to front', + defaultMessage: 'Bring forward', }), BRING_TO_FRONT: i18n.translate('xpack.canvas.keyboardShortcuts.bringToFrontShortcutHelpText', { - defaultMessage: 'Bring forward', + defaultMessage: 'Bring to front', }), SEND_BACKWARD: i18n.translate('xpack.canvas.keyboardShortcuts.sendBackwardShortcutHelpText', { defaultMessage: 'Send backward', diff --git a/x-pack/legacy/plugins/canvas/public/apps/workpad/workpad_app/workpad_app.js b/x-pack/legacy/plugins/canvas/public/apps/workpad/workpad_app/workpad_app.js index b8e1bece6ac30..fc3ac9922355a 100644 --- a/x-pack/legacy/plugins/canvas/public/apps/workpad/workpad_app/workpad_app.js +++ b/x-pack/legacy/plugins/canvas/public/apps/workpad/workpad_app/workpad_app.js @@ -43,7 +43,7 @@ export class WorkpadApp extends React.PureComponent {
    - + {})} />
    - {})} /> +
    )}
    diff --git a/x-pack/legacy/plugins/canvas/public/components/keyboard_shortcuts_doc/__examples__/__snapshots__/keyboard_shortcuts_doc.stories.storyshot b/x-pack/legacy/plugins/canvas/public/components/keyboard_shortcuts_doc/__examples__/__snapshots__/keyboard_shortcuts_doc.stories.storyshot index 503677687ba12..d59d03578a363 100644 --- a/x-pack/legacy/plugins/canvas/public/components/keyboard_shortcuts_doc/__examples__/__snapshots__/keyboard_shortcuts_doc.stories.storyshot +++ b/x-pack/legacy/plugins/canvas/public/components/keyboard_shortcuts_doc/__examples__/__snapshots__/keyboard_shortcuts_doc.stories.storyshot @@ -212,7 +212,7 @@ exports[`Storyshots components/KeyboardShortcutsDoc default 1`] = `
    - Bring forward + Bring to front
    - Bring to front + Bring forward
    ({ selectedToplevelNodes: getSelectedToplevelNodes(state), selectedElementId: getSelectedElementId(state), - state, }); -const mergeProps = ( - { state, ...restStateProps }, - { dispatch, ...restDispatchProps }, - ownProps -) => ({ - ...ownProps, - ...restDispatchProps, - ...restStateProps, - updateGlobalState: globalStateUpdater(dispatch, state), -}); - -const withGlobalState = (commit, updateGlobalState) => (type, payload) => { - const newLayoutState = commit(type, payload); - if (newLayoutState.currentScene.gestureEnd) { - updateGlobalState(newLayoutState); - } -}; - -const MultiElementSidebar = ({ commit, updateGlobalState }) => ( +const MultiElementSidebar = () => ( - + ); -const GroupedElementSidebar = ({ commit, updateGlobalState }) => ( +const GroupedElementSidebar = () => ( - + @@ -92,7 +65,4 @@ const branches = [ ), ]; -export const SidebarContent = compose( - connect(mapStateToProps, null, mergeProps), - ...branches -)(GlobalConfig); +export const SidebarContent = compose(connect(mapStateToProps), ...branches)(GlobalConfig); diff --git a/x-pack/legacy/plugins/canvas/public/components/sidebar_header/__examples__/__snapshots__/sidebar_header.stories.storyshot b/x-pack/legacy/plugins/canvas/public/components/sidebar_header/__examples__/__snapshots__/sidebar_header.stories.storyshot index ac25cbe0b6832..4d5b9570ee20f 100644 --- a/x-pack/legacy/plugins/canvas/public/components/sidebar_header/__examples__/__snapshots__/sidebar_header.stories.storyshot +++ b/x-pack/legacy/plugins/canvas/public/components/sidebar_header/__examples__/__snapshots__/sidebar_header.stories.storyshot @@ -20,80 +20,6 @@ exports[`Storyshots components/Sidebar/SidebarHeader default 1`] = ` Selected layer
    -
    -
    -
    - - - -
    -
    - -
    -
    -
  • `; @@ -224,72 +150,6 @@ exports[`Storyshots components/Sidebar/SidebarHeader with layer controls 1`] = ` -
    - - - -
    -
    - -
    diff --git a/x-pack/legacy/plugins/canvas/public/components/sidebar_header/__examples__/sidebar_header.stories.tsx b/x-pack/legacy/plugins/canvas/public/components/sidebar_header/__examples__/sidebar_header.stories.tsx index 9baff380fc3eb..11c66906a6ef6 100644 --- a/x-pack/legacy/plugins/canvas/public/components/sidebar_header/__examples__/sidebar_header.stories.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/sidebar_header/__examples__/sidebar_header.stories.tsx @@ -10,26 +10,10 @@ import { action } from '@storybook/addon-actions'; import { SidebarHeader } from '../sidebar_header'; const handlers = { - cloneNodes: action('cloneNodes'), - copyNodes: action('copyNodes'), - cutNodes: action('cutNodes'), - pasteNodes: action('pasteNodes'), - deleteNodes: action('deleteNodes'), bringToFront: action('bringToFront'), bringForward: action('bringForward'), sendBackward: action('sendBackward'), sendToBack: action('sendToBack'), - createCustomElement: action('createCustomElement'), - groupNodes: action('groupNodes'), - ungroupNodes: action('ungroupNodes'), - alignLeft: action('alignLeft'), - alignMiddle: action('alignMiddle'), - alignRight: action('alignRight'), - alignTop: action('alignTop'), - alignCenter: action('alignCenter'), - alignBottom: action('alignBottom'), - distributeHorizontally: action('distributeHorizontally'), - distributeVertically: action('distributeVertically'), }; storiesOf('components/Sidebar/SidebarHeader', module) diff --git a/x-pack/legacy/plugins/canvas/public/components/sidebar_header/sidebar_header.tsx b/x-pack/legacy/plugins/canvas/public/components/sidebar_header/sidebar_header.tsx index 925e68a565f04..024a2dbb41a24 100644 --- a/x-pack/legacy/plugins/canvas/public/components/sidebar_header/sidebar_header.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/sidebar_header/sidebar_header.tsx @@ -4,25 +4,12 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { Component, Fragment } from 'react'; +import React, { FunctionComponent } from 'react'; import PropTypes from 'prop-types'; -import { - EuiFlexGroup, - EuiFlexItem, - EuiTitle, - EuiButtonIcon, - EuiContextMenu, - EuiToolTip, - EuiContextMenuPanelItemDescriptor, - EuiContextMenuPanelDescriptor, - EuiOverlayMask, -} from '@elastic/eui'; -import { Popover } from '../popover'; -import { CustomElementModal } from '../custom_element_modal'; +import { EuiFlexGroup, EuiFlexItem, EuiTitle, EuiButtonIcon, EuiToolTip } from '@elastic/eui'; import { ToolTipShortcut } from '../tool_tip_shortcut/'; import { ComponentStrings } from '../../../i18n/components'; import { ShortcutStrings } from '../../../i18n/shortcuts'; -import { CONTEXT_MENU_TOP_BORDER_CLASSNAME } from '../../../common/lib/constants'; const { SidebarHeader: strings } = ComponentStrings; const shortcutHelp = ShortcutStrings.getShortcutHelp(); @@ -36,26 +23,6 @@ interface Props { * indicated whether or not layer controls should be displayed */ showLayerControls?: boolean; - /** - * cuts selected elements - */ - cutNodes: () => void; - /** - * copies selected elements to clipboard - */ - copyNodes: () => void; - /** - * pastes elements stored in clipboard to page - */ - pasteNodes: () => void; - /** - * clones selected elements - */ - cloneNodes: () => void; - /** - * deletes selected elements - */ - deleteNodes: () => void; /** * moves selected element to top layer */ @@ -72,493 +39,117 @@ interface Props { * moves selected element to bottom layer */ sendToBack: () => void; - /** - * saves the selected elements as an custom-element saved object - */ - createCustomElement: (name: string, description: string, image: string) => void; - /** - * indicated whether the selected element is a group or not - */ - groupIsSelected: boolean; - /** - * only more than one selected element can be grouped - */ - selectedNodes: string[]; - /** - * groups selected elements - */ - groupNodes: () => void; - /** - * ungroups selected group - */ - ungroupNodes: () => void; - /** - * left align selected elements - */ - alignLeft: () => void; - /** - * center align selected elements - */ - alignCenter: () => void; - /** - * right align selected elements - */ - alignRight: () => void; - /** - * top align selected elements - */ - alignTop: () => void; - /** - * middle align selected elements - */ - alignMiddle: () => void; - /** - * bottom align selected elements - */ - alignBottom: () => void; - /** - * horizontally distribute selected elements - */ - distributeHorizontally: () => void; - /** - * vertically distribute selected elements - */ - distributeVertically: () => void; -} - -interface State { - /** - * indicates whether or not the custom element modal is open - */ - isModalVisible: boolean; -} - -interface MenuTuple { - menuItem: EuiContextMenuPanelItemDescriptor; - panel: EuiContextMenuPanelDescriptor; } -const contextMenuButton = (handleClick: React.MouseEventHandler) => ( - -); - -export class SidebarHeader extends Component { - public static propTypes = { - title: PropTypes.string.isRequired, - showLayerControls: PropTypes.bool, // TODO: remove when we support relayering multiple elements - cutNodes: PropTypes.func.isRequired, - copyNodes: PropTypes.func.isRequired, - pasteNodes: PropTypes.func.isRequired, - cloneNodes: PropTypes.func.isRequired, - deleteNodes: PropTypes.func.isRequired, - bringToFront: PropTypes.func.isRequired, - bringForward: PropTypes.func.isRequired, - sendBackward: PropTypes.func.isRequired, - sendToBack: PropTypes.func.isRequired, - createCustomElement: PropTypes.func.isRequired, - groupIsSelected: PropTypes.bool, - selectedNodes: PropTypes.array, - groupNodes: PropTypes.func.isRequired, - ungroupNodes: PropTypes.func.isRequired, - alignLeft: PropTypes.func.isRequired, - alignCenter: PropTypes.func.isRequired, - alignRight: PropTypes.func.isRequired, - alignTop: PropTypes.func.isRequired, - alignMiddle: PropTypes.func.isRequired, - alignBottom: PropTypes.func.isRequired, - distributeHorizontally: PropTypes.func.isRequired, - distributeVertically: PropTypes.func.isRequired, - }; - - public static defaultProps = { - groupIsSelected: false, - showLayerControls: false, - selectedNodes: [], - }; - - public state = { - isModalVisible: false, - }; - - private _isMounted = false; - private _showModal = () => this._isMounted && this.setState({ isModalVisible: true }); - private _hideModal = () => this._isMounted && this.setState({ isModalVisible: false }); - - public componentDidMount() { - this._isMounted = true; - } - - public componentWillUnmount() { - this._isMounted = false; - } - - private _renderLayoutControls = () => { - const { bringToFront, bringForward, sendBackward, sendToBack } = this.props; - return ( - - - - {shortcutHelp.BRING_TO_FRONT} - - - } - > - - - - - - {shortcutHelp.BRING_FORWARD} - - - } - > - - - - - - {shortcutHelp.SEND_BACKWARD} - - - } - > - - - - - - {shortcutHelp.SEND_TO_BACK} - - - } - > - - - - - ); - }; - - private _getLayerMenuItems = (): MenuTuple => { - const { bringToFront, bringForward, sendBackward, sendToBack } = this.props; - - return { - menuItem: { - name: strings.getOrderMenuItemLabel(), - className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, - panel: 1, - }, - panel: { - id: 1, - title: strings.getOrderMenuItemLabel(), - items: [ - { - name: shortcutHelp.BRING_TO_FRONT, // TODO: check against current element position and disable if already top layer - icon: 'sortUp', - onClick: bringToFront, - }, - { - name: shortcutHelp.BRING_TO_FRONT, // TODO: same as above - icon: 'arrowUp', - onClick: bringForward, - }, - { - name: shortcutHelp.SEND_BACKWARD, // TODO: check against current element position and disable if already bottom layer - icon: 'arrowDown', - onClick: sendBackward, - }, - { - name: shortcutHelp.SEND_TO_BACK, // TODO: same as above - icon: 'sortDown', - onClick: sendToBack, - }, - ], - }, - }; - }; - - private _getAlignmentMenuItems = (close: (fn: () => void) => () => void): MenuTuple => { - const { alignLeft, alignCenter, alignRight, alignTop, alignMiddle, alignBottom } = this.props; - - return { - menuItem: { - name: strings.getAlignmentMenuItemLabel(), - className: 'canvasContextMenu', - panel: 2, - }, - panel: { - id: 2, - title: strings.getAlignmentMenuItemLabel(), - items: [ - { - name: strings.getLeftAlignMenuItemLabel(), - icon: 'editorItemAlignLeft', - onClick: close(alignLeft), - }, - { - name: strings.getCenterAlignMenuItemLabel(), - icon: 'editorItemAlignCenter', - onClick: close(alignCenter), - }, - { - name: strings.getRightAlignMenuItemLabel(), - icon: 'editorItemAlignRight', - onClick: close(alignRight), - }, - { - name: strings.getTopAlignMenuItemLabel(), - icon: 'editorItemAlignTop', - onClick: close(alignTop), - }, - { - name: strings.getMiddleAlignMenuItemLabel(), - icon: 'editorItemAlignMiddle', - onClick: close(alignMiddle), - }, - { - name: strings.getBottomAlignMenuItemLabel(), - icon: 'editorItemAlignBottom', - onClick: close(alignBottom), - }, - ], - }, - }; - }; - - private _getDistributionMenuItems = (close: (fn: () => void) => () => void): MenuTuple => { - const { distributeHorizontally, distributeVertically } = this.props; - - return { - menuItem: { - name: strings.getDistributionMenuItemLabel(), - className: 'canvasContextMenu', - panel: 3, - }, - panel: { - id: 3, - title: strings.getDistributionMenuItemLabel(), - items: [ - { - name: strings.getHorizontalDistributionMenuItemLabel(), - icon: 'editorDistributeHorizontal', - onClick: close(distributeHorizontally), - }, - { - name: strings.getVerticalDistributionMenuItemLabel(), - icon: 'editorDistributeVertical', - onClick: close(distributeVertically), - }, - ], - }, - }; - }; - - private _getGroupMenuItems = ( - close: (fn: () => void) => () => void - ): EuiContextMenuPanelItemDescriptor[] => { - const { groupIsSelected, ungroupNodes, groupNodes, selectedNodes } = this.props; - return groupIsSelected - ? [ - { - name: strings.getUngroupMenuItemLabel(), - className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, - onClick: close(ungroupNodes), - }, - ] - : selectedNodes.length > 1 - ? [ - { - name: strings.getGroupMenuItemLabel(), - className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, - onClick: close(groupNodes), - }, - ] - : []; - }; - - private _getPanels = (closePopover: () => void): EuiContextMenuPanelDescriptor[] => { - const { - showLayerControls, - cutNodes, - copyNodes, - pasteNodes, - deleteNodes, - cloneNodes, - } = this.props; - - // closes popover after invoking fn - const close = (fn: () => void) => () => { - fn(); - closePopover(); - }; - - const items: EuiContextMenuPanelItemDescriptor[] = [ - { - name: shortcutHelp.CUT, - icon: 'cut', - onClick: close(cutNodes), - }, - { - name: shortcutHelp.COPY, - icon: 'copy', - onClick: copyNodes, - }, - { - name: shortcutHelp.PASTE, // TODO: can this be disabled if clipboard is empty? - icon: 'copyClipboard', - onClick: close(pasteNodes), - }, - { - name: shortcutHelp.DELETE, - icon: 'trash', - onClick: close(deleteNodes), - }, - { - name: shortcutHelp.CLONE, - onClick: close(cloneNodes), - }, - ...this._getGroupMenuItems(close), - ]; - - const panels: EuiContextMenuPanelDescriptor[] = [ - { - id: 0, - title: strings.getContextMenuTitle(), - items, - }, - ]; - - const fillMenu = ({ menuItem, panel }: MenuTuple) => { - items.push(menuItem); // add Order menu item to first panel - panels.push(panel); // add nested panel for layers controls - }; - - if (showLayerControls) { - fillMenu(this._getLayerMenuItems()); - } - - if (this.props.selectedNodes.length > 1) { - fillMenu(this._getAlignmentMenuItems(close)); - } - - if (this.props.selectedNodes.length > 2) { - fillMenu(this._getDistributionMenuItems(close)); - } - - items.push({ - name: strings.getSaveElementMenuItemLabel(), - icon: 'indexOpen', - className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, - onClick: this._showModal, - }); - - return panels; - }; - - private _renderContextMenu = () => ( - - {({ closePopover }: { closePopover: () => void }) => ( - - )} - - ); - - private _handleSave = (name: string, description: string, image: string) => { - const { createCustomElement } = this.props; - createCustomElement(name, description, image); - this._hideModal(); - }; - - render() { - const { title, showLayerControls } = this.props; - const { isModalVisible } = this.state; - - return ( - - +export const SidebarHeader: FunctionComponent = ({ + title, + showLayerControls, + bringToFront, + bringForward, + sendBackward, + sendToBack, +}) => ( + + + +

    {title}

    +
    +
    + {showLayerControls ? ( + + - -

    {title}

    -
    + + {shortcutHelp.BRING_TO_FRONT} + + + } + > + +
    - - {showLayerControls ? this._renderLayoutControls() : null} - - - - - - {this._renderContextMenu()} - + + {shortcutHelp.BRING_FORWARD} + + + } + > + + + + + + {shortcutHelp.SEND_BACKWARD} + + + } + > + + + + + + {shortcutHelp.SEND_TO_BACK} + + + } + > + +
    - {isModalVisible ? ( - - - - ) : null} -
    - ); - } -} + + ) : null} + +); + +SidebarHeader.propTypes = { + title: PropTypes.string.isRequired, + showLayerControls: PropTypes.bool, // TODO: remove when we support relayering multiple elements + bringToFront: PropTypes.func.isRequired, + bringForward: PropTypes.func.isRequired, + sendBackward: PropTypes.func.isRequired, + sendToBack: PropTypes.func.isRequired, +}; + +SidebarHeader.defaultProps = { + showLayerControls: false, +}; diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/__examples__/__snapshots__/edit_menu.examples.storyshot b/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/__examples__/__snapshots__/edit_menu.examples.storyshot new file mode 100644 index 0000000000000..42c59d41dca62 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/__examples__/__snapshots__/edit_menu.examples.storyshot @@ -0,0 +1,205 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Storyshots components/WorkpadHeader/EditMenu 2 elements selected 1`] = ` +
    +
    + +
    +
    +`; + +exports[`Storyshots components/WorkpadHeader/EditMenu 3+ elements selected 1`] = ` +
    +
    + +
    +
    +`; + +exports[`Storyshots components/WorkpadHeader/EditMenu clipboard data exists 1`] = ` +
    +
    + +
    +
    +`; + +exports[`Storyshots components/WorkpadHeader/EditMenu default 1`] = ` +
    +
    + +
    +
    +`; + +exports[`Storyshots components/WorkpadHeader/EditMenu single element selected 1`] = ` +
    +
    + +
    +
    +`; + +exports[`Storyshots components/WorkpadHeader/EditMenu single grouped element selected 1`] = ` +
    +
    + +
    +
    +`; diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/__examples__/edit_menu.examples.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/__examples__/edit_menu.examples.tsx new file mode 100644 index 0000000000000..a0ab8d53485f5 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/__examples__/edit_menu.examples.tsx @@ -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 { storiesOf } from '@storybook/react'; +import { action } from '@storybook/addon-actions'; +import React from 'react'; +import { EditMenu } from '../edit_menu'; + +const handlers = { + cutNodes: action('cutNodes'), + copyNodes: action('copyNodes'), + pasteNodes: action('pasteNodes'), + deleteNodes: action('deleteNodes'), + cloneNodes: action('cloneNodes'), + bringToFront: action('bringToFront'), + bringForward: action('bringForward'), + sendBackward: action('sendBackward'), + sendToBack: action('sendToBack'), + alignLeft: action('alignLeft'), + alignCenter: action('alignCenter'), + alignRight: action('alignRight'), + alignTop: action('alignTop'), + alignMiddle: action('alignMiddle'), + alignBottom: action('alignBottom'), + distributeHorizontally: action('distributeHorizontally'), + distributeVertically: action('distributeVertically'), + createCustomElement: action('createCustomElement'), + groupNodes: action('groupNodes'), + ungroupNodes: action('ungroupNodes'), + undoHistory: action('undoHistory'), + redoHistory: action('redoHistory'), +}; + +storiesOf('components/WorkpadHeader/EditMenu', module) + .add('default', () => ( + + )) + .add('clipboard data exists', () => ( + + )) + .add('single element selected', () => ( + + )) + .add('single grouped element selected', () => ( + + )) + .add('2 elements selected', () => ( + + )) + .add('3+ elements selected', () => ( + + )); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/edit_menu.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/edit_menu.tsx new file mode 100644 index 0000000000000..15191b8d416ff --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/edit_menu.tsx @@ -0,0 +1,448 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, FunctionComponent, useState } from 'react'; +import PropTypes from 'prop-types'; +import { EuiButtonEmpty, EuiContextMenu, EuiIcon, EuiOverlayMask } from '@elastic/eui'; +import { ComponentStrings } from '../../../../i18n/components'; +import { ShortcutStrings } from '../../../../i18n/shortcuts'; +import { flattenPanelTree } from '../../../lib/flatten_panel_tree'; +import { Popover, ClosePopoverFn } from '../../popover'; +import { CustomElementModal } from '../../custom_element_modal'; +import { CONTEXT_MENU_TOP_BORDER_CLASSNAME } from '../../../../common/lib/constants'; + +const { WorkpadHeaderEditMenu: strings } = ComponentStrings; +const shortcutHelp = ShortcutStrings.getShortcutHelp(); + +export interface Props { + /** + * cuts selected elements + */ + cutNodes: () => void; + /** + * copies selected elements to clipboard + */ + copyNodes: () => void; + /** + * pastes elements stored in clipboard to page + */ + pasteNodes: () => void; + /** + * clones selected elements + */ + cloneNodes: () => void; + /** + * deletes selected elements + */ + deleteNodes: () => void; + /** + * moves selected element to top layer + */ + bringToFront: () => void; + /** + * moves selected element up one layer + */ + bringForward: () => void; + /** + * moves selected element down one layer + */ + sendBackward: () => void; + /** + * moves selected element to bottom layer + */ + sendToBack: () => void; + /** + * saves the selected elements as an custom-element saved object + */ + createCustomElement: (name: string, description: string, image: string) => void; + /** + * indicated whether the selected element is a group or not + */ + groupIsSelected: boolean; + /** + * only more than one selected element can be grouped + */ + selectedNodes: string[]; + /** + * groups selected elements + */ + groupNodes: () => void; + /** + * ungroups selected group + */ + ungroupNodes: () => void; + /** + * left align selected elements + */ + alignLeft: () => void; + /** + * center align selected elements + */ + alignCenter: () => void; + /** + * right align selected elements + */ + alignRight: () => void; + /** + * top align selected elements + */ + alignTop: () => void; + /** + * middle align selected elements + */ + alignMiddle: () => void; + /** + * bottom align selected elements + */ + alignBottom: () => void; + /** + * horizontally distribute selected elements + */ + distributeHorizontally: () => void; + /** + * vertically distribute selected elements + */ + distributeVertically: () => void; + /** + * Reverts last change to the workpad + */ + undoHistory: () => void; + /** + * Reapplies last reverted change to the workpad + */ + redoHistory: () => void; + /** + * Is there element clipboard data to paste? + */ + hasPasteData: boolean; +} + +export const EditMenu: FunctionComponent = ({ + cutNodes, + copyNodes, + pasteNodes, + deleteNodes, + cloneNodes, + bringToFront, + bringForward, + sendBackward, + sendToBack, + alignLeft, + alignCenter, + alignRight, + alignTop, + alignMiddle, + alignBottom, + distributeHorizontally, + distributeVertically, + createCustomElement, + selectedNodes, + groupIsSelected, + groupNodes, + ungroupNodes, + undoHistory, + redoHistory, + hasPasteData, +}) => { + const [isModalVisible, setModalVisible] = useState(false); + const showModal = () => setModalVisible(true); + const hideModal = () => setModalVisible(false); + + const handleSave = (name: string, description: string, image: string) => { + createCustomElement(name, description, image); + hideModal(); + }; + + const editControl = (togglePopover: React.MouseEventHandler) => ( + + {strings.getEditMenuButtonLabel()} + + ); + + const getPanelTree = (closePopover: ClosePopoverFn) => { + const groupMenuItem = groupIsSelected + ? { + name: strings.getUngroupMenuItemLabel(), + className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, + icon: , + onClick: () => { + ungroupNodes(); + closePopover(); + }, + } + : { + name: strings.getGroupMenuItemLabel(), + className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, + icon: , + disabled: selectedNodes.length < 2, + onClick: () => { + groupNodes(); + closePopover(); + }, + }; + + const orderMenuItem = { + name: strings.getOrderMenuItemLabel(), + disabled: selectedNodes.length !== 1, // TODO: change to === 0 when we support relayering multiple elements + icon: , + panel: { + id: 1, + title: strings.getOrderMenuItemLabel(), + items: [ + { + name: shortcutHelp.BRING_TO_FRONT, // TODO: check against current element position and disable if already top layer + icon: 'sortUp', + onClick: bringToFront, + }, + { + name: shortcutHelp.BRING_FORWARD, // TODO: same as above + icon: 'arrowUp', + onClick: bringForward, + }, + { + name: shortcutHelp.SEND_BACKWARD, // TODO: check against current element position and disable if already bottom layer + icon: 'arrowDown', + onClick: sendBackward, + }, + { + name: shortcutHelp.SEND_TO_BACK, // TODO: same as above + icon: 'sortDown', + onClick: sendToBack, + }, + ], + }, + }; + + const alignmentMenuItem = { + name: strings.getAlignmentMenuItemLabel(), + className: 'canvasContextMenu', + disabled: groupIsSelected || selectedNodes.length < 2, + icon: , + panel: { + id: 2, + title: strings.getAlignmentMenuItemLabel(), + items: [ + { + name: strings.getLeftAlignMenuItemLabel(), + icon: 'editorItemAlignLeft', + onClick: () => { + alignLeft(); + closePopover(); + }, + }, + { + name: strings.getCenterAlignMenuItemLabel(), + icon: 'editorItemAlignCenter', + onClick: () => { + alignCenter(); + closePopover(); + }, + }, + { + name: strings.getRightAlignMenuItemLabel(), + icon: 'editorItemAlignRight', + onClick: () => { + alignRight(); + closePopover(); + }, + }, + { + name: strings.getTopAlignMenuItemLabel(), + icon: 'editorItemAlignTop', + onClick: () => { + alignTop(); + closePopover(); + }, + }, + { + name: strings.getMiddleAlignMenuItemLabel(), + icon: 'editorItemAlignMiddle', + onClick: () => { + alignMiddle(); + closePopover(); + }, + }, + { + name: strings.getBottomAlignMenuItemLabel(), + icon: 'editorItemAlignBottom', + onClick: () => { + alignBottom(); + closePopover(); + }, + }, + ], + }, + }; + + const distributionMenuItem = { + name: strings.getDistributionMenuItemLabel(), + className: 'canvasContextMenu', + disabled: groupIsSelected || selectedNodes.length < 3, + icon: , + panel: { + id: 3, + title: strings.getAlignmentMenuItemLabel(), + items: [ + { + name: strings.getHorizontalDistributionMenuItemLabel(), + icon: 'editorDistributeHorizontal', + onClick: () => { + distributeHorizontally(); + closePopover(); + }, + }, + { + name: strings.getVerticalDistributionMenuItemLabel(), + icon: 'editorDistributeVertical', + onClick: () => { + distributeVertically(); + closePopover(); + }, + }, + ], + }, + }; + + const savedElementMenuItem = { + name: strings.getSaveElementMenuItemLabel(), + icon: , + disabled: selectedNodes.length < 1, + className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, + 'data-test-subj': 'canvasWorkpadEditMenu__saveElementButton', + onClick: () => { + showModal(); + closePopover(); + }, + }; + + const items = [ + { + // TODO: check history and disable when there are no more changes to revert + name: strings.getUndoMenuItemLabel(), + icon: , + onClick: () => { + undoHistory(); + }, + }, + { + // TODO: check history and disable when there are no more changes to reapply + name: strings.getRedoMenuItemLabel(), + icon: , + onClick: () => { + redoHistory(); + }, + }, + { + name: shortcutHelp.CUT, + icon: , + className: CONTEXT_MENU_TOP_BORDER_CLASSNAME, + disabled: selectedNodes.length < 1, + onClick: () => { + cutNodes(); + closePopover(); + }, + }, + { + name: shortcutHelp.COPY, + disabled: selectedNodes.length < 1, + icon: , + onClick: () => { + copyNodes(); + }, + }, + { + name: shortcutHelp.PASTE, // TODO: can this be disabled if clipboard is empty? + icon: , + disabled: !hasPasteData, + onClick: () => { + pasteNodes(); + closePopover(); + }, + }, + { + name: shortcutHelp.DELETE, + icon: , + disabled: selectedNodes.length < 1, + onClick: () => { + deleteNodes(); + closePopover(); + }, + }, + { + name: shortcutHelp.CLONE, + icon: , + disabled: selectedNodes.length < 1, + onClick: () => { + cloneNodes(); + closePopover(); + }, + }, + groupMenuItem, + orderMenuItem, + alignmentMenuItem, + distributionMenuItem, + savedElementMenuItem, + ]; + + return { + id: 0, + // title: strings.getEditMenuLabel(), + items, + }; + }; + + return ( + + + {({ closePopover }: { closePopover: ClosePopoverFn }) => ( + + )} + + {isModalVisible ? ( + + + + ) : null} + + ); +}; + +EditMenu.propTypes = { + cutNodes: PropTypes.func.isRequired, + copyNodes: PropTypes.func.isRequired, + pasteNodes: PropTypes.func.isRequired, + deleteNodes: PropTypes.func.isRequired, + cloneNodes: PropTypes.func.isRequired, + bringToFront: PropTypes.func.isRequired, + bringForward: PropTypes.func.isRequired, + sendBackward: PropTypes.func.isRequired, + sendToBack: PropTypes.func.isRequired, + alignLeft: PropTypes.func.isRequired, + alignCenter: PropTypes.func.isRequired, + alignRight: PropTypes.func.isRequired, + alignTop: PropTypes.func.isRequired, + alignMiddle: PropTypes.func.isRequired, + alignBottom: PropTypes.func.isRequired, + distributeHorizontally: PropTypes.func.isRequired, + distributeVertically: PropTypes.func.isRequired, + createCustomElement: PropTypes.func.isRequired, + selectedNodes: PropTypes.arrayOf(PropTypes.string).isRequired, + groupIsSelected: PropTypes.bool.isRequired, + groupNodes: PropTypes.func.isRequired, + ungroupNodes: PropTypes.func.isRequired, +}; diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/index.ts b/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/index.ts new file mode 100644 index 0000000000000..a8bb7177dbd24 --- /dev/null +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/edit_menu/index.ts @@ -0,0 +1,123 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { compose, withHandlers, withProps } from 'recompose'; +import { Dispatch } from 'redux'; +import { State, PositionedElement } from '../../../../types'; +import { getClipboardData } from '../../../lib/clipboard'; +// @ts-ignore Untyped local +import { flatten } from '../../../lib/aeroelastic/functional'; +// @ts-ignore Untyped local +import { globalStateUpdater } from '../../workpad_page/integration_utils'; +// @ts-ignore Untyped local +import { crawlTree } from '../../workpad_page/integration_utils'; +// @ts-ignore Untyped local +import { insertNodes, elementLayer, removeElements } from '../../../state/actions/elements'; +// @ts-ignore Untyped local +import { undoHistory, redoHistory } from '../../../state/actions/history'; +// @ts-ignore Untyped local +import { selectToplevelNodes } from '../../../state/actions/transient'; +import { + getSelectedPage, + getNodes, + getSelectedToplevelNodes, +} from '../../../state/selectors/workpad'; +import { + layerHandlerCreators, + clipboardHandlerCreators, + basicHandlerCreators, + groupHandlerCreators, + alignmentDistributionHandlerCreators, +} from '../../../lib/element_handler_creators'; +import { EditMenu as Component, Props as ComponentProps } from './edit_menu'; + +type LayoutState = any; + +type CommitFn = (type: string, payload: any) => LayoutState; + +interface OwnProps { + commit: CommitFn; +} + +const withGlobalState = ( + commit: CommitFn, + updateGlobalState: (layoutState: LayoutState) => void +) => (type: string, payload: any) => { + const newLayoutState = commit(type, payload); + if (newLayoutState.currentScene.gestureEnd) { + updateGlobalState(newLayoutState); + } +}; + +/* + * TODO: this is all copied from interactive_workpad_page and workpad_shortcuts + */ +const mapStateToProps = (state: State) => { + const pageId = getSelectedPage(state); + const nodes = getNodes(state, pageId) as PositionedElement[]; + const selectedToplevelNodes = getSelectedToplevelNodes(state); + const selectedPrimaryShapeObjects = selectedToplevelNodes + .map((id: string) => nodes.find((s: PositionedElement) => s.id === id)) + .filter((shape?: PositionedElement) => shape) as PositionedElement[]; + const selectedPersistentPrimaryNodes = flatten( + selectedPrimaryShapeObjects.map((shape: PositionedElement) => + nodes.find((n: PositionedElement) => n.id === shape.id) // is it a leaf or a persisted group? + ? [shape.id] + : nodes.filter((s: PositionedElement) => s.position.parent === shape.id).map(s => s.id) + ) + ); + const selectedNodeIds = flatten(selectedPersistentPrimaryNodes.map(crawlTree(nodes))); + + return { + pageId, + selectedToplevelNodes, + selectedNodes: selectedNodeIds.map((id: string) => nodes.find(s => s.id === id)), + state, + }; +}; + +const mapDispatchToProps = (dispatch: Dispatch) => ({ + insertNodes: (selectedNodes: PositionedElement[], pageId: string) => + dispatch(insertNodes(selectedNodes, pageId)), + removeNodes: (nodeIds: string[], pageId: string) => dispatch(removeElements(nodeIds, pageId)), + selectToplevelNodes: (nodes: PositionedElement[]) => + dispatch( + selectToplevelNodes(nodes.filter((e: PositionedElement) => !e.position.parent).map(e => e.id)) + ), + elementLayer: (pageId: string, elementId: string, movement: number) => { + dispatch(elementLayer({ pageId, elementId, movement })); + }, + undoHistory: () => dispatch(undoHistory()), + redoHistory: () => dispatch(redoHistory()), + dispatch, +}); + +const mergeProps = ( + { state, selectedToplevelNodes, ...restStateProps }: ReturnType, + { dispatch, ...restDispatchProps }: ReturnType, + { commit }: OwnProps +) => { + const updateGlobalState = globalStateUpdater(dispatch, state); + + return { + ...restDispatchProps, + ...restStateProps, + commit: withGlobalState(commit, updateGlobalState), + groupIsSelected: + selectedToplevelNodes.length === 1 && selectedToplevelNodes[0].includes('group'), + }; +}; + +export const EditMenu = compose( + connect(mapStateToProps, mapDispatchToProps, mergeProps), + withProps(() => ({ hasPasteData: Boolean(getClipboardData()) })), + withHandlers(basicHandlerCreators), + withHandlers(clipboardHandlerCreators), + withHandlers(layerHandlerCreators), + withHandlers(groupHandlerCreators), + withHandlers(alignmentDistributionHandlerCreators) +)(Component); diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/element_menu/element_menu.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/element_menu/element_menu.tsx index 5c420cf3a04c9..fbb5d70dfc55c 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/element_menu/element_menu.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/element_menu/element_menu.tsx @@ -139,7 +139,6 @@ export const ElementMenu: FunctionComponent = ({ return { id: 0, - title: strings.getElementMenuLabel(), items: [ elementListToMenuItems(textElements), elementListToMenuItems(shapeElements), diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx index 621077c29c368..2ac0591a1bdd4 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/share_menu/share_menu.tsx @@ -62,7 +62,6 @@ export const ShareMenu: FunctionComponent = ({ onCopy, onExport, getExpor const getPanelTree = (closePopover: ClosePopoverFn) => ({ id: 0, - title: strings.getShareWorkpadMessage(), items: [ { name: strings.getShareDownloadJSONTitle(), diff --git a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_header.tsx b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_header.tsx index 1f8e47b556771..4aab8280a9f24 100644 --- a/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_header.tsx +++ b/x-pack/legacy/plugins/canvas/public/components/workpad_header/workpad_header.tsx @@ -15,6 +15,7 @@ import { ToolTipShortcut } from '../tool_tip_shortcut/'; import { RefreshControl } from './refresh_control'; // @ts-ignore untyped local import { FullscreenControl } from './fullscreen_control'; +import { EditMenu } from './edit_menu'; import { ElementMenu } from './element_menu'; import { ShareMenu } from './share_menu'; import { ViewMenu } from './view_menu'; @@ -25,12 +26,14 @@ export interface Props { isWriteable: boolean; toggleWriteable: () => void; canUserWrite: boolean; + commit: (type: string, payload: any) => any; } export const WorkpadHeader: FunctionComponent = ({ isWriteable, canUserWrite, toggleWriteable, + commit, }) => { const keyHandler = (action: string) => { if (action === 'EDITING') { @@ -99,6 +102,9 @@ export const WorkpadHeader: FunctionComponent = ({ + + + diff --git a/x-pack/legacy/plugins/canvas/public/state/selectors/workpad.ts b/x-pack/legacy/plugins/canvas/public/state/selectors/workpad.ts index 1623035bd25ba..80a7c34e8bef5 100644 --- a/x-pack/legacy/plugins/canvas/public/state/selectors/workpad.ts +++ b/x-pack/legacy/plugins/canvas/public/state/selectors/workpad.ts @@ -363,7 +363,11 @@ export function getNodesForPage(page: CanvasPage, withAst: boolean): CanvasEleme } // todo unify or DRY up with `getElements` -export function getNodes(state: State, pageId: string, withAst = true): CanvasElement[] { +export function getNodes( + state: State, + pageId: string, + withAst = true +): CanvasElement[] | PositionedElement[] { const id = pageId || getSelectedPage(state); if (!id) { return []; diff --git a/x-pack/legacy/plugins/canvas/types/elements.ts b/x-pack/legacy/plugins/canvas/types/elements.ts index 86356f5bd32a9..5de6b4968545f 100644 --- a/x-pack/legacy/plugins/canvas/types/elements.ts +++ b/x-pack/legacy/plugins/canvas/types/elements.ts @@ -75,4 +75,8 @@ export interface ElementPosition { parent: string | null; } -export type PositionedElement = CanvasElement & { ast: ExpressionAstExpression }; +export type PositionedElement = CanvasElement & { + ast: ExpressionAstExpression; +} & { + position: ElementPosition; +}; diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 49a749c578caf..d1270ea92c51e 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -5521,26 +5521,10 @@ "xpack.canvas.sidebarContent.groupedElementSidebarTitle": "グループ化されたエレメント", "xpack.canvas.sidebarContent.multiElementSidebarTitle": "複数エレメント", "xpack.canvas.sidebarContent.singleElementSidebarTitle": "選択されたエレメント", - "xpack.canvas.sidebarHeader.alignmentMenuItemLabel": "アラインメント", - "xpack.canvas.sidebarHeader.bottomAlignMenuItemLabel": "一番下", "xpack.canvas.sidebarHeader.bringForwardArialLabel": "エレメントを 1 つ上のレイヤーに移動", "xpack.canvas.sidebarHeader.bringToFrontArialLabel": "エレメントを一番上のレイヤーに移動", - "xpack.canvas.sidebarHeader.centerAlignMenuItemLabel": "中央", - "xpack.canvas.sidebarHeader.contextMenuAriaLabel": "エレメントオプション", - "xpack.canvas.sidebarHeader.createElementModalTitle": "新規エレメントの作成", - "xpack.canvas.sidebarHeader.distributionMenutItemLabel": "分布", - "xpack.canvas.sidebarHeader.groupMenuItemLabel": "グループ", - "xpack.canvas.sidebarHeader.horizontalDistributionMenutItemLabel": "横", - "xpack.canvas.sidebarHeader.leftAlignMenuItemLabel": "左", - "xpack.canvas.sidebarHeader.middleAlignMenuItemLabel": "真ん中", - "xpack.canvas.sidebarHeader.orderMenuItemLabel": "順序", - "xpack.canvas.sidebarHeader.rightAlignMenuItemLabel": "右", - "xpack.canvas.sidebarHeader.savedElementMenuItemLabel": "新規エレメントとして保存", "xpack.canvas.sidebarHeader.sendBackwardArialLabel": "エレメントを 1 つ下のレイヤーに移動", "xpack.canvas.sidebarHeader.sendToBackArialLabel": "エレメントを一番下のレイヤーに移動", - "xpack.canvas.sidebarHeader.topAlignMenuItemLabel": "一番上", - "xpack.canvas.sidebarHeader.ungroupMenuItemLabel": "グループ解除", - "xpack.canvas.sidebarHeader.verticalDistributionMenutItemLabel": "縦", "xpack.canvas.tags.presentationTag": "プレゼンテーション", "xpack.canvas.tags.reportTag": "レポート", "xpack.canvas.templates.darkHelp": "ダークカラーテーマのプレゼンテーションデッキです", @@ -5854,6 +5838,18 @@ "xpack.canvas.workpadHeaderCustomInterval.confirmButtonLabel": "設定", "xpack.canvas.workpadHeaderCustomInterval.formDescription": "{secondsExample}、{minutesExample}、{hoursExample} のような短い表記を使用します", "xpack.canvas.workpadHeaderCustomInterval.formLabel": "カスタム間隔を設定", + "xpack.canvas.workpadHeaderEditMenu.alignmentMenuItemLabel": "アラインメント", + "xpack.canvas.workpadHeaderEditMenu.bottomAlignMenuItemLabel": "一番下", + "xpack.canvas.workpadHeaderEditMenu.centerAlignMenuItemLabel": "中央", + "xpack.canvas.workpadHeaderEditMenu.createElementModalTitle": "新規エレメントの作成", + "xpack.canvas.workpadHeaderEditMenu.distributionMenutItemLabel": "分布", + "xpack.canvas.workpadHeaderEditMenu.groupMenuItemLabel": "グループ", + "xpack.canvas.workpadHeaderEditMenu.horizontalDistributionMenutItemLabel": "横", + "xpack.canvas.workpadHeaderEditMenu.leftAlignMenuItemLabel": "左", + "xpack.canvas.workpadHeaderEditMenu.middleAlignMenuItemLabel": "真ん中", + "xpack.canvas.workpadHeaderEditMenu.orderMenuItemLabel": "順序", + "xpack.canvas.workpadHeaderEditMenu.rightAlignMenuItemLabel": "右", + "xpack.canvas.workpadHeaderEditMenu.savedElementMenuItemLabel": "新規エレメントとして保存", "xpack.canvas.workpadHeaderKioskControl.controlTitle": "全画面ページのサイクル", "xpack.canvas.workpadHeaderKioskControl.cycleFormLabel": "サイクル間隔を変更", "xpack.canvas.workpadHeaderKioskControl.cycleToggleSwitch": "スライドを自動的にサイクル", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index adb8ac1817a14..32c91a6ef2931 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -5522,26 +5522,10 @@ "xpack.canvas.sidebarContent.groupedElementSidebarTitle": "已分组元素", "xpack.canvas.sidebarContent.multiElementSidebarTitle": "多个元素", "xpack.canvas.sidebarContent.singleElementSidebarTitle": "选定元素", - "xpack.canvas.sidebarHeader.alignmentMenuItemLabel": "对齐方式", - "xpack.canvas.sidebarHeader.bottomAlignMenuItemLabel": "下", "xpack.canvas.sidebarHeader.bringForwardArialLabel": "将元素上移一层", "xpack.canvas.sidebarHeader.bringToFrontArialLabel": "将元素移到顶层", - "xpack.canvas.sidebarHeader.centerAlignMenuItemLabel": "中", - "xpack.canvas.sidebarHeader.contextMenuAriaLabel": "元素选项", - "xpack.canvas.sidebarHeader.createElementModalTitle": "创建新元素", - "xpack.canvas.sidebarHeader.distributionMenutItemLabel": "分布", - "xpack.canvas.sidebarHeader.groupMenuItemLabel": "分组", - "xpack.canvas.sidebarHeader.horizontalDistributionMenutItemLabel": "水平", - "xpack.canvas.sidebarHeader.leftAlignMenuItemLabel": "左", - "xpack.canvas.sidebarHeader.middleAlignMenuItemLabel": "中", - "xpack.canvas.sidebarHeader.orderMenuItemLabel": "顺序", - "xpack.canvas.sidebarHeader.rightAlignMenuItemLabel": "右", - "xpack.canvas.sidebarHeader.savedElementMenuItemLabel": "另存为新元素", "xpack.canvas.sidebarHeader.sendBackwardArialLabel": "将元素下移一层", "xpack.canvas.sidebarHeader.sendToBackArialLabel": "将元素移到底层", - "xpack.canvas.sidebarHeader.topAlignMenuItemLabel": "上", - "xpack.canvas.sidebarHeader.ungroupMenuItemLabel": "取消分组", - "xpack.canvas.sidebarHeader.verticalDistributionMenutItemLabel": "垂直", "xpack.canvas.tags.presentationTag": "演示", "xpack.canvas.tags.reportTag": "报告", "xpack.canvas.templates.darkHelp": "深色主题的演示幻灯片", @@ -5856,6 +5840,21 @@ "xpack.canvas.workpadHeaderCustomInterval.confirmButtonLabel": "设置", "xpack.canvas.workpadHeaderCustomInterval.formDescription": "使用速记表示法,如 {secondsExample}、{minutesExample} 或 {hoursExample}", "xpack.canvas.workpadHeaderCustomInterval.formLabel": "设置定制时间间隔", + "xpack.canvas.workpadHeaderEditMenu.alignmentMenuItemLabel": "对齐方式", + "xpack.canvas.workpadHeaderEditMenu.bottomAlignMenuItemLabel": "下", + "xpack.canvas.workpadHeaderEditMenu.centerAlignMenuItemLabel": "中", + "xpack.canvas.workpadHeaderEditMenu.createElementModalTitle": "创建新元素", + "xpack.canvas.workpadHeaderEditMenu.distributionMenutItemLabel": "分布", + "xpack.canvas.workpadHeaderEditMenu.groupMenuItemLabel": "分组", + "xpack.canvas.workpadHeaderEditMenu.horizontalDistributionMenutItemLabel": "水平", + "xpack.canvas.workpadHeaderEditMenu.leftAlignMenuItemLabel": "左", + "xpack.canvas.workpadHeaderEditMenu.middleAlignMenuItemLabel": "中", + "xpack.canvas.workpadHeaderEditMenu.orderMenuItemLabel": "顺序", + "xpack.canvas.workpadHeaderEditMenu.rightAlignMenuItemLabel": "右", + "xpack.canvas.workpadHeaderEditMenu.savedElementMenuItemLabel": "另存为新元素", + "xpack.canvas.workpadHeaderEditMenu.topAlignMenuItemLabel": "上", + "xpack.canvas.workpadHeaderEditMenu.ungroupMenuItemLabel": "取消分组", + "xpack.canvas.workpadHeaderEditMenu.verticalDistributionMenutItemLabel": "垂直", "xpack.canvas.workpadHeaderKioskControl.controlTitle": "循环播放全屏页面", "xpack.canvas.workpadHeaderKioskControl.cycleFormLabel": "更改循环播放时间间隔", "xpack.canvas.workpadHeaderKioskControl.cycleToggleSwitch": "自动循环播放幻灯片", diff --git a/x-pack/test/functional/apps/canvas/custom_elements.ts b/x-pack/test/functional/apps/canvas/custom_elements.ts index d4e1702368879..3bd3749ec6935 100644 --- a/x-pack/test/functional/apps/canvas/custom_elements.ts +++ b/x-pack/test/functional/apps/canvas/custom_elements.ts @@ -40,8 +40,11 @@ export default function canvasCustomElementTest({ // find the first workpad element (a markdown element) and click it to select it await testSubjects.click('canvasWorkpadPage > canvasWorkpadPageElementContent', 20000); + // click "Edit" menu + await testSubjects.click('canvasWorkpadEditMenuButton', 20000); + // click the "Save as new element" button - await testSubjects.click('canvasSidebarHeader__saveElementButton', 20000); + await testSubjects.click('canvasWorkpadEditMenu__saveElementButton', 20000); // fill out the custom element form and submit it await PageObjects.canvas.fillOutCustomElementForm( From 3cef8e6f309f8d52b7b9c5553692f52a4131e815 Mon Sep 17 00:00:00 2001 From: Phillip Burch Date: Thu, 30 Apr 2020 16:53:56 -0500 Subject: [PATCH 09/10] [Metrics UI] Add inventory metric threshold alerts (#64292) * Add new inventory metric threshold alert * Add missed file * Fix some types * Convert units on client and executor. * Move formatters to common. Properly format metrics in alert messages * Style changes * Remove unused files * fix test * Update create * Fix signature * Remove old test. Remove unecessary import * Pass in filter when clicking create alert from context menu * Fix filtering * Fix more types * Fix tests * Fix merge * Fix merge Co-authored-by: Elastic Machine --- .../utils => common}/formatters/bytes.test.ts | 4 +- .../utils => common}/formatters/bytes.ts | 3 +- .../utils => common}/formatters/datetime.ts | 0 .../formatters/high_precision.ts | 0 .../utils => common}/formatters/index.ts | 4 +- .../utils => common}/formatters/number.ts | 0 .../utils => common}/formatters/percent.ts | 0 .../formatters/snapshot_metric_formats.ts | 73 +++ .../plugins/infra/common/formatters/types.ts | 11 + .../aws_ec2/toolbar_items.tsx | 32 +- .../aws_rds/toolbar_items.tsx | 30 +- .../inventory_models/aws_s3/toolbar_items.tsx | 22 +- .../aws_sqs/toolbar_items.tsx | 21 +- .../container/toolbar_items.tsx | 23 +- .../inventory_models/host/toolbar_items.tsx | 27 +- .../inventory_models/pod/toolbar_items.tsx | 9 +- .../components/alert_dropdown.tsx | 2 +- .../components/expression.tsx | 37 +- .../alerting/inventory/alert_dropdown.tsx | 62 +++ .../alerting/inventory/alert_flyout.tsx | 52 ++ .../alerting/inventory/expression.tsx | 498 ++++++++++++++++++ .../components/alerting/inventory/metric.tsx | 150 ++++++ .../metric_inventory_threshold_alert_type.ts | 34 ++ .../alerting/inventory/node_type.tsx | 115 ++++ .../alerting/inventory/validation.tsx | 80 +++ .../log_text_stream/column_headers.tsx | 2 +- .../logging/log_text_stream/log_date_row.tsx | 2 +- .../containers/source/use_source_via_http.ts | 17 +- x-pack/plugins/infra/public/index.ts | 2 +- x-pack/plugins/infra/public/lib/lib.ts | 6 - .../infra/public/pages/metrics/index.tsx | 7 +- .../components/waffle/node_context_menu.tsx | 315 ++++++----- .../lib/create_inventory_metric_formatter.ts | 2 +- .../components/gauges_section_vis.tsx | 2 +- .../metric_detail/components/helpers.ts | 2 +- .../helpers/create_formatter_for_metric.ts | 2 +- .../metrics_explorer/components/kuery_bar.tsx | 5 + x-pack/plugins/infra/public/plugin.ts | 2 + .../infra/server/graphql/sources/resolvers.ts | 10 +- .../metrics/kibana_metrics_adapter.ts | 10 +- .../inventory_metric_threshold_executor.ts | 214 ++++++++ ...r_inventory_metric_threshold_alert_type.ts | 92 ++++ .../inventory_metric_threshold/types.ts | 35 ++ .../metric_threshold_executor.test.ts | 192 ++++--- .../metric_threshold_executor.ts | 63 +-- .../register_metric_threshold_alert_type.ts | 39 +- .../lib/alerting/register_alert_types.ts | 5 +- .../infra/server/lib/compose/kibana.ts | 2 +- .../create_timerange_with_interval.ts | 21 +- .../infra/server/lib/snapshot/snapshot.ts | 52 +- .../infra/server/lib/sources/sources.ts | 33 +- x-pack/plugins/infra/server/plugin.ts | 2 +- .../routes/log_sources/configuration.ts | 4 +- .../lib/get_dataset_for_field.ts | 13 +- .../lib/populate_series_with_tsvb_data.ts | 16 +- .../infra/server/routes/snapshot/index.ts | 9 +- .../server/utils/calculate_metric_interval.ts | 14 +- .../apis/infra/metrics_alerting.ts | 11 +- 58 files changed, 1995 insertions(+), 497 deletions(-) rename x-pack/plugins/infra/{public/utils => common}/formatters/bytes.test.ts (93%) rename x-pack/plugins/infra/{public/utils => common}/formatters/bytes.ts (96%) rename x-pack/plugins/infra/{public/utils => common}/formatters/datetime.ts (100%) rename x-pack/plugins/infra/{public/utils => common}/formatters/high_precision.ts (100%) rename x-pack/plugins/infra/{public/utils => common}/formatters/index.ts (90%) rename x-pack/plugins/infra/{public/utils => common}/formatters/number.ts (100%) rename x-pack/plugins/infra/{public/utils => common}/formatters/percent.ts (100%) create mode 100644 x-pack/plugins/infra/common/formatters/snapshot_metric_formats.ts create mode 100644 x-pack/plugins/infra/common/formatters/types.ts create mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx create mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/alert_flyout.tsx create mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/expression.tsx create mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/metric.tsx create mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/metric_inventory_threshold_alert_type.ts create mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/node_type.tsx create mode 100644 x-pack/plugins/infra/public/components/alerting/inventory/validation.tsx create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts create mode 100644 x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts diff --git a/x-pack/plugins/infra/public/utils/formatters/bytes.test.ts b/x-pack/plugins/infra/common/formatters/bytes.test.ts similarity index 93% rename from x-pack/plugins/infra/public/utils/formatters/bytes.test.ts rename to x-pack/plugins/infra/common/formatters/bytes.test.ts index 4c872bcee057d..ccdeed120acca 100644 --- a/x-pack/plugins/infra/public/utils/formatters/bytes.test.ts +++ b/x-pack/plugins/infra/common/formatters/bytes.test.ts @@ -3,9 +3,9 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -import { InfraWaffleMapDataFormat } from '../../lib/lib'; +import { InfraWaffleMapDataFormat } from './types'; import { createBytesFormatter } from './bytes'; + describe('createDataFormatter', () => { it('should format bytes as bytesDecimal', () => { const formatter = createBytesFormatter(InfraWaffleMapDataFormat.bytesDecimal); diff --git a/x-pack/plugins/infra/public/utils/formatters/bytes.ts b/x-pack/plugins/infra/common/formatters/bytes.ts similarity index 96% rename from x-pack/plugins/infra/public/utils/formatters/bytes.ts rename to x-pack/plugins/infra/common/formatters/bytes.ts index 80a5603ed6994..3a45caa8b5e15 100644 --- a/x-pack/plugins/infra/public/utils/formatters/bytes.ts +++ b/x-pack/plugins/infra/common/formatters/bytes.ts @@ -3,9 +3,8 @@ * or more contributor license agreements. Licensed under the Elastic License; * you may not use this file except in compliance with the Elastic License. */ - -import { InfraWaffleMapDataFormat } from '../../lib/lib'; import { formatNumber } from './number'; +import { InfraWaffleMapDataFormat } from './types'; /** * The labels are derived from these two Wikipedia articles. diff --git a/x-pack/plugins/infra/public/utils/formatters/datetime.ts b/x-pack/plugins/infra/common/formatters/datetime.ts similarity index 100% rename from x-pack/plugins/infra/public/utils/formatters/datetime.ts rename to x-pack/plugins/infra/common/formatters/datetime.ts diff --git a/x-pack/plugins/infra/public/utils/formatters/high_precision.ts b/x-pack/plugins/infra/common/formatters/high_precision.ts similarity index 100% rename from x-pack/plugins/infra/public/utils/formatters/high_precision.ts rename to x-pack/plugins/infra/common/formatters/high_precision.ts diff --git a/x-pack/plugins/infra/public/utils/formatters/index.ts b/x-pack/plugins/infra/common/formatters/index.ts similarity index 90% rename from x-pack/plugins/infra/public/utils/formatters/index.ts rename to x-pack/plugins/infra/common/formatters/index.ts index 3c60dba747825..096085696bd6b 100644 --- a/x-pack/plugins/infra/public/utils/formatters/index.ts +++ b/x-pack/plugins/infra/common/formatters/index.ts @@ -5,12 +5,12 @@ */ import Mustache from 'mustache'; -import { InfraWaffleMapDataFormat } from '../../lib/lib'; import { createBytesFormatter } from './bytes'; import { formatNumber } from './number'; import { formatPercent } from './percent'; -import { InventoryFormatterType } from '../../../common/inventory_models/types'; +import { InventoryFormatterType } from '../inventory_models/types'; import { formatHighPercision } from './high_precision'; +import { InfraWaffleMapDataFormat } from './types'; export const FORMATTERS = { number: formatNumber, diff --git a/x-pack/plugins/infra/public/utils/formatters/number.ts b/x-pack/plugins/infra/common/formatters/number.ts similarity index 100% rename from x-pack/plugins/infra/public/utils/formatters/number.ts rename to x-pack/plugins/infra/common/formatters/number.ts diff --git a/x-pack/plugins/infra/public/utils/formatters/percent.ts b/x-pack/plugins/infra/common/formatters/percent.ts similarity index 100% rename from x-pack/plugins/infra/public/utils/formatters/percent.ts rename to x-pack/plugins/infra/common/formatters/percent.ts diff --git a/x-pack/plugins/infra/common/formatters/snapshot_metric_formats.ts b/x-pack/plugins/infra/common/formatters/snapshot_metric_formats.ts new file mode 100644 index 0000000000000..8b4ae27cb3061 --- /dev/null +++ b/x-pack/plugins/infra/common/formatters/snapshot_metric_formats.ts @@ -0,0 +1,73 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +enum InfraFormatterType { + number = 'number', + abbreviatedNumber = 'abbreviatedNumber', + bytes = 'bytes', + bits = 'bits', + percent = 'percent', +} + +interface MetricFormatter { + formatter: InfraFormatterType; + template: string; + bounds?: { min: number; max: number }; +} + +interface MetricFormatters { + [key: string]: MetricFormatter; +} + +export const METRIC_FORMATTERS: MetricFormatters = { + ['count']: { formatter: InfraFormatterType.number, template: '{{value}}' }, + ['cpu']: { + formatter: InfraFormatterType.percent, + template: '{{value}}', + }, + ['memory']: { + formatter: InfraFormatterType.percent, + template: '{{value}}', + }, + ['rx']: { formatter: InfraFormatterType.bits, template: '{{value}}/s' }, + ['tx']: { formatter: InfraFormatterType.bits, template: '{{value}}/s' }, + ['logRate']: { + formatter: InfraFormatterType.abbreviatedNumber, + template: '{{value}}/s', + }, + ['diskIOReadBytes']: { + formatter: InfraFormatterType.bytes, + template: '{{value}}/s', + }, + ['diskIOWriteBytes']: { + formatter: InfraFormatterType.bytes, + template: '{{value}}/s', + }, + ['s3BucketSize']: { + formatter: InfraFormatterType.bytes, + template: '{{value}}', + }, + ['s3TotalRequests']: { + formatter: InfraFormatterType.abbreviatedNumber, + template: '{{value}}', + }, + ['s3NumberOfObjects']: { + formatter: InfraFormatterType.abbreviatedNumber, + template: '{{value}}', + }, + ['s3UploadBytes']: { + formatter: InfraFormatterType.bytes, + template: '{{value}}', + }, + ['s3DownloadBytes']: { + formatter: InfraFormatterType.bytes, + template: '{{value}}', + }, + ['sqsOldestMessage']: { + formatter: InfraFormatterType.number, + template: '{{value}} seconds', + }, +}; diff --git a/x-pack/plugins/infra/common/formatters/types.ts b/x-pack/plugins/infra/common/formatters/types.ts new file mode 100644 index 0000000000000..c438ec2d4205d --- /dev/null +++ b/x-pack/plugins/infra/common/formatters/types.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 enum InfraWaffleMapDataFormat { + bytesDecimal = 'bytesDecimal', + bitsDecimal = 'bitsDecimal', + abbreviatedNumber = 'abbreviatedNumber', +} diff --git a/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx index b2da7dec3f2e0..764db2164b711 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_ec2/toolbar_items.tsx @@ -11,27 +11,29 @@ import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_ import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; +export const ec2MetricTypes: SnapshotMetricType[] = [ + 'cpu', + 'rx', + 'tx', + 'diskIOReadBytes', + 'diskIOWriteBytes', +]; + +export const ec2groupByFields = [ + 'cloud.availability_zone', + 'cloud.machine.type', + 'aws.ec2.instance.image.id', + 'aws.ec2.instance.state.name', +]; + export const AwsEC2ToolbarItems = (props: ToolbarProps) => { - const metricTypes: SnapshotMetricType[] = [ - 'cpu', - 'rx', - 'tx', - 'diskIOReadBytes', - '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/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx index 2a8394b9dd3a4..3eebdee22b2c3 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_rds/toolbar_items.tsx @@ -11,26 +11,28 @@ import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_ import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; +export const rdsMetricTypes: SnapshotMetricType[] = [ + 'cpu', + 'rdsConnections', + 'rdsQueriesExecuted', + 'rdsActiveTransactions', + 'rdsLatency', +]; + +export const rdsGroupByFields = [ + 'cloud.availability_zone', + 'aws.rds.db_instance.class', + 'aws.rds.db_instance.status', +]; + export const AwsRDSToolbarItems = (props: ToolbarProps) => { - const metricTypes: SnapshotMetricType[] = [ - 'cpu', - 'rdsConnections', - 'rdsQueriesExecuted', - 'rdsActiveTransactions', - 'rdsLatency', - ]; - const groupByFields = [ - 'cloud.availability_zone', - 'aws.rds.db_instance.class', - 'aws.rds.db_instance.status', - ]; return ( <> ); diff --git a/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx index 324bdd0586029..ede618b1bf19d 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_s3/toolbar_items.tsx @@ -11,22 +11,24 @@ import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_ import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; +export const s3MetricTypes: SnapshotMetricType[] = [ + 's3BucketSize', + 's3NumberOfObjects', + 's3TotalRequests', + 's3DownloadBytes', + 's3UploadBytes', +]; + +export const s3GroupByFields = ['cloud.region']; + export const AwsS3ToolbarItems = (props: ToolbarProps) => { - const metricTypes: SnapshotMetricType[] = [ - 's3BucketSize', - 's3NumberOfObjects', - 's3TotalRequests', - 's3DownloadBytes', - 's3UploadBytes', - ]; - const groupByFields = ['cloud.region']; return ( <> ); diff --git a/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx index 3229c07034772..e77f3af578197 100644 --- a/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/aws_sqs/toolbar_items.tsx @@ -11,22 +11,23 @@ import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_ import { CloudToolbarItems } from '../shared/components/cloud_toolbar_items'; import { SnapshotMetricType } from '../types'; +export const sqsMetricTypes: SnapshotMetricType[] = [ + 'sqsMessagesVisible', + 'sqsMessagesDelayed', + 'sqsMessagesSent', + 'sqsMessagesEmpty', + 'sqsOldestMessage', +]; +export const sqsGroupByFields = ['cloud.region']; + export const AwsSQSToolbarItems = (props: ToolbarProps) => { - const metricTypes: SnapshotMetricType[] = [ - 'sqsMessagesVisible', - 'sqsMessagesDelayed', - 'sqsMessagesSent', - 'sqsMessagesEmpty', - 'sqsOldestMessage', - ]; - const groupByFields = ['cloud.region']; return ( <> ); diff --git a/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx index f6c707726d9ca..f193adbf6aadc 100644 --- a/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/container/toolbar_items.tsx @@ -10,21 +10,22 @@ import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/compo import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; +export const containerMetricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'rx', 'tx']; +export const containerGroupByFields = [ + 'host.name', + 'cloud.availability_zone', + 'cloud.machine.type', + 'cloud.project.id', + 'cloud.provider', + 'service.type', +]; + export const ContainerToolbarItems = (props: ToolbarProps) => { - const metricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'rx', 'tx']; - const groupByFields = [ - 'host.name', - 'cloud.availability_zone', - 'cloud.machine.type', - 'cloud.project.id', - 'cloud.provider', - 'service.type', - ]; return ( ); }; diff --git a/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx index 136264c0e26f4..8ed684b3885de 100644 --- a/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/host/toolbar_items.tsx @@ -10,20 +10,27 @@ import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/compo import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; +export const hostMetricTypes: SnapshotMetricType[] = [ + 'cpu', + 'memory', + 'load', + 'rx', + 'tx', + 'logRate', +]; +export const hostGroupByFields = [ + 'cloud.availability_zone', + 'cloud.machine.type', + 'cloud.project.id', + 'cloud.provider', + 'service.type', +]; export const HostToolbarItems = (props: ToolbarProps) => { - const metricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'load', 'rx', 'tx', 'logRate']; - const groupByFields = [ - 'cloud.availability_zone', - 'cloud.machine.type', - 'cloud.project.id', - 'cloud.provider', - 'service.type', - ]; return ( ); }; diff --git a/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx b/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx index c1cd375ff47bf..54a32e3e0180a 100644 --- a/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx +++ b/x-pack/plugins/infra/common/inventory_models/pod/toolbar_items.tsx @@ -10,14 +10,15 @@ import { ToolbarProps } from '../../../public/pages/metrics/inventory_view/compo import { MetricsAndGroupByToolbarItems } from '../shared/components/metrics_and_groupby_toolbar_items'; import { SnapshotMetricType } from '../types'; +export const podMetricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'rx', 'tx']; +export const podGroupByFields = ['kubernetes.namespace', 'kubernetes.node.name', 'service.type']; + export const PodToolbarItems = (props: ToolbarProps) => { - const metricTypes: SnapshotMetricType[] = ['cpu', 'memory', 'rx', 'tx']; - const groupByFields = ['kubernetes.namespace', 'kubernetes.node.name', 'service.type']; return ( ); }; diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx index bb664f4067662..8bcf0e9ed5be5 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/alert_dropdown.tsx @@ -10,7 +10,7 @@ import { FormattedMessage } from '@kbn/i18n/react'; import { AlertFlyout } from './alert_flyout'; import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; -export const AlertDropdown = () => { +export const MetricsAlertDropdown = () => { const [popoverOpen, setPopoverOpen] = useState(false); const [flyoutVisible, setFlyoutVisible] = useState(false); const kibana = useKibana(); diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx index 352ac1927479e..5e14babddcb07 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression.tsx @@ -34,6 +34,8 @@ import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer import { MetricsExplorerOptions } from '../../../pages/metrics/metrics_explorer/hooks/use_metrics_explorer_options'; import { MetricsExplorerGroupBy } from '../../../pages/metrics/metrics_explorer/components/group_by'; import { useSourceViaHttp } from '../../../containers/source/use_source_via_http'; +import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; + import { ExpressionRow } from './expression_row'; import { AlertContextMeta, TimeUnit, MetricExpression } from '../types'; import { ExpressionChart } from './expression_chart'; @@ -45,6 +47,7 @@ interface Props { groupBy?: string; filterQuery?: string; sourceId?: string; + filterQueryText?: string; alertOnNoData?: boolean; }; alertsContext: AlertsContextValue; @@ -111,11 +114,15 @@ export const Expressions: React.FC = props => { [setAlertParams, alertParams.criteria] ); - const onFilterQuerySubmit = useCallback( + const onFilterChange = useCallback( (filter: any) => { - setAlertParams('filterQuery', filter); + setAlertParams('filterQueryText', filter); + setAlertParams( + 'filterQuery', + convertKueryToElasticSearchQuery(filter, derivedIndexPattern) || '' + ); }, - [setAlertParams] + [setAlertParams, derivedIndexPattern] ); const onGroupByChange = useCallback( @@ -180,10 +187,19 @@ export const Expressions: React.FC = props => { if (md.currentOptions) { if (md.currentOptions.filterQuery) { - setAlertParams('filterQuery', md.currentOptions.filterQuery); + setAlertParams('filterQueryText', md.currentOptions.filterQuery); + setAlertParams( + 'filterQuery', + convertKueryToElasticSearchQuery(md.currentOptions.filterQuery, derivedIndexPattern) || + '' + ); } else if (md.currentOptions.groupBy && md.series) { const filter = `${md.currentOptions.groupBy}: "${md.series.id}"`; - setAlertParams('filterQuery', filter); + setAlertParams('filterQueryText', filter); + setAlertParams( + 'filterQuery', + convertKueryToElasticSearchQuery(filter, derivedIndexPattern) || '' + ); } setAlertParams('groupBy', md.currentOptions.groupBy); @@ -200,8 +216,8 @@ export const Expressions: React.FC = props => { }, [alertsContext.metadata, defaultExpression, source]); // eslint-disable-line react-hooks/exhaustive-deps const handleFieldSearchChange = useCallback( - (e: ChangeEvent) => onFilterQuerySubmit(e.target.value), - [onFilterQuerySubmit] + (e: ChangeEvent) => onFilterChange(e.target.value), + [onFilterChange] ); return ( @@ -304,13 +320,14 @@ export const Expressions: React.FC = props => { {(alertsContext.metadata && ( )) || ( )} diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx new file mode 100644 index 0000000000000..d2904206875c7 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/inventory/alert_dropdown.tsx @@ -0,0 +1,62 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useState, useCallback, useMemo } from 'react'; +import { EuiPopover, EuiButtonEmpty, EuiContextMenuItem, EuiContextMenuPanel } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { AlertFlyout } from './alert_flyout'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; + +export const InventoryAlertDropdown = () => { + const [popoverOpen, setPopoverOpen] = useState(false); + const [flyoutVisible, setFlyoutVisible] = useState(false); + const kibana = useKibana(); + + const closePopover = useCallback(() => { + setPopoverOpen(false); + }, [setPopoverOpen]); + + const openPopover = useCallback(() => { + setPopoverOpen(true); + }, [setPopoverOpen]); + + const menuItems = useMemo(() => { + return [ + setFlyoutVisible(true)}> + + , + + + , + ]; + }, [kibana.services]); + + return ( + <> + + + + } + isOpen={popoverOpen} + closePopover={closePopover} + > + + + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/alert_flyout.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/alert_flyout.tsx new file mode 100644 index 0000000000000..83298afd4fc5a --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/inventory/alert_flyout.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, { useContext } from 'react'; +import { AlertsContextProvider, AlertAdd } from '../../../../../triggers_actions_ui/public'; +import { TriggerActionsContext } from '../../../utils/triggers_actions_context'; +import { useKibana } from '../../../../../../../src/plugins/kibana_react/public'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../server/lib/alerting/inventory_metric_threshold/types'; +import { InfraWaffleMapOptions } from '../../../lib/lib'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; + +interface Props { + visible?: boolean; + options?: Partial; + nodeType?: InventoryItemType; + filter?: string; + setVisible: React.Dispatch>; +} + +export const AlertFlyout = (props: Props) => { + const { triggersActionsUI } = useContext(TriggerActionsContext); + const { services } = useKibana(); + + return ( + <> + {triggersActionsUI && ( + + + + )} + + ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/expression.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/expression.tsx new file mode 100644 index 0000000000000..15cad770836bd --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/inventory/expression.tsx @@ -0,0 +1,498 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useCallback, useMemo, useEffect, useState, ChangeEvent } from 'react'; +import { + EuiFlexGroup, + EuiFlexItem, + EuiButtonIcon, + EuiSpacer, + EuiText, + EuiFormRow, + EuiButtonEmpty, + EuiFieldSearch, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { i18n } from '@kbn/i18n'; +import { + Comparator, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../server/lib/alerting/metric_threshold/types'; +import { euiStyled } from '../../../../../observability/public'; +import { + ThresholdExpression, + ForLastExpression, + // eslint-disable-next-line @kbn/eslint/no-restricted-paths +} from '../../../../../triggers_actions_ui/public/common'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { IErrorObject } from '../../../../../triggers_actions_ui/public/types'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/application/context/alerts_context'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { MetricsExplorerKueryBar } from '../../../pages/metrics/metrics_explorer/components/kuery_bar'; +import { useSourceViaHttp } from '../../../containers/source/use_source_via_http'; +import { toMetricOpt } from '../../../pages/metrics/inventory_view/components/toolbars/toolbar_wrapper'; +import { sqsMetricTypes } from '../../../../common/inventory_models/aws_sqs/toolbar_items'; +import { ec2MetricTypes } from '../../../../common/inventory_models/aws_ec2/toolbar_items'; +import { s3MetricTypes } from '../../../../common/inventory_models/aws_s3/toolbar_items'; +import { rdsMetricTypes } from '../../../../common/inventory_models/aws_rds/toolbar_items'; +import { hostMetricTypes } from '../../../../common/inventory_models/host/toolbar_items'; +import { containerMetricTypes } from '../../../../common/inventory_models/container/toolbar_items'; +import { podMetricTypes } from '../../../../common/inventory_models/pod/toolbar_items'; +import { findInventoryModel } from '../../../../common/inventory_models'; +import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { InventoryMetricConditions } from '../../../../server/lib/alerting/inventory_metric_threshold/types'; +import { MetricExpression } from './metric'; +import { NodeTypeExpression } from './node_type'; +import { InfraWaffleMapOptions } from '../../../lib/lib'; +import { convertKueryToElasticSearchQuery } from '../../../utils/kuery'; + +interface AlertContextMeta { + options?: Partial; + nodeType?: InventoryItemType; + filter?: string; +} + +interface Props { + errors: IErrorObject[]; + alertParams: { + criteria: InventoryMetricConditions[]; + nodeType: InventoryItemType; + groupBy?: string; + filterQuery?: string; + filterQueryText?: string; + sourceId?: string; + }; + alertsContext: AlertsContextValue; + setAlertParams(key: string, value: any): void; + setAlertProperty(key: string, value: any): void; +} + +type TimeUnit = 's' | 'm' | 'h' | 'd'; + +const defaultExpression = { + metric: 'cpu' as SnapshotMetricType, + comparator: Comparator.GT, + threshold: [], + timeSize: 1, + timeUnit: 'm', +} as InventoryMetricConditions; + +export const Expressions: React.FC = props => { + const { setAlertParams, alertParams, errors, alertsContext } = props; + const { source, createDerivedIndexPattern } = useSourceViaHttp({ + sourceId: 'default', + type: 'metrics', + fetch: alertsContext.http.fetch, + toastWarning: alertsContext.toastNotifications.addWarning, + }); + const [timeSize, setTimeSize] = useState(1); + const [timeUnit, setTimeUnit] = useState('m'); + + const derivedIndexPattern = useMemo(() => createDerivedIndexPattern('metrics'), [ + createDerivedIndexPattern, + ]); + + const updateParams = useCallback( + (id, e: InventoryMetricConditions) => { + const exp = alertParams.criteria ? alertParams.criteria.slice() : []; + exp[id] = { ...exp[id], ...e }; + setAlertParams('criteria', exp); + }, + [setAlertParams, alertParams.criteria] + ); + + const addExpression = useCallback(() => { + const exp = alertParams.criteria.slice(); + exp.push(defaultExpression); + setAlertParams('criteria', exp); + }, [setAlertParams, alertParams.criteria]); + + const removeExpression = useCallback( + (id: number) => { + const exp = alertParams.criteria.slice(); + if (exp.length > 1) { + exp.splice(id, 1); + setAlertParams('criteria', exp); + } + }, + [setAlertParams, alertParams.criteria] + ); + + const onFilterChange = useCallback( + (filter: any) => { + setAlertParams('filterQueryText', filter || ''); + setAlertParams( + 'filterQuery', + convertKueryToElasticSearchQuery(filter, derivedIndexPattern) || '' + ); + }, + [derivedIndexPattern, setAlertParams] + ); + + const emptyError = useMemo(() => { + return { + aggField: [], + timeSizeUnit: [], + timeWindowSize: [], + }; + }, []); + + const updateTimeSize = useCallback( + (ts: number | undefined) => { + const criteria = alertParams.criteria.map(c => ({ + ...c, + timeSize: ts, + })); + setTimeSize(ts || undefined); + setAlertParams('criteria', criteria); + }, + [alertParams.criteria, setAlertParams] + ); + + const updateTimeUnit = useCallback( + (tu: string) => { + const criteria = alertParams.criteria.map(c => ({ + ...c, + timeUnit: tu, + })); + setTimeUnit(tu as TimeUnit); + setAlertParams('criteria', criteria); + }, + [alertParams.criteria, setAlertParams] + ); + + const updateNodeType = useCallback( + (nt: any) => { + setAlertParams('nodeType', nt); + }, + [setAlertParams] + ); + + const handleFieldSearchChange = useCallback( + (e: ChangeEvent) => onFilterChange(e.target.value), + [onFilterChange] + ); + + useEffect(() => { + const md = alertsContext.metadata; + if (!alertParams.nodeType) { + if (md && md.nodeType) { + setAlertParams('nodeType', md.nodeType); + } else { + setAlertParams('nodeType', 'host'); + } + } + + if (!alertParams.criteria) { + if (md && md.options) { + setAlertParams('criteria', [ + { + ...defaultExpression, + metric: md.options.metric!.type, + } as InventoryMetricConditions, + ]); + } else { + setAlertParams('criteria', [defaultExpression]); + } + } + + if (!alertParams.filterQuery) { + if (md && md.filter) { + setAlertParams('filterQueryText', md.filter); + setAlertParams( + 'filterQuery', + convertKueryToElasticSearchQuery(md.filter, derivedIndexPattern) || '' + ); + } + } + + if (!alertParams.sourceId) { + setAlertParams('sourceId', source?.id); + } + }, [alertsContext.metadata, derivedIndexPattern, defaultExpression, source]); // eslint-disable-line react-hooks/exhaustive-deps + + return ( + <> + + +

    + +

    +
    + + + + + {alertParams.criteria && + alertParams.criteria.map((e, idx) => { + return ( + 1} + remove={removeExpression} + addExpression={addExpression} + key={idx} // idx's don't usually make good key's but here the index has semantic meaning + expressionId={idx} + setAlertParams={updateParams} + errors={errors[idx] || emptyError} + expression={e || {}} + /> + ); + })} + + + +
    + + + +
    + + + + + {(alertsContext.metadata && ( + + )) || ( + + )} + + + + + ); +}; + +interface ExpressionRowProps { + nodeType: InventoryItemType; + expressionId: number; + expression: Omit & { + metric?: SnapshotMetricType; + }; + errors: IErrorObject; + canDelete: boolean; + addExpression(): void; + remove(id: number): void; + setAlertParams(id: number, params: Partial): void; +} + +const StyledExpressionRow = euiStyled(EuiFlexGroup)` + display: flex; + flex-wrap: wrap; + margin: 0 -4px; +`; + +const StyledExpression = euiStyled.div` + padding: 0 4px; +`; + +export const ExpressionRow: React.FC = props => { + const { setAlertParams, expression, errors, expressionId, remove, canDelete } = props; + const { metric, comparator = Comparator.GT, threshold = [] } = expression; + + const updateMetric = useCallback( + (m?: SnapshotMetricType) => { + setAlertParams(expressionId, { ...expression, metric: m }); + }, + [expressionId, expression, setAlertParams] + ); + + const updateComparator = useCallback( + (c?: string) => { + setAlertParams(expressionId, { ...expression, comparator: c as Comparator | undefined }); + }, + [expressionId, expression, setAlertParams] + ); + + const updateThreshold = useCallback( + t => { + if (t.join() !== expression.threshold.join()) { + setAlertParams(expressionId, { ...expression, threshold: t }); + } + }, + [expressionId, expression, setAlertParams] + ); + + const ofFields = useMemo(() => { + let myMetrics = hostMetricTypes; + + switch (props.nodeType) { + case 'awsEC2': + myMetrics = ec2MetricTypes; + break; + case 'awsRDS': + myMetrics = rdsMetricTypes; + break; + case 'awsS3': + myMetrics = s3MetricTypes; + break; + case 'awsSQS': + myMetrics = sqsMetricTypes; + break; + case 'host': + myMetrics = hostMetricTypes; + break; + case 'pod': + myMetrics = podMetricTypes; + break; + case 'container': + myMetrics = containerMetricTypes; + break; + } + return myMetrics.map(toMetricOpt); + }, [props.nodeType]); + + return ( + <> + + + + + v?.value === metric)?.text || '', + }} + metrics={ + ofFields.filter(m => m !== undefined && m.value !== undefined) as Array<{ + value: SnapshotMetricType; + text: string; + }> + } + onChange={updateMetric} + errors={errors} + /> + + + + + {metric && ( + +
    +
    {metricUnit[metric]?.label || ''}
    +
    +
    + )} +
    +
    + {canDelete && ( + + remove(expressionId)} + /> + + )} +
    + + + ); +}; + +const getDisplayNameForType = (type: InventoryItemType) => { + const inventoryModel = findInventoryModel(type); + return inventoryModel.displayName; +}; + +export const nodeTypes: { [key: string]: any } = { + host: { + text: getDisplayNameForType('host'), + value: 'host', + }, + pod: { + text: getDisplayNameForType('pod'), + value: 'pod', + }, + container: { + text: getDisplayNameForType('container'), + value: 'container', + }, + awsEC2: { + text: getDisplayNameForType('awsEC2'), + value: 'awsEC2', + }, + awsS3: { + text: getDisplayNameForType('awsS3'), + value: 'awsS3', + }, + awsRDS: { + text: getDisplayNameForType('awsRDS'), + value: 'awsRDS', + }, + awsSQS: { + text: getDisplayNameForType('awsSQS'), + value: 'awsSQS', + }, +}; + +const metricUnit: Record = { + count: { label: '' }, + cpu: { label: '%' }, + memory: { label: '%' }, + rx: { label: 'bits/s' }, + tx: { label: 'bits/s' }, + logRate: { label: '/s' }, + diskIOReadBytes: { label: 'bytes/s' }, + diskIOWriteBytes: { label: 'bytes/s' }, + s3BucketSize: { label: 'bytes' }, + s3TotalRequests: { label: '' }, + s3NumberOfObjects: { label: '' }, + s3UploadBytes: { label: 'bytes' }, + s3DownloadBytes: { label: 'bytes' }, + sqsOldestMessage: { label: 'seconds' }, +}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/metric.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/metric.tsx new file mode 100644 index 0000000000000..faafdf1b81eed --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/inventory/metric.tsx @@ -0,0 +1,150 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiExpression, + EuiPopover, + EuiFlexGroup, + EuiFlexItem, + EuiFormRow, + EuiComboBox, +} from '@elastic/eui'; +import { EuiPopoverTitle, EuiButtonIcon } from '@elastic/eui'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { IErrorObject } from '../../../../../triggers_actions_ui/public/types'; +import { SnapshotMetricType } from '../../../../common/inventory_models/types'; + +interface Props { + metric?: { value: SnapshotMetricType; text: string }; + metrics: Array<{ value: string; text: string }>; + errors: IErrorObject; + onChange: (metric: SnapshotMetricType) => void; + popupPosition?: + | 'upCenter' + | 'upLeft' + | 'upRight' + | 'downCenter' + | 'downLeft' + | 'downRight' + | 'leftCenter' + | 'leftUp' + | 'leftDown' + | 'rightCenter' + | 'rightUp' + | 'rightDown'; +} + +export const MetricExpression = ({ metric, metrics, errors, onChange, popupPosition }: Props) => { + const [aggFieldPopoverOpen, setAggFieldPopoverOpen] = useState(false); + const firstFieldOption = { + text: i18n.translate('xpack.infra.metrics.alertFlyout.expression.metric.selectFieldLabel', { + defaultMessage: 'Select a metric', + }), + value: '', + }; + + const availablefieldsOptions = metrics.map(m => { + return { label: m.text, value: m.value }; + }, []); + + return ( + { + setAggFieldPopoverOpen(true); + }} + color={metric ? 'secondary' : 'danger'} + /> + } + isOpen={aggFieldPopoverOpen} + closePopover={() => { + setAggFieldPopoverOpen(false); + }} + withTitle + anchorPosition={popupPosition ?? 'downRight'} + zIndex={8000} + > +
    + setAggFieldPopoverOpen(false)}> + + + + + 0 && metric !== undefined} + error={errors.metric} + > + 0 && metric !== undefined} + placeholder={firstFieldOption.text} + options={availablefieldsOptions} + noSuggestions={!availablefieldsOptions.length} + selectedOptions={ + metric ? availablefieldsOptions.filter(a => a.value === metric.value) : [] + } + renderOption={(o: any) => o.label} + onChange={selectedOptions => { + if (selectedOptions.length > 0) { + onChange(selectedOptions[0].value as SnapshotMetricType); + setAggFieldPopoverOpen(false); + } + }} + /> + + + +
    +
    + ); +}; + +interface ClosablePopoverTitleProps { + children: JSX.Element; + onClose: () => void; +} + +export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => { + return ( + + + {children} + + onClose()} + /> + + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/metric_inventory_threshold_alert_type.ts b/x-pack/plugins/infra/public/components/alerting/inventory/metric_inventory_threshold_alert_type.ts new file mode 100644 index 0000000000000..b7abaf5b36373 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/inventory/metric_inventory_threshold_alert_type.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { i18n } from '@kbn/i18n'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { AlertTypeModel } from '../../../../../triggers_actions_ui/public/types'; +import { Expressions } from './expression'; +import { validateMetricThreshold } from './validation'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from '../../../../server/lib/alerting/inventory_metric_threshold/types'; + +export function getInventoryMetricAlertType(): AlertTypeModel { + return { + id: METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, + name: i18n.translate('xpack.infra.metrics.inventory.alertFlyout.alertName', { + defaultMessage: 'Inventory', + }), + iconClass: 'bell', + alertParamsExpression: Expressions, + validate: validateMetricThreshold, + defaultActionMessage: i18n.translate( + 'xpack.infra.metrics.alerting.inventory.threshold.defaultActionMessage', + { + defaultMessage: `\\{\\{alertName\\}\\} - \\{\\{context.group\\}\\} + +\\{\\{context.metricOf.condition0\\}\\} has crossed a threshold of \\{\\{context.thresholdOf.condition0\\}\\} +Current value is \\{\\{context.valueOf.condition0\\}\\} +`, + } + ), + }; +} diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/node_type.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/node_type.tsx new file mode 100644 index 0000000000000..1623fc4e24dcb --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/inventory/node_type.tsx @@ -0,0 +1,115 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiExpression, EuiPopover, EuiFlexGroup, EuiFlexItem, EuiSelect } from '@elastic/eui'; +import { EuiPopoverTitle, EuiButtonIcon } from '@elastic/eui'; +import { InventoryItemType } from '../../../../common/inventory_models/types'; + +interface WhenExpressionProps { + value: InventoryItemType; + options: { [key: string]: { text: string; value: InventoryItemType } }; + onChange: (value: InventoryItemType) => void; + popupPosition?: + | 'upCenter' + | 'upLeft' + | 'upRight' + | 'downCenter' + | 'downLeft' + | 'downRight' + | 'leftCenter' + | 'leftUp' + | 'leftDown' + | 'rightCenter' + | 'rightUp' + | 'rightDown'; +} + +export const NodeTypeExpression = ({ + value, + options, + onChange, + popupPosition, +}: WhenExpressionProps) => { + const [aggTypePopoverOpen, setAggTypePopoverOpen] = useState(false); + + return ( + { + setAggTypePopoverOpen(true); + }} + /> + } + isOpen={aggTypePopoverOpen} + closePopover={() => { + setAggTypePopoverOpen(false); + }} + ownFocus + withTitle + anchorPosition={popupPosition ?? 'downLeft'} + > +
    + setAggTypePopoverOpen(false)}> + + + { + onChange(e.target.value as InventoryItemType); + setAggTypePopoverOpen(false); + }} + options={Object.values(options).map(o => o)} + /> +
    +
    + ); +}; + +interface ClosablePopoverTitleProps { + children: JSX.Element; + onClose: () => void; +} + +export const ClosablePopoverTitle = ({ children, onClose }: ClosablePopoverTitleProps) => { + return ( + + + {children} + + onClose()} + /> + + + + ); +}; diff --git a/x-pack/plugins/infra/public/components/alerting/inventory/validation.tsx b/x-pack/plugins/infra/public/components/alerting/inventory/validation.tsx new file mode 100644 index 0000000000000..803893dd5a323 --- /dev/null +++ b/x-pack/plugins/infra/public/components/alerting/inventory/validation.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 { i18n } from '@kbn/i18n'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { MetricExpressionParams } from '../../../../server/lib/alerting/metric_threshold/types'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { ValidationResult } from '../../../../../triggers_actions_ui/public/types'; + +export function validateMetricThreshold({ + criteria, +}: { + criteria: MetricExpressionParams[]; +}): ValidationResult { + const validationResult = { errors: {} }; + const errors: { + [id: string]: { + timeSizeUnit: string[]; + timeWindowSize: string[]; + threshold0: string[]; + threshold1: string[]; + metric: string[]; + }; + } = {}; + validationResult.errors = errors; + + if (!criteria || !criteria.length) { + return validationResult; + } + + criteria.forEach((c, idx) => { + // Create an id for each criteria, so we can map errors to specific criteria. + const id = idx.toString(); + + errors[id] = errors[id] || { + timeSizeUnit: [], + timeWindowSize: [], + threshold0: [], + threshold1: [], + metric: [], + }; + + if (!c.threshold || !c.threshold.length) { + errors[id].threshold0.push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { + defaultMessage: 'Threshold is required.', + }) + ); + } + + if (c.comparator === 'between' && (!c.threshold || c.threshold.length < 2)) { + errors[id].threshold1.push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.thresholdRequired', { + defaultMessage: 'Threshold is required.', + }) + ); + } + + if (!c.timeSize) { + errors[id].timeWindowSize.push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.timeRequred', { + defaultMessage: 'Time size is Required.', + }) + ); + } + + if (!c.metric && c.aggType !== 'count') { + errors[id].metric.push( + i18n.translate('xpack.infra.metrics.alertFlyout.error.metricRequired', { + defaultMessage: 'Metric is required.', + }) + ); + } + }); + + return validationResult; +} diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx index 72d6aea5ecfc6..c713839a1bba8 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/column_headers.tsx @@ -22,7 +22,7 @@ import { } from './log_entry_column'; import { ASSUMED_SCROLLBAR_WIDTH } from './vertical_scroll_panel'; import { LogPositionState } from '../../../containers/logs/log_position'; -import { localizedDate } from '../../../utils/formatters/datetime'; +import { localizedDate } from '../../../../common/formatters/datetime'; export const LogColumnHeaders: React.FunctionComponent<{ columnConfigurations: LogColumnConfiguration[]; diff --git a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx index fbc450950b828..144caed744bab 100644 --- a/x-pack/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx +++ b/x-pack/plugins/infra/public/components/logging/log_text_stream/log_date_row.tsx @@ -5,7 +5,7 @@ */ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiHorizontalRule, EuiTitle } from '@elastic/eui'; -import { localizedDate } from '../../../utils/formatters/datetime'; +import { localizedDate } from '../../../../common/formatters/datetime'; interface LogDateRowProps { timestamp: number; diff --git a/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts b/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts index bc6374a6538e3..aad54bd2222b7 100644 --- a/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts +++ b/x-pack/plugins/infra/public/containers/source/use_source_via_http.ts @@ -3,7 +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 { useEffect, useMemo } from 'react'; +import { useEffect, useMemo, useCallback } from 'react'; import { fold } from 'fp-ts/lib/Either'; import { identity } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; @@ -69,12 +69,15 @@ export const useSourceViaHttp = ({ })(); }, [makeRequest]); - const createDerivedIndexPattern = (indexType: 'logs' | 'metrics' | 'both' = type) => { - return { - fields: response?.source ? response.status.indexFields : [], - title: pickIndexPattern(response?.source, indexType), - }; - }; + const createDerivedIndexPattern = useCallback( + (indexType: 'logs' | 'metrics' | 'both' = type) => { + return { + fields: response?.source ? response.status.indexFields : [], + title: pickIndexPattern(response?.source, indexType), + }; + }, + [response, type] + ); const source = useMemo(() => { return response ? { ...response.source, status: response.status } : null; diff --git a/x-pack/plugins/infra/public/index.ts b/x-pack/plugins/infra/public/index.ts index 4465bde377c12..1dfdf827f203b 100644 --- a/x-pack/plugins/infra/public/index.ts +++ b/x-pack/plugins/infra/public/index.ts @@ -16,7 +16,7 @@ export const plugin: PluginInitializer< return new Plugin(context); }; -export { FORMATTERS } from './utils/formatters'; +export { FORMATTERS } from '../common/formatters'; export { InfraFormatterType } from './lib/lib'; export type InfraAppId = 'logs' | 'metrics'; diff --git a/x-pack/plugins/infra/public/lib/lib.ts b/x-pack/plugins/infra/public/lib/lib.ts index e4de0caf9bb8b..9043b4d9f6979 100644 --- a/x-pack/plugins/infra/public/lib/lib.ts +++ b/x-pack/plugins/infra/public/lib/lib.ts @@ -186,12 +186,6 @@ export enum InfraFormatterType { percent = 'percent', } -export enum InfraWaffleMapDataFormat { - bytesDecimal = 'bytesDecimal', - bitsDecimal = 'bitsDecimal', - abbreviatedNumber = 'abbreviatedNumber', -} - export interface InfraGroupByOptions { text: string; field: string; diff --git a/x-pack/plugins/infra/public/pages/metrics/index.tsx b/x-pack/plugins/infra/public/pages/metrics/index.tsx index 5dc9802fefd25..dbf71665ea869 100644 --- a/x-pack/plugins/infra/public/pages/metrics/index.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/index.tsx @@ -28,7 +28,9 @@ import { useKibana } from '../../../../../../src/plugins/kibana_react/public'; import { WaffleOptionsProvider } from './inventory_view/hooks/use_waffle_options'; import { WaffleTimeProvider } from './inventory_view/hooks/use_waffle_time'; import { WaffleFiltersProvider } from './inventory_view/hooks/use_waffle_filters'; -import { AlertDropdown } from '../../alerting/metric_threshold/components/alert_dropdown'; + +import { InventoryAlertDropdown } from '../../components/alerting/inventory/alert_dropdown'; +import { MetricsAlertDropdown } from '../../alerting/metric_threshold/components/alert_dropdown'; export const InfrastructurePage = ({ match }: RouteComponentProps) => { const uiCapabilities = useKibana().services.application?.capabilities; @@ -96,7 +98,8 @@ export const InfrastructurePage = ({ match }: RouteComponentProps) => { /> - + + diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx index c528aa885346e..d576f08108649 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/waffle/node_context_menu.tsx @@ -9,7 +9,7 @@ import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { useMemo, useState } from 'react'; -import { AlertFlyout } from '../../../../../alerting/metric_threshold/components/alert_flyout'; +import { AlertFlyout } from '../../../../../components/alerting/inventory/alert_flyout'; import { InfraWaffleMapNode, InfraWaffleMapOptions } from '../../../../../lib/lib'; import { getNodeDetailUrl, getNodeLogsUrl } from '../../../../link_to'; import { createUptimeLink } from '../../lib/create_uptime_link'; @@ -24,6 +24,8 @@ import { SectionSubtitle, SectionLinks, SectionLink, + withTheme, + EuiTheme, } from '../../../../../../../observability/public'; import { useLinkProps } from '../../../../../hooks/use_link_props'; @@ -37,157 +39,178 @@ interface Props { popoverPosition: EuiPopoverProps['anchorPosition']; } -export const NodeContextMenu: React.FC = ({ - options, - currentTime, - children, - node, - isPopoverOpen, - closePopover, - nodeType, - popoverPosition, -}) => { - const [flyoutVisible, setFlyoutVisible] = useState(false); - const inventoryModel = findInventoryModel(nodeType); - const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; - const uiCapabilities = useKibana().services.application?.capabilities; - // 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 apmField = nodeType === 'host' ? 'host.hostname' : inventoryModel.fields.id; +export const NodeContextMenu: React.FC = withTheme( + ({ + options, + currentTime, + children, + node, + isPopoverOpen, + closePopover, + nodeType, + popoverPosition, + theme, + }) => { + const [flyoutVisible, setFlyoutVisible] = useState(false); + const inventoryModel = findInventoryModel(nodeType); + const nodeDetailFrom = currentTime - inventoryModel.metrics.defaultTimeRangeInSeconds * 1000; + const uiCapabilities = useKibana().services.application?.capabilities; + // 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 apmField = nodeType === 'host' ? 'host.hostname' : inventoryModel.fields.id; - 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 = - inventoryModel.crosslinkSupport.uptime && (['pod', 'container'].includes(nodeType) || node.ip); + 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 = + inventoryModel.crosslinkSupport.uptime && + (['pod', 'container'].includes(nodeType) || node.ip); - const inventoryId = useMemo(() => { - if (nodeType === 'host') { - if (node.ip) { - return { label: host.ip, value: node.ip }; + const inventoryId = useMemo(() => { + if (nodeType === 'host') { + if (node.ip) { + return { label: host.ip, value: node.ip }; + } + } else { + if (options.fields) { + const { id } = findInventoryFields(nodeType, options.fields); + return { + label: {id}, + value: node.id, + }; + } } - } else { - if (options.fields) { - const { id } = findInventoryFields(nodeType, options.fields); - return { - label: {id}, - value: node.id, - }; - } - } - return { label: '', value: '' }; - }, [nodeType, node.ip, node.id, options.fields]); + return { label: '', value: '' }; + }, [nodeType, node.ip, node.id, options.fields]); + + const nodeLogsMenuItemLinkProps = useLinkProps({ + app: 'logs', + ...getNodeLogsUrl({ + nodeType, + nodeId: node.id, + time: currentTime, + }), + }); + const nodeDetailMenuItemLinkProps = useLinkProps({ + ...getNodeDetailUrl({ + nodeType, + nodeId: node.id, + from: nodeDetailFrom, + to: currentTime, + }), + }); + const apmTracesMenuItemLinkProps = useLinkProps({ + app: 'apm', + hash: 'traces', + search: { + kuery: `${apmField}:"${node.id}"`, + }, + }); + const uptimeMenuItemLinkProps = useLinkProps(createUptimeLink(options, nodeType, node)); - const nodeLogsMenuItemLinkProps = useLinkProps({ - app: 'logs', - ...getNodeLogsUrl({ - nodeType, - nodeId: node.id, - time: currentTime, - }), - }); - const nodeDetailMenuItemLinkProps = useLinkProps({ - ...getNodeDetailUrl({ - nodeType, - nodeId: node.id, - from: nodeDetailFrom, - to: currentTime, - }), - }); - const apmTracesMenuItemLinkProps = useLinkProps({ - app: 'apm', - hash: 'traces', - search: { - kuery: `${apmField}:"${node.id}"`, - }, - }); - const uptimeMenuItemLinkProps = useLinkProps(createUptimeLink(options, nodeType, node)); + const nodeLogsMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.viewLogsName', { + defaultMessage: '{inventoryName} logs', + values: { inventoryName: inventoryModel.singularDisplayName }, + }), + ...nodeLogsMenuItemLinkProps, + 'data-test-subj': 'viewLogsContextMenuItem', + isDisabled: !showLogsLink, + }; - const nodeLogsMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.viewLogsName', { - defaultMessage: '{inventoryName} logs', - values: { inventoryName: inventoryModel.singularDisplayName }, - }), - ...nodeLogsMenuItemLinkProps, - 'data-test-subj': 'viewLogsContextMenuItem', - isDisabled: !showLogsLink, - }; + const nodeDetailMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.viewMetricsName', { + defaultMessage: '{inventoryName} metrics', + values: { inventoryName: inventoryModel.singularDisplayName }, + }), + ...nodeDetailMenuItemLinkProps, + isDisabled: !showDetail, + }; - const nodeDetailMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.viewMetricsName', { - defaultMessage: '{inventoryName} metrics', - values: { inventoryName: inventoryModel.singularDisplayName }, - }), - ...nodeDetailMenuItemLinkProps, - isDisabled: !showDetail, - }; + const apmTracesMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.viewAPMTraces', { + defaultMessage: '{inventoryName} APM traces', + values: { inventoryName: inventoryModel.singularDisplayName }, + }), + ...apmTracesMenuItemLinkProps, + 'data-test-subj': 'viewApmTracesContextMenuItem', + isDisabled: !showAPMTraceLink, + }; - const apmTracesMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.viewAPMTraces', { - defaultMessage: '{inventoryName} APM traces', - values: { inventoryName: inventoryModel.singularDisplayName }, - }), - ...apmTracesMenuItemLinkProps, - 'data-test-subj': 'viewApmTracesContextMenuItem', - isDisabled: !showAPMTraceLink, - }; + const uptimeMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.viewUptimeLink', { + defaultMessage: '{inventoryName} in Uptime', + values: { inventoryName: inventoryModel.singularDisplayName }, + }), + ...uptimeMenuItemLinkProps, + isDisabled: !showUptimeLink, + }; - const uptimeMenuItem: SectionLinkProps = { - label: i18n.translate('xpack.infra.nodeContextMenu.viewUptimeLink', { - defaultMessage: '{inventoryName} in Uptime', - values: { inventoryName: inventoryModel.singularDisplayName }, - }), - ...uptimeMenuItemLinkProps, - isDisabled: !showUptimeLink, - }; + const createAlertMenuItem: SectionLinkProps = { + label: i18n.translate('xpack.infra.nodeContextMenu.createAlertLink', { + defaultMessage: 'Create alert', + }), + style: { color: theme?.eui.euiLinkColor || '#006BB4', fontWeight: 500, padding: 0 }, + onClick: () => { + setFlyoutVisible(true); + }, + }; - return ( - <> - -
    -
    - - - - {inventoryId.label && ( - -
    - -
    -
    - )} - - - - - - -
    -
    -
    - - - ); -}; + return ( + <> + +
    +
    + + + + {inventoryId.label && ( + +
    + +
    +
    + )} + + + + + + + +
    +
    +
    + + + ); + } +); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_inventory_metric_formatter.ts b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_inventory_metric_formatter.ts index acd71e5137694..f8c7a10f12831 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_inventory_metric_formatter.ts +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/lib/create_inventory_metric_formatter.ts @@ -5,13 +5,13 @@ */ import { get } from 'lodash'; -import { createFormatter } from '../../../../utils/formatters'; import { InfraFormatterType } from '../../../../lib/lib'; import { SnapshotMetricInput, SnapshotCustomMetricInputRT, } from '../../../../../common/http_api/snapshot_api'; import { createFormatterForMetric } from '../../metrics_explorer/components/helpers/create_formatter_for_metric'; +import { createFormatter } from '../../../../../common/formatters'; interface MetricFormatter { formatter: InfraFormatterType; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx index 0aab676b7d6c5..0f53ced80888b 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/gauges_section_vis.tsx @@ -17,7 +17,7 @@ import { get, last, max } from 'lodash'; import React, { ReactText } from 'react'; import { euiStyled } from '../../../../../../observability/public'; -import { createFormatter } from '../../../../utils/formatters'; +import { createFormatter } from '../../../../../common/formatters'; import { InventoryFormatterType } from '../../../../../common/inventory_models/types'; import { SeriesOverrides, VisSectionProps } from '../types'; import { getChartName } from './helpers'; diff --git a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts index bb4ad32660952..0b8773db2dddf 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metric_detail/components/helpers.ts @@ -7,7 +7,7 @@ import { ReactText } from 'react'; import Color from 'color'; import { get, first, last, min, max } from 'lodash'; -import { createFormatter } from '../../../../utils/formatters'; +import { createFormatter } from '../../../../../common/formatters'; import { InfraDataSeries } from '../../../../graphql/types'; import { InventoryVisTypeRT, diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts index d07a6b45f02be..46bd7b006446a 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/helpers/create_formatter_for_metric.ts @@ -5,7 +5,7 @@ */ import { MetricsExplorerMetric } from '../../../../../../common/http_api/metrics_explorer'; -import { createFormatter } from '../../../../../utils/formatters'; +import { createFormatter } from '../../../../../../common/formatters'; import { InfraFormatterType } from '../../../../../lib/lib'; import { metricToFormat } from './metric_to_format'; export const createFormatterForMetric = (metric?: MetricsExplorerMetric) => { diff --git a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx index e9826e1ff3955..04661bbc37702 100644 --- a/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/metrics_explorer/components/kuery_bar.tsx @@ -14,6 +14,7 @@ import { esKuery, IIndexPattern } from '../../../../../../../../src/plugins/data interface Props { derivedIndexPattern: IIndexPattern; onSubmit: (query: string) => void; + onChange?: (query: string) => void; value?: string | null; placeholder?: string; } @@ -30,6 +31,7 @@ function validateQuery(query: string) { export const MetricsExplorerKueryBar = ({ derivedIndexPattern, onSubmit, + onChange, value, placeholder, }: Props) => { @@ -46,6 +48,9 @@ export const MetricsExplorerKueryBar = ({ const handleChange = (query: string) => { setValidation(validateQuery(query)); setDraftQuery(query); + if (onChange) { + onChange(query); + } }; const filteredDerivedIndexPattern = { diff --git a/x-pack/plugins/infra/public/plugin.ts b/x-pack/plugins/infra/public/plugin.ts index 8cdfc4f381f43..d61ef7fc4a631 100644 --- a/x-pack/plugins/infra/public/plugin.ts +++ b/x-pack/plugins/infra/public/plugin.ts @@ -22,6 +22,7 @@ import { DataEnhancedSetup, DataEnhancedStart } from '../../data_enhanced/public import { TriggersAndActionsUIPublicPluginSetup } from '../../../plugins/triggers_actions_ui/public'; import { getAlertType as getLogsAlertType } from './components/alerting/logs/log_threshold_alert_type'; +import { getInventoryMetricAlertType } from './components/alerting/inventory/metric_inventory_threshold_alert_type'; import { createMetricThresholdAlertType } from './alerting/metric_threshold'; export type ClientSetup = void; @@ -53,6 +54,7 @@ export class Plugin setup(core: CoreSetup, pluginsSetup: ClientPluginsSetup) { registerFeatures(pluginsSetup.home); + pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getInventoryMetricAlertType()); pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(getLogsAlertType()); pluginsSetup.triggers_actions_ui.alertTypeRegistry.register(createMetricThresholdAlertType()); diff --git a/x-pack/plugins/infra/server/graphql/sources/resolvers.ts b/x-pack/plugins/infra/server/graphql/sources/resolvers.ts index f880eca933241..cffab4ba4f6f0 100644 --- a/x-pack/plugins/infra/server/graphql/sources/resolvers.ts +++ b/x-pack/plugins/infra/server/graphql/sources/resolvers.ts @@ -101,7 +101,9 @@ export const createSourcesResolvers = ( return requestedSourceConfiguration; }, async allSources(root, args, { req }) { - const sourceConfigurations = await libs.sources.getAllSourceConfigurations(req); + const sourceConfigurations = await libs.sources.getAllSourceConfigurations( + req.core.savedObjects.client + ); return sourceConfigurations; }, @@ -131,7 +133,7 @@ export const createSourcesResolvers = ( Mutation: { async createSource(root, args, { req }) { const sourceConfiguration = await libs.sources.createSourceConfiguration( - req, + req.core.savedObjects.client, args.id, compactObject({ ...args.sourceProperties, @@ -147,7 +149,7 @@ export const createSourcesResolvers = ( }; }, async deleteSource(root, args, { req }) { - await libs.sources.deleteSourceConfiguration(req, args.id); + await libs.sources.deleteSourceConfiguration(req.core.savedObjects.client, args.id); return { id: args.id, @@ -155,7 +157,7 @@ export const createSourcesResolvers = ( }, async updateSource(root, args, { req }) { const updatedSourceConfiguration = await libs.sources.updateSourceConfiguration( - req, + req.core.savedObjects.client, args.id, compactObject({ ...args.sourceProperties, diff --git a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts index 5a5f9d0f8f529..62f324e01f8d9 100644 --- a/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts +++ b/x-pack/plugins/infra/server/lib/adapters/metrics/kibana_metrics_adapter.ts @@ -18,6 +18,7 @@ import { InventoryMetricRT, } from '../../../../common/inventory_models/types'; import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; +import { CallWithRequestParams, InfraDatabaseSearchResponse } from '../framework'; export class KibanaMetricsAdapter implements InfraMetricsAdapter { private framework: KibanaFramework; @@ -120,9 +121,14 @@ export class KibanaMetricsAdapter implements InfraMetricsAdapter { indexPattern, options.timerange.interval ); + + const client = ( + opts: CallWithRequestParams + ): Promise> => + this.framework.callWithRequest(requestContext, 'search', opts); + const calculatedInterval = await calculateMetricInterval( - this.framework, - requestContext, + client, { indexPattern: `${options.sourceConfiguration.logAlias},${options.sourceConfiguration.metricAlias}`, timestampField: options.sourceConfiguration.fields.timestamp, diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts new file mode 100644 index 0000000000000..cc8a35f6e47a1 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/inventory_metric_threshold_executor.ts @@ -0,0 +1,214 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +import { mapValues, last, get } from 'lodash'; +import { i18n } from '@kbn/i18n'; +import moment from 'moment'; +import { + InfraDatabaseSearchResponse, + CallWithRequestParams, +} from '../../adapters/framework/adapter_types'; +import { Comparator, AlertStates, InventoryMetricConditions } from './types'; +import { AlertServices, AlertExecutorOptions } from '../../../../../alerting/server'; +import { InfraSnapshot } from '../../snapshot'; +import { parseFilterQuery } from '../../../utils/serialized_query'; +import { InventoryItemType, SnapshotMetricType } from '../../../../common/inventory_models/types'; +import { InfraTimerangeInput } from '../../../../common/http_api/snapshot_api'; +import { InfraSourceConfiguration } from '../../sources'; +import { InfraBackendLibs } from '../../infra_types'; +import { METRIC_FORMATTERS } from '../../../../common/formatters/snapshot_metric_formats'; +import { createFormatter } from '../../../../common/formatters'; + +interface InventoryMetricThresholdParams { + criteria: InventoryMetricConditions[]; + groupBy: string | undefined; + filterQuery: string | undefined; + nodeType: InventoryItemType; + sourceId?: string; +} + +export const createInventoryMetricThresholdExecutor = ( + libs: InfraBackendLibs, + alertId: string +) => async ({ services, params }: AlertExecutorOptions) => { + const { criteria, filterQuery, sourceId, nodeType } = params as InventoryMetricThresholdParams; + + const source = await libs.sources.getSourceConfiguration( + services.savedObjectsClient, + sourceId || 'default' + ); + + const results = await Promise.all( + criteria.map(c => evaluateCondtion(c, nodeType, source.configuration, services, filterQuery)) + ); + + const invenotryItems = Object.keys(results[0]); + for (const item of invenotryItems) { + const alertInstance = services.alertInstanceFactory(`${alertId}-${item}`); + // AND logic; all criteria must be across the threshold + const shouldAlertFire = results.every(result => result[item].shouldFire); + + // AND logic; because we need to evaluate all criteria, if one of them reports no data then the + // whole alert is in a No Data/Error state + const isNoData = results.some(result => result[item].isNoData); + const isError = results.some(result => result[item].isError); + + if (shouldAlertFire) { + alertInstance.scheduleActions(FIRED_ACTIONS.id, { + group: item, + item, + valueOf: mapToConditionsLookup(results, result => + formatMetric(result[item].metric, result[item].currentValue) + ), + thresholdOf: mapToConditionsLookup(criteria, c => c.threshold), + metricOf: mapToConditionsLookup(criteria, c => c.metric), + }); + } + + alertInstance.replaceState({ + alertState: isError + ? AlertStates.ERROR + : isNoData + ? AlertStates.NO_DATA + : shouldAlertFire + ? AlertStates.ALERT + : AlertStates.OK, + }); + } +}; + +interface ConditionResult { + shouldFire: boolean; + currentValue?: number | null; + isNoData: boolean; + isError: boolean; +} + +const evaluateCondtion = async ( + condition: InventoryMetricConditions, + nodeType: InventoryItemType, + sourceConfiguration: InfraSourceConfiguration, + services: AlertServices, + filterQuery?: string +): Promise> => { + const { comparator, metric } = condition; + let { threshold } = condition; + + const currentValues = await getData( + services, + nodeType, + metric, + { + to: Date.now(), + from: moment() + .subtract(condition.timeSize, condition.timeUnit) + .toDate() + .getTime(), + interval: condition.timeUnit, + }, + sourceConfiguration, + filterQuery + ); + + threshold = threshold.map(n => convertMetricValue(metric, n)); + + const comparisonFunction = comparatorMap[comparator]; + + return mapValues(currentValues, value => ({ + shouldFire: value !== undefined && value !== null && comparisonFunction(value, threshold), + metric, + currentValue: value, + isNoData: value === null, + isError: value === undefined, + })); +}; + +const getData = async ( + services: AlertServices, + nodeType: InventoryItemType, + metric: SnapshotMetricType, + timerange: InfraTimerangeInput, + sourceConfiguration: InfraSourceConfiguration, + filterQuery?: string +) => { + const snapshot = new InfraSnapshot(); + const esClient = ( + options: CallWithRequestParams + ): Promise> => + services.callCluster('search', options); + + const options = { + filterQuery: parseFilterQuery(filterQuery), + nodeType, + groupBy: [], + sourceConfiguration, + metric: { type: metric }, + timerange, + }; + + const { nodes } = await snapshot.getNodes(esClient, options); + + return nodes.reduce((acc, n) => { + const nodePathItem = last(n.path); + acc[nodePathItem.label] = n.metric && n.metric.value; + return acc; + }, {} as Record); +}; + +const comparatorMap = { + [Comparator.BETWEEN]: (value: number, [a, b]: number[]) => + value >= Math.min(a, b) && value <= Math.max(a, b), + // `threshold` is always an array of numbers in case the BETWEEN comparator is + // used; all other compartors will just destructure the first value in the array + [Comparator.GT]: (a: number, [b]: number[]) => a > b, + [Comparator.LT]: (a: number, [b]: number[]) => a < b, + [Comparator.OUTSIDE_RANGE]: (value: number, [a, b]: number[]) => value < a || value > b, + [Comparator.GT_OR_EQ]: (a: number, [b]: number[]) => a >= b, + [Comparator.LT_OR_EQ]: (a: number, [b]: number[]) => a <= b, +}; + +const mapToConditionsLookup = ( + list: any[], + mapFn: (value: any, index: number, array: any[]) => unknown +) => + list + .map(mapFn) + .reduce( + (result: Record, value, i) => ({ ...result, [`condition${i}`]: value }), + {} + ); + +export const FIRED_ACTIONS = { + id: 'metrics.invenotry_threshold.fired', + name: i18n.translate('xpack.infra.metrics.alerting.inventory.threshold.fired', { + defaultMessage: 'Fired', + }), +}; + +// Some metrics in the UI are in a different unit that what we store in ES. +const convertMetricValue = (metric: SnapshotMetricType, value: number) => { + if (converters[metric]) { + return converters[metric](value); + } else { + return value; + } +}; +const converters: Record number> = { + cpu: n => Number(n) / 100, + memory: n => Number(n) / 100, +}; + +const formatMetric = (metric: SnapshotMetricType, value: number) => { + // if (SnapshotCustomMetricInputRT.is(metric)) { + // const formatter = createFormatterForMetric(metric); + // return formatter(val); + // } + const metricFormatter = get(METRIC_FORMATTERS, metric, METRIC_FORMATTERS.count); + if (value == null) { + return ''; + } + const formatter = createFormatter(metricFormatter.formatter, metricFormatter.template); + return formatter(value); +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts new file mode 100644 index 0000000000000..3b6a1b5557bc6 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/register_inventory_metric_threshold_alert_type.ts @@ -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. + */ +import { i18n } from '@kbn/i18n'; +import { schema } from '@kbn/config-schema'; +import { curry } from 'lodash'; +import uuid from 'uuid'; +import { + createInventoryMetricThresholdExecutor, + FIRED_ACTIONS, +} from './inventory_metric_threshold_executor'; +import { METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID } from './types'; +import { InfraBackendLibs } from '../../infra_types'; + +const condition = schema.object({ + threshold: schema.arrayOf(schema.number()), + comparator: schema.oneOf([ + schema.literal('>'), + schema.literal('<'), + schema.literal('>='), + schema.literal('<='), + schema.literal('between'), + schema.literal('outside'), + ]), + timeUnit: schema.string(), + timeSize: schema.number(), + metric: schema.string(), +}); + +export const registerMetricInventoryThresholdAlertType = (libs: InfraBackendLibs) => ({ + id: METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID, + name: 'Inventory', + validate: { + params: schema.object( + { + criteria: schema.arrayOf(condition), + nodeType: schema.string(), + filterQuery: schema.maybe(schema.string()), + sourceId: schema.string(), + }, + { unknowns: 'allow' } + ), + }, + defaultActionGroupId: FIRED_ACTIONS.id, + actionGroups: [FIRED_ACTIONS], + executor: curry(createInventoryMetricThresholdExecutor)(libs, uuid.v4()), + actionVariables: { + context: [ + { + name: 'group', + description: i18n.translate( + 'xpack.infra.metrics.alerting.threshold.alerting.groupActionVariableDescription', + { + defaultMessage: 'Name of the group reporting data', + } + ), + }, + { + name: 'valueOf', + description: i18n.translate( + 'xpack.infra.metrics.alerting.threshold.alerting.valueOfActionVariableDescription', + { + defaultMessage: + 'Record of the current value of the watched metric; grouped by condition, i.e valueOf.condition0, valueOf.condition1, etc.', + } + ), + }, + { + name: 'thresholdOf', + description: i18n.translate( + 'xpack.infra.metrics.alerting.threshold.alerting.thresholdOfActionVariableDescription', + { + defaultMessage: + 'Record of the alerting threshold; grouped by condition, i.e thresholdOf.condition0, thresholdOf.condition1, etc.', + } + ), + }, + { + name: 'metricOf', + description: i18n.translate( + 'xpack.infra.metrics.alerting.threshold.alerting.metricOfActionVariableDescription', + { + defaultMessage: + 'Record of the watched metric; grouped by condition, i.e metricOf.condition0, metricOf.condition1, etc.', + } + ), + }, + ], + }, +}); diff --git a/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.ts new file mode 100644 index 0000000000000..73ee1ab6b7615 --- /dev/null +++ b/x-pack/plugins/infra/server/lib/alerting/inventory_metric_threshold/types.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 { SnapshotMetricType } from '../../../../common/inventory_models/types'; + +export const METRIC_INVENTORY_THRESHOLD_ALERT_TYPE_ID = 'metrics.alert.inventory.threshold'; + +export enum Comparator { + GT = '>', + LT = '<', + GT_OR_EQ = '>=', + LT_OR_EQ = '<=', + BETWEEN = 'between', + OUTSIDE_RANGE = 'outside', +} + +export enum AlertStates { + OK, + ALERT, + NO_DATA, + ERROR, +} + +export type TimeUnit = 's' | 'm' | 'h' | 'd'; + +export interface InventoryMetricConditions { + metric: SnapshotMetricType; + timeSize: number; + timeUnit: TimeUnit; + sourceId?: string; + threshold: number[]; + comparator: Comparator; +} diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts index 0007b8bd719f4..2531e939792af 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.test.ts @@ -3,7 +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. */ - import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold_executor'; import { Comparator, AlertStates } from './types'; import * as mocks from './test_mocks'; @@ -13,81 +12,14 @@ import { AlertServicesMock, AlertInstanceMock, } from '../../../../../alerting/server/mocks'; - -const executor = createMetricThresholdExecutor('test') as (opts: { - params: AlertExecutorOptions['params']; - services: { callCluster: AlertExecutorOptions['params']['callCluster'] }; -}) => Promise; - -const services: AlertServicesMock = alertsMock.createAlertServices(); -services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { - if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse; - const metric = body.query.bool.filter[1]?.exists.field; - if (body.aggs.groupings) { - if (body.aggs.groupings.composite.after) { - return mocks.compositeEndResponse; - } - if (metric === 'test.metric.2') { - return mocks.alternateCompositeResponse; - } - return mocks.basicCompositeResponse; - } - if (metric === 'test.metric.2') { - return mocks.alternateMetricResponse; - } else if (metric === 'test.metric.3') { - return mocks.emptyMetricResponse; - } - return mocks.basicMetricResponse; -}); -services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId: string) => { - if (sourceId === 'alternate') - return { - id: 'alternate', - attributes: { metricAlias: 'alternatebeat-*' }, - type, - references: [], - }; - return { id: 'default', attributes: { metricAlias: 'metricbeat-*' }, type, references: [] }; -}); +import { InfraSources } from '../../sources'; interface AlertTestInstance { instance: AlertInstanceMock; actionQueue: any[]; state: any; } -const alertInstances = new Map(); -services.alertInstanceFactory.mockImplementation((instanceID: string) => { - const alertInstance: AlertTestInstance = { - instance: alertsMock.createAlertInstanceFactory(), - actionQueue: [], - state: {}, - }; - alertInstances.set(instanceID, alertInstance); - alertInstance.instance.replaceState.mockImplementation((newState: any) => { - alertInstance.state = newState; - return alertInstance.instance; - }); - alertInstance.instance.scheduleActions.mockImplementation((id: string, action: any) => { - alertInstance.actionQueue.push({ id, action }); - return alertInstance.instance; - }); - return alertInstance.instance; -}); - -function mostRecentAction(id: string) { - return alertInstances.get(id)!.actionQueue.pop(); -} -function getState(id: string) { - return alertInstances.get(id)!.state; -} - -const baseCriterion = { - aggType: 'avg', - metric: 'test.metric.1', - timeSize: 1, - timeUnit: 'm', -}; describe('The metric threshold alert type', () => { describe('querying the entire infrastructure', () => { const instanceID = 'test-*'; @@ -167,14 +99,6 @@ describe('The metric threshold alert type', () => { expect(action.reason).toContain('threshold of 0.75'); expect(action.reason).toContain('test.metric.1'); }); - test('fetches the index pattern dynamically', async () => { - await execute(Comparator.LT, [17], 'alternate'); - expect(mostRecentAction(instanceID).id).toBe(FIRED_ACTIONS.id); - expect(getState(instanceID).alertState).toBe(AlertStates.ALERT); - await execute(Comparator.LT, [1.5], 'alternate'); - expect(mostRecentAction(instanceID)).toBe(undefined); - expect(getState(instanceID).alertState).toBe(AlertStates.OK); - }); }); describe('querying with a groupBy parameter', () => { @@ -338,3 +262,117 @@ describe('The metric threshold alert type', () => { }); }); }); + +const createMockStaticConfiguration = (sources: any) => ({ + enabled: true, + query: { + partitionSize: 1, + partitionFactor: 1, + }, + sources, +}); + +const mockLibs: any = { + sources: new InfraSources({ + config: createMockStaticConfiguration({}), + }), + configuration: createMockStaticConfiguration({}), +}; + +const executor = createMetricThresholdExecutor(mockLibs, 'test') as (opts: { + params: AlertExecutorOptions['params']; + services: { callCluster: AlertExecutorOptions['params']['callCluster'] }; +}) => Promise; + +const services: AlertServicesMock = alertsMock.createAlertServices(); +services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { + if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse; + const metric = body.query.bool.filter[1]?.exists.field; + if (body.aggs.groupings) { + if (body.aggs.groupings.composite.after) { + return mocks.compositeEndResponse; + } + if (metric === 'test.metric.2') { + return mocks.alternateCompositeResponse; + } + return mocks.basicCompositeResponse; + } + if (metric === 'test.metric.2') { + return mocks.alternateMetricResponse; + } + return mocks.basicMetricResponse; +}); +services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId: string) => { + if (sourceId === 'alternate') + return { + id: 'alternate', + attributes: { metricAlias: 'alternatebeat-*' }, + type, + references: [], + }; + return { id: 'default', attributes: { metricAlias: 'metricbeat-*' }, type, references: [] }; +}); + +services.callCluster.mockImplementation(async (_: string, { body, index }: any) => { + if (index === 'alternatebeat-*') return mocks.changedSourceIdResponse; + const metric = body.query.bool.filter[1]?.exists.field; + if (body.aggs.groupings) { + if (body.aggs.groupings.composite.after) { + return mocks.compositeEndResponse; + } + if (metric === 'test.metric.2') { + return mocks.alternateCompositeResponse; + } + return mocks.basicCompositeResponse; + } + if (metric === 'test.metric.2') { + return mocks.alternateMetricResponse; + } else if (metric === 'test.metric.3') { + return mocks.emptyMetricResponse; + } + return mocks.basicMetricResponse; +}); +services.savedObjectsClient.get.mockImplementation(async (type: string, sourceId: string) => { + if (sourceId === 'alternate') + return { + id: 'alternate', + attributes: { metricAlias: 'alternatebeat-*' }, + type, + references: [], + }; + return { id: 'default', attributes: { metricAlias: 'metricbeat-*' }, type, references: [] }; +}); + +const alertInstances = new Map(); +services.alertInstanceFactory.mockImplementation((instanceID: string) => { + const alertInstance: AlertTestInstance = { + instance: alertsMock.createAlertInstanceFactory(), + actionQueue: [], + state: {}, + }; + alertInstances.set(instanceID, alertInstance); + alertInstance.instance.replaceState.mockImplementation((newState: any) => { + alertInstance.state = newState; + return alertInstance.instance; + }); + alertInstance.instance.scheduleActions.mockImplementation((id: string, action: any) => { + alertInstance.actionQueue.push({ id, action }); + return alertInstance.instance; + }); + return alertInstance.instance; +}); + +function mostRecentAction(id: string) { + return alertInstances.get(id)!.actionQueue.pop(); +} + +function getState(id: string) { + return alertInstances.get(id)!.state; +} + +const baseCriterion = { + aggType: 'avg', + metric: 'test.metric.1', + timeSize: 1, + timeUnit: 'm', +}; diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts index bd77e5e2daf42..5c34a058577a1 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/metric_threshold_executor.ts @@ -5,8 +5,6 @@ */ import { mapValues } from 'lodash'; import { i18n } from '@kbn/i18n'; -import { convertSavedObjectToSavedSourceConfiguration } from '../../sources/sources'; -import { infraSourceConfigurationSavedObjectType } from '../../sources/saved_object_mappings'; import { InfraDatabaseSearchResponse } from '../../adapters/framework/adapter_types'; import { createAfterKeyHandler } from '../../../utils/create_afterkey_handler'; import { getAllCompositeData } from '../../../utils/get_all_composite_data'; @@ -22,9 +20,9 @@ import { import { AlertServices, AlertExecutorOptions } from '../../../../../alerting/server'; import { getIntervalInSeconds } from '../../../utils/get_interval_in_seconds'; import { getDateHistogramOffset } from '../../snapshot/query_helpers'; +import { InfraBackendLibs } from '../../infra_types'; const TOTAL_BUCKETS = 5; -const DEFAULT_INDEX_PATTERN = 'metricbeat-*'; interface Aggregation { aggregatedIntervals: { @@ -76,6 +74,7 @@ const getParsedFilterQuery: ( export const getElasticsearchMetricQuery = ( { metric, aggType, timeUnit, timeSize }: MetricExpressionParams, + timefield: string, groupBy?: string, filterQuery?: string ) => { @@ -109,7 +108,7 @@ export const getElasticsearchMetricQuery = ( const baseAggs = { aggregatedIntervals: { date_histogram: { - field: '@timestamp', + field: timefield, fixed_interval: interval, offset, extended_bounds: { @@ -181,43 +180,23 @@ export const getElasticsearchMetricQuery = ( }; }; -const getIndexPattern: ( - services: AlertServices, - sourceId?: string -) => Promise = async function({ savedObjectsClient }, sourceId = 'default') { - try { - const sourceConfiguration = await savedObjectsClient.get( - infraSourceConfigurationSavedObjectType, - sourceId - ); - const { metricAlias } = convertSavedObjectToSavedSourceConfiguration( - sourceConfiguration - ).configuration; - return metricAlias || DEFAULT_INDEX_PATTERN; - } catch (e) { - if (e.output.statusCode === 404) { - return DEFAULT_INDEX_PATTERN; - } else { - throw e; - } - } -}; - const getMetric: ( services: AlertServices, params: MetricExpressionParams, index: string, + timefield: string, groupBy: string | undefined, filterQuery: string | undefined ) => Promise> = async function( - { savedObjectsClient, callCluster }, + { callCluster }, params, index, + timefield, groupBy, filterQuery ) { const { aggType } = params; - const searchBody = getElasticsearchMetricQuery(params, groupBy, filterQuery); + const searchBody = getElasticsearchMetricQuery(params, timefield, groupBy, filterQuery); try { if (groupBy) { @@ -265,7 +244,7 @@ const comparatorMap = { [Comparator.LT_OR_EQ]: (a: number, [b]: number[]) => a <= b, }; -export const createMetricThresholdExecutor = (alertUUID: string) => +export const createMetricThresholdExecutor = (libs: InfraBackendLibs, alertId: string) => async function({ services, params }: AlertExecutorOptions) { const { criteria, groupBy, filterQuery, sourceId, alertOnNoData } = params as { criteria: MetricExpressionParams[]; @@ -275,11 +254,22 @@ export const createMetricThresholdExecutor = (alertUUID: string) => alertOnNoData: boolean; }; + const source = await libs.sources.getSourceConfiguration( + services.savedObjectsClient, + sourceId || 'default' + ); + const config = source.configuration; const alertResults = await Promise.all( - criteria.map(criterion => - (async () => { - const index = await getIndexPattern(services, sourceId); - const currentValues = await getMetric(services, criterion, index, groupBy, filterQuery); + criteria.map(criterion => { + return (async () => { + const currentValues = await getMetric( + services, + criterion, + config.fields.timestamp, + config.metricAlias, + groupBy, + filterQuery + ); const { threshold, comparator } = criterion; const comparisonFunction = comparatorMap[comparator]; return mapValues(currentValues, value => ({ @@ -291,13 +281,14 @@ export const createMetricThresholdExecutor = (alertUUID: string) => isNoData: value === null, isError: value === undefined, })); - })() - ) + })(); + }) ); + // Because each alert result has the same group definitions, just grap the groups from the first one. const groups = Object.keys(alertResults[0]); for (const group of groups) { - const alertInstance = services.alertInstanceFactory(`${alertUUID}-${group}`); + const alertInstance = services.alertInstanceFactory(`${alertId}-${group}`); // AND logic; all criteria must be across the threshold const shouldAlertFire = alertResults.every(result => result[group].shouldFire); diff --git a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts index 029491c1168cf..23611559a184f 100644 --- a/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts +++ b/x-pack/plugins/infra/server/lib/alerting/metric_threshold/register_metric_threshold_alert_type.ts @@ -6,11 +6,11 @@ import { i18n } from '@kbn/i18n'; import uuid from 'uuid'; import { schema } from '@kbn/config-schema'; -import { PluginSetupContract } from '../../../../../alerting/server'; +import { curry } from 'lodash'; import { METRIC_EXPLORER_AGGREGATIONS } from '../../../../common/http_api/metrics_explorer'; import { createMetricThresholdExecutor, FIRED_ACTIONS } from './metric_threshold_executor'; -import { InfraBackendLibs } from '../../infra_types'; import { METRIC_THRESHOLD_ALERT_TYPE_ID, Comparator } from './types'; +import { InfraBackendLibs } from '../../infra_types'; const oneOfLiterals = (arrayOfLiterals: Readonly) => schema.string({ @@ -18,17 +18,7 @@ const oneOfLiterals = (arrayOfLiterals: Readonly) => arrayOfLiterals.includes(value) ? undefined : `must be one of ${arrayOfLiterals.join(' | ')}`, }); -export async function registerMetricThresholdAlertType( - alertingPlugin: PluginSetupContract, - libs: InfraBackendLibs -) { - if (!alertingPlugin) { - throw new Error( - 'Cannot register metric threshold alert type. Both the actions and alerting plugins need to be enabled.' - ); - } - const alertUUID = uuid.v4(); - +export function registerMetricThresholdAlertType(libs: InfraBackendLibs) { const baseCriterion = { threshold: schema.arrayOf(schema.number()), comparator: oneOfLiterals(Object.values(Comparator)), @@ -70,21 +60,24 @@ export async function registerMetricThresholdAlertType( } ); - alertingPlugin.registerType({ + return { id: METRIC_THRESHOLD_ALERT_TYPE_ID, name: 'Metric threshold', validate: { - params: schema.object({ - criteria: schema.arrayOf(schema.oneOf([countCriterion, nonCountCriterion])), - groupBy: schema.maybe(schema.string()), - filterQuery: schema.maybe(schema.string()), - sourceId: schema.string(), - alertOnNoData: schema.maybe(schema.boolean()), - }), + params: schema.object( + { + criteria: schema.arrayOf(schema.oneOf([countCriterion, nonCountCriterion])), + groupBy: schema.maybe(schema.string()), + filterQuery: schema.maybe(schema.string()), + sourceId: schema.string(), + alertOnNoData: schema.maybe(schema.boolean()), + }, + { unknowns: 'allow' } + ), }, defaultActionGroupId: FIRED_ACTIONS.id, actionGroups: [FIRED_ACTIONS], - executor: createMetricThresholdExecutor(alertUUID), + executor: curry(createMetricThresholdExecutor)(libs, uuid.v4()), actionVariables: { context: [ { name: 'group', description: groupActionVariableDescription }, @@ -92,5 +85,5 @@ export async function registerMetricThresholdAlertType( { name: 'reason', description: reasonActionVariableDescription }, ], }, - }); + }; } diff --git a/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts b/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts index 9760873ff7478..44d30d7281f20 100644 --- a/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts +++ b/x-pack/plugins/infra/server/lib/alerting/register_alert_types.ts @@ -6,13 +6,16 @@ import { PluginSetupContract } from '../../../../alerting/server'; import { registerMetricThresholdAlertType } from './metric_threshold/register_metric_threshold_alert_type'; +import { registerMetricInventoryThresholdAlertType } from './inventory_metric_threshold/register_inventory_metric_threshold_alert_type'; import { registerLogThresholdAlertType } from './log_threshold/register_log_threshold_alert_type'; import { InfraBackendLibs } from '../infra_types'; const registerAlertTypes = (alertingPlugin: PluginSetupContract, libs: InfraBackendLibs) => { if (alertingPlugin) { - const registerFns = [registerMetricThresholdAlertType, registerLogThresholdAlertType]; + alertingPlugin.registerType(registerMetricThresholdAlertType(libs)); + alertingPlugin.registerType(registerMetricInventoryThresholdAlertType(libs)); + const registerFns = [registerLogThresholdAlertType]; registerFns.forEach(fn => { fn(alertingPlugin, libs); }); diff --git a/x-pack/plugins/infra/server/lib/compose/kibana.ts b/x-pack/plugins/infra/server/lib/compose/kibana.ts index f100726b5b92e..d22ca2961cfa5 100644 --- a/x-pack/plugins/infra/server/lib/compose/kibana.ts +++ b/x-pack/plugins/infra/server/lib/compose/kibana.ts @@ -28,7 +28,7 @@ export function compose(core: CoreSetup, config: InfraConfig, plugins: InfraServ const sourceStatus = new InfraSourceStatus(new InfraElasticsearchSourceStatusAdapter(framework), { sources, }); - const snapshot = new InfraSnapshot({ sources, framework }); + const snapshot = new InfraSnapshot(); const logEntryCategoriesAnalysis = new LogEntryCategoriesAnalysis({ framework }); const logEntryRateAnalysis = new LogEntryRateAnalysis({ framework }); diff --git a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts b/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts index cf2b1e59b2a22..c75ee6d644044 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts +++ b/x-pack/plugins/infra/server/lib/snapshot/create_timerange_with_interval.ts @@ -5,26 +5,23 @@ */ import { uniq } from 'lodash'; -import { RequestHandlerContext } from 'kibana/server'; import { InfraSnapshotRequestOptions } from './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'; import { getDatasetForField } from '../../routes/metrics_explorer/lib/get_dataset_for_field'; import { InfraTimerangeInput } from '../../../common/http_api/snapshot_api'; +import { ESSearchClient } from '.'; export const createTimeRangeWithInterval = async ( - framework: KibanaFramework, - requestContext: RequestHandlerContext, + client: ESSearchClient, options: InfraSnapshotRequestOptions ): Promise => { const aggregations = getMetricsAggregations(options); - const modules = await aggregationsToModules(framework, requestContext, aggregations, options); + const modules = await aggregationsToModules(client, aggregations, options); const interval = Math.max( (await calculateMetricInterval( - framework, - requestContext, + client, { indexPattern: options.sourceConfiguration.metricAlias, timestampField: options.sourceConfiguration.fields.timestamp, @@ -43,8 +40,7 @@ export const createTimeRangeWithInterval = async ( }; const aggregationsToModules = async ( - framework: KibanaFramework, - requestContext: RequestHandlerContext, + client: ESSearchClient, aggregations: SnapshotModel, options: InfraSnapshotRequestOptions ): Promise => { @@ -59,12 +55,7 @@ const aggregationsToModules = async ( const fields = await Promise.all( uniqueFields.map( async field => - await getDatasetForField( - framework, - requestContext, - field as string, - options.sourceConfiguration.metricAlias - ) + await getDatasetForField(client, field as string, options.sourceConfiguration.metricAlias) ) ); return fields.filter(f => f) as string[]; diff --git a/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts b/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts index 07abfa5fd474a..4057ed246ccaf 100644 --- a/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts +++ b/x-pack/plugins/infra/server/lib/snapshot/snapshot.ts @@ -3,11 +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 { RequestHandlerContext } from 'src/core/server'; -import { InfraDatabaseSearchResponse } from '../adapters/framework'; -import { KibanaFramework } from '../adapters/framework/kibana_framework_adapter'; -import { InfraSources } from '../sources'; +import { InfraDatabaseSearchResponse, CallWithRequestParams } from '../adapters/framework'; import { JsonObject } from '../../../common/typed_json'; import { SNAPSHOT_COMPOSITE_REQUEST_SIZE } from './constants'; @@ -31,36 +27,26 @@ import { InfraSnapshotRequestOptions } from './types'; import { createTimeRangeWithInterval } from './create_timerange_with_interval'; import { SnapshotNode } from '../../../common/http_api/snapshot_api'; +export type ESSearchClient = ( + options: CallWithRequestParams +) => Promise>; export class InfraSnapshot { - constructor(private readonly libs: { sources: InfraSources; framework: KibanaFramework }) {} - public async getNodes( - requestContext: RequestHandlerContext, + client: ESSearchClient, options: InfraSnapshotRequestOptions ): Promise<{ nodes: SnapshotNode[]; interval: string }> { // Both requestGroupedNodes and requestNodeMetrics may send several requests to elasticsearch // 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 timeRangeWithIntervalApplied = await createTimeRangeWithInterval( - this.libs.framework, - requestContext, - options - ); + const timeRangeWithIntervalApplied = await createTimeRangeWithInterval(client, options); const optionsWithTimerange = { ...options, timerange: timeRangeWithIntervalApplied }; - const groupedNodesPromise = requestGroupedNodes( - requestContext, - optionsWithTimerange, - this.libs.framework - ); - const nodeMetricsPromise = requestNodeMetrics( - requestContext, - optionsWithTimerange, - this.libs.framework - ); + const groupedNodesPromise = requestGroupedNodes(client, optionsWithTimerange); + const nodeMetricsPromise = requestNodeMetrics(client, optionsWithTimerange); const groupedNodeBuckets = await groupedNodesPromise; const nodeMetricBuckets = await nodeMetricsPromise; + return { nodes: mergeNodeBuckets(groupedNodeBuckets, nodeMetricBuckets, options), interval: timeRangeWithIntervalApplied.interval, @@ -77,15 +63,12 @@ const handleAfterKey = createAfterKeyHandler( input => input?.aggregations?.nodes?.after_key ); -const callClusterFactory = (framework: KibanaFramework, requestContext: RequestHandlerContext) => ( - opts: any -) => - framework.callWithRequest<{}, InfraSnapshotAggregationResponse>(requestContext, 'search', opts); +const callClusterFactory = (search: ESSearchClient) => (opts: any) => + search<{}, InfraSnapshotAggregationResponse>(opts); const requestGroupedNodes = async ( - requestContext: RequestHandlerContext, - options: InfraSnapshotRequestOptions, - framework: KibanaFramework + client: ESSearchClient, + options: InfraSnapshotRequestOptions ): Promise => { const inventoryModel = findInventoryModel(options.nodeType); const query = { @@ -124,13 +107,12 @@ const requestGroupedNodes = async ( return await getAllCompositeData< InfraSnapshotAggregationResponse, InfraSnapshotNodeGroupByBucket - >(callClusterFactory(framework, requestContext), query, bucketSelector, handleAfterKey); + >(callClusterFactory(client), query, bucketSelector, handleAfterKey); }; const requestNodeMetrics = async ( - requestContext: RequestHandlerContext, - options: InfraSnapshotRequestOptions, - framework: KibanaFramework + client: ESSearchClient, + options: InfraSnapshotRequestOptions ): Promise => { const index = options.metric.type === 'logRate' @@ -175,7 +157,7 @@ const requestNodeMetrics = async ( return await getAllCompositeData< InfraSnapshotAggregationResponse, InfraSnapshotNodeMetricsBucket - >(callClusterFactory(framework, requestContext), query, bucketSelector, handleAfterKey); + >(callClusterFactory(client), query, bucketSelector, handleAfterKey); }; // buckets can be InfraSnapshotNodeGroupByBucket[] or InfraSnapshotNodeMetricsBucket[] diff --git a/x-pack/plugins/infra/server/lib/sources/sources.ts b/x-pack/plugins/infra/server/lib/sources/sources.ts index 0368c7bfd6db8..71682c9e798a6 100644 --- a/x-pack/plugins/infra/server/lib/sources/sources.ts +++ b/x-pack/plugins/infra/server/lib/sources/sources.ts @@ -9,7 +9,7 @@ import { failure } from 'io-ts/lib/PathReporter'; import { identity, constant } from 'fp-ts/lib/function'; import { pipe } from 'fp-ts/lib/pipeable'; import { map, fold } from 'fp-ts/lib/Either'; -import { RequestHandlerContext, SavedObjectsClientContract } from 'src/core/server'; +import { SavedObjectsClientContract } from 'src/core/server'; import { defaultSourceConfiguration } from './defaults'; import { NotFoundError } from './errors'; import { infraSourceConfigurationSavedObjectType } from './saved_object_mappings'; @@ -41,7 +41,6 @@ export class InfraSources { sourceId: string ): Promise { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); - const savedSourceConfiguration = await this.getInternalSourceConfiguration(sourceId) .then(internalSourceConfiguration => ({ id: sourceId, @@ -79,10 +78,12 @@ export class InfraSources { return savedSourceConfiguration; } - public async getAllSourceConfigurations(requestContext: RequestHandlerContext) { + public async getAllSourceConfigurations(savedObjectsClient: SavedObjectsClientContract) { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); - const savedSourceConfigurations = await this.getAllSavedSourceConfigurations(requestContext); + const savedSourceConfigurations = await this.getAllSavedSourceConfigurations( + savedObjectsClient + ); return savedSourceConfigurations.map(savedSourceConfiguration => ({ ...savedSourceConfiguration, @@ -94,7 +95,7 @@ export class InfraSources { } public async createSourceConfiguration( - requestContext: RequestHandlerContext, + savedObjectsClient: SavedObjectsClientContract, sourceId: string, source: InfraSavedSourceConfiguration ) { @@ -106,7 +107,7 @@ export class InfraSources { ); const createdSourceConfiguration = convertSavedObjectToSavedSourceConfiguration( - await requestContext.core.savedObjects.client.create( + await savedObjectsClient.create( infraSourceConfigurationSavedObjectType, pickSavedSourceConfiguration(newSourceConfiguration) as any, { id: sourceId } @@ -122,22 +123,22 @@ export class InfraSources { }; } - public async deleteSourceConfiguration(requestContext: RequestHandlerContext, sourceId: string) { - await requestContext.core.savedObjects.client.delete( - infraSourceConfigurationSavedObjectType, - sourceId - ); + public async deleteSourceConfiguration( + savedObjectsClient: SavedObjectsClientContract, + sourceId: string + ) { + await savedObjectsClient.delete(infraSourceConfigurationSavedObjectType, sourceId); } public async updateSourceConfiguration( - requestContext: RequestHandlerContext, + savedObjectsClient: SavedObjectsClientContract, sourceId: string, sourceProperties: InfraSavedSourceConfiguration ) { const staticDefaultSourceConfiguration = await this.getStaticDefaultSourceConfiguration(); const { configuration, version } = await this.getSourceConfiguration( - requestContext.core.savedObjects.client, + savedObjectsClient, sourceId ); @@ -147,7 +148,7 @@ export class InfraSources { ); const updatedSourceConfiguration = convertSavedObjectToSavedSourceConfiguration( - await requestContext.core.savedObjects.client.update( + await savedObjectsClient.update( infraSourceConfigurationSavedObjectType, sourceId, pickSavedSourceConfiguration(updatedSourceConfigurationAttributes) as any, @@ -213,8 +214,8 @@ export class InfraSources { return convertSavedObjectToSavedSourceConfiguration(savedObject); } - private async getAllSavedSourceConfigurations(requestContext: RequestHandlerContext) { - const savedObjects = await requestContext.core.savedObjects.client.find({ + private async getAllSavedSourceConfigurations(savedObjectsClient: SavedObjectsClientContract) { + const savedObjects = await savedObjectsClient.find({ type: infraSourceConfigurationSavedObjectType, }); diff --git a/x-pack/plugins/infra/server/plugin.ts b/x-pack/plugins/infra/server/plugin.ts index d4dfa60ac67a0..db34033c1d4f8 100644 --- a/x-pack/plugins/infra/server/plugin.ts +++ b/x-pack/plugins/infra/server/plugin.ts @@ -109,7 +109,7 @@ export class InfraServerPlugin { sources, } ); - const snapshot = new InfraSnapshot({ sources, framework }); + const snapshot = new InfraSnapshot(); const logEntryCategoriesAnalysis = new LogEntryCategoriesAnalysis({ framework }); const logEntryRateAnalysis = new LogEntryRateAnalysis({ framework }); diff --git a/x-pack/plugins/infra/server/routes/log_sources/configuration.ts b/x-pack/plugins/infra/server/routes/log_sources/configuration.ts index 0ce594675773c..46929954431f5 100644 --- a/x-pack/plugins/infra/server/routes/log_sources/configuration.ts +++ b/x-pack/plugins/infra/server/routes/log_sources/configuration.ts @@ -82,12 +82,12 @@ export const initLogSourceConfigurationRoutes = ({ framework, sources }: InfraBa const sourceConfigurationExists = sourceConfiguration.origin === 'stored'; const patchedSourceConfiguration = await (sourceConfigurationExists ? sources.updateSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId, patchedSourceConfigurationProperties ) : sources.createSourceConfiguration( - requestContext, + requestContext.core.savedObjects.client, sourceId, patchedSourceConfigurationProperties )); diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts index 66f0ca8fc706a..94e91d32b14bb 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/get_dataset_for_field.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { RequestHandlerContext } from 'kibana/server'; -import { KibanaFramework } from '../../../lib/adapters/framework/kibana_framework_adapter'; +import { ESSearchClient } from '../../../lib/snapshot'; interface EventDatasetHit { _source: { @@ -16,8 +15,7 @@ interface EventDatasetHit { } export const getDatasetForField = async ( - framework: KibanaFramework, - requestContext: RequestHandlerContext, + client: ESSearchClient, field: string, indexPattern: string ) => { @@ -33,11 +31,8 @@ export const getDatasetForField = async ( }, }; - const response = await framework.callWithRequest( - requestContext, - 'search', - params - ); + const response = await client(params); + if (response.hits.total.value === 0) { return null; } diff --git a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts index e735a26d96a91..a709cbdeeb680 100644 --- a/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts +++ b/x-pack/plugins/infra/server/routes/metrics_explorer/lib/populate_series_with_tsvb_data.ts @@ -17,6 +17,10 @@ import { createMetricModel } from './create_metrics_model'; import { JsonObject } from '../../../../common/typed_json'; import { calculateMetricInterval } from '../../../utils/calculate_metric_interval'; import { getDatasetForField } from './get_dataset_for_field'; +import { + CallWithRequestParams, + InfraDatabaseSearchResponse, +} from '../../../lib/adapters/framework'; export const populateSeriesWithTSVBData = ( request: KibanaRequest, @@ -52,17 +56,21 @@ export const populateSeriesWithTSVBData = ( } const timerange = { min: options.timerange.from, max: options.timerange.to }; + const client = ( + opts: CallWithRequestParams + ): Promise> => + framework.callWithRequest(requestContext, 'search', opts); + // Create the TSVB model based on the request options const model = createMetricModel(options); const modules = await Promise.all( uniq(options.metrics.filter(m => m.field)).map( - async m => - await getDatasetForField(framework, requestContext, m.field as string, options.indexPattern) + async m => await getDatasetForField(client, m.field as string, options.indexPattern) ) ); + const calculatedInterval = await calculateMetricInterval( - framework, - requestContext, + client, { indexPattern: options.indexPattern, timestampField: options.timerange.field, diff --git a/x-pack/plugins/infra/server/routes/snapshot/index.ts b/x-pack/plugins/infra/server/routes/snapshot/index.ts index d1dc03893a0d9..2d951d426b03a 100644 --- a/x-pack/plugins/infra/server/routes/snapshot/index.ts +++ b/x-pack/plugins/infra/server/routes/snapshot/index.ts @@ -13,6 +13,7 @@ import { UsageCollector } from '../../usage/usage_collector'; import { parseFilterQuery } from '../../utils/serialized_query'; import { SnapshotRequestRT, SnapshotNodeResponseRT } from '../../../common/http_api/snapshot_api'; import { throwErrors } from '../../../common/runtime_types'; +import { CallWithRequestParams, InfraDatabaseSearchResponse } from '../../lib/adapters/framework'; const escapeHatch = schema.object({}, { unknowns: 'allow' }); @@ -57,7 +58,13 @@ export const initSnapshotRoute = (libs: InfraBackendLibs) => { metric, timerange, }; - const nodesWithInterval = await libs.snapshot.getNodes(requestContext, options); + + const searchES = ( + opts: CallWithRequestParams + ): Promise> => + framework.callWithRequest(requestContext, 'search', opts); + + const nodesWithInterval = await libs.snapshot.getNodes(searchES, options); return response.ok({ body: SnapshotNodeResponseRT.encode(nodesWithInterval), }); diff --git a/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts b/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts index 7cbbdc0f2145b..43e109b009f48 100644 --- a/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts +++ b/x-pack/plugins/infra/server/utils/calculate_metric_interval.ts @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { RequestHandlerContext } from 'src/core/server'; +// import { RequestHandlerContext } from 'src/core/server'; import { findInventoryModel } from '../../common/inventory_models'; -import { KibanaFramework } from '../lib/adapters/framework/kibana_framework_adapter'; +// import { KibanaFramework } from '../lib/adapters/framework/kibana_framework_adapter'; import { InventoryItemType } from '../../common/inventory_models/types'; +import { ESSearchClient } from '../lib/snapshot'; interface Options { indexPattern: string; @@ -23,8 +24,7 @@ interface Options { * This is useful for visualizing metric modules like s3 that only send metrics once per day. */ export const calculateMetricInterval = async ( - framework: KibanaFramework, - requestContext: RequestHandlerContext, + client: ESSearchClient, options: Options, modules?: string[], nodeType?: InventoryItemType // TODO: check that this type still makes sense @@ -73,11 +73,7 @@ export const calculateMetricInterval = async ( }, }; - const resp = await framework.callWithRequest<{}, PeriodAggregationData>( - requestContext, - 'search', - query - ); + const resp = await client<{}, PeriodAggregationData>(query); // if ES doesn't return an aggregations key, something went seriously wrong. if (!resp.aggregations) { diff --git a/x-pack/test/api_integration/apis/infra/metrics_alerting.ts b/x-pack/test/api_integration/apis/infra/metrics_alerting.ts index 19879f5761ab2..5c43e8938a8c1 100644 --- a/x-pack/test/api_integration/apis/infra/metrics_alerting.ts +++ b/x-pack/test/api_integration/apis/infra/metrics_alerting.ts @@ -32,7 +32,7 @@ export default function({ getService }: FtrProviderContext) { describe('querying the entire infrastructure', () => { for (const aggType of aggs) { it(`should work with the ${aggType} aggregator`, async () => { - const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType)); + const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType), '@timestamp'); const result = await client.search({ index, body: searchBody, @@ -45,6 +45,7 @@ export default function({ getService }: FtrProviderContext) { it('should work with a filterQuery', async () => { const searchBody = getElasticsearchMetricQuery( getSearchParams('avg'), + '@timestamp', undefined, '{"bool":{"should":[{"match_phrase":{"agent.hostname":"foo"}}],"minimum_should_match":1}}' ); @@ -59,6 +60,7 @@ export default function({ getService }: FtrProviderContext) { it('should work with a filterQuery in KQL format', async () => { const searchBody = getElasticsearchMetricQuery( getSearchParams('avg'), + '@timestamp', undefined, '"agent.hostname":"foo"' ); @@ -74,7 +76,11 @@ export default function({ getService }: FtrProviderContext) { describe('querying with a groupBy parameter', () => { for (const aggType of aggs) { it(`should work with the ${aggType} aggregator`, async () => { - const searchBody = getElasticsearchMetricQuery(getSearchParams(aggType), 'agent.id'); + const searchBody = getElasticsearchMetricQuery( + getSearchParams(aggType), + '@timestamp', + 'agent.id' + ); const result = await client.search({ index, body: searchBody, @@ -87,6 +93,7 @@ export default function({ getService }: FtrProviderContext) { it('should work with a filterQuery', async () => { const searchBody = getElasticsearchMetricQuery( getSearchParams('avg'), + '@timestamp', 'agent.id', '{"bool":{"should":[{"match_phrase":{"agent.hostname":"foo"}}],"minimum_should_match":1}}' ); From ffe5166023a8e4d82d5b4fead3718d69a0dc62bc Mon Sep 17 00:00:00 2001 From: Sandra Gonzales Date: Thu, 30 Apr 2020 17:54:37 -0400 Subject: [PATCH 10/10] [EPM] restrict package install endpoint from installing/updating to old packages (#64932) * restrict installing or updating to out-of-date package * throw bad requests in remove handler * remove accidental commit * remove space --- .../ingest_manager/server/routes/epm/handlers.ts | 12 ++++++++++++ .../server/services/epm/packages/install.ts | 12 ++++++++++-- .../server/services/epm/packages/remove.ts | 5 +++-- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts b/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts index ad16e1dde456b..fd3a9c520b90a 100644 --- a/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts +++ b/x-pack/plugins/ingest_manager/server/routes/epm/handlers.ts @@ -136,6 +136,12 @@ export const installPackageHandler: RequestHandler