From b42defa37e5d1292fa067f80fceadb298c2d8bae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cau=C3=AA=20Marcondes?= <55978943+cauemarcondes@users.noreply.github.com> Date: Tue, 16 Jun 2020 16:17:17 +0100 Subject: [PATCH 01/41] [Observability] Update landing page copy and content (#69247) * removing try it section * removing try it section --- .../observability/public/pages/home/index.tsx | 43 +------------------ .../public/pages/home/section.ts | 22 ---------- 2 files changed, 1 insertion(+), 64 deletions(-) diff --git a/x-pack/plugins/observability/public/pages/home/index.tsx b/x-pack/plugins/observability/public/pages/home/index.tsx index 072d3c47d3a55..696361393ef82 100644 --- a/x-pack/plugins/observability/public/pages/home/index.tsx +++ b/x-pack/plugins/observability/public/pages/home/index.tsx @@ -10,7 +10,6 @@ import { EuiFlexGrid, EuiFlexGroup, EuiFlexItem, - EuiHorizontalRule, EuiIcon, EuiImage, EuiSpacer, @@ -21,7 +20,7 @@ import { i18n } from '@kbn/i18n'; import React, { useEffect } from 'react'; import styled from 'styled-components'; import { usePluginContext } from '../../hooks/use_plugin_context'; -import { appsSection, tryItOutItemsSection } from './section'; +import { appsSection } from './section'; const Container = styled.div` min-height: calc(100vh - 48px); @@ -158,46 +157,6 @@ export const Home = () => { - - - - {/* Try it out */} - - - - -

- {i18n.translate('xpack.observability.home.tryItOut', { - defaultMessage: 'Try it out', - })} -

-
-
-
-
- - {/* Try it out sections */} - - - {tryItOutItemsSection.map((item) => ( - - } - title={ - -

{item.title}

-
- } - description={item.description} - target={item.target} - href={item.href} - /> -
- ))} -
- -
diff --git a/x-pack/plugins/observability/public/pages/home/section.ts b/x-pack/plugins/observability/public/pages/home/section.ts index f8bbfbfa30548..a2b82c31bf2ab 100644 --- a/x-pack/plugins/observability/public/pages/home/section.ts +++ b/x-pack/plugins/observability/public/pages/home/section.ts @@ -60,25 +60,3 @@ export const appsSection: ISection[] = [ }), }, ]; - -export const tryItOutItemsSection: ISection[] = [ - { - id: 'demo', - title: i18n.translate('xpack.observability.section.tryItOut.demo.title', { - defaultMessage: 'Demo Playground', - }), - icon: 'play', - description: '', - href: 'https://demo.elastic.co/', - target: '_blank', - }, - { - id: 'sampleData', - title: i18n.translate('xpack.observability.section.tryItOut.sampleData.title', { - defaultMessage: 'Add sample data', - }), - icon: 'documents', - description: '', - href: '/app/home#/tutorial_directory/sampleData', - }, -]; From f43d51d41bd9cf347db8064297b9fe7ebd347801 Mon Sep 17 00:00:00 2001 From: Vignesh Shanmugam Date: Tue, 16 Jun 2020 17:24:40 +0200 Subject: [PATCH 02/41] feat: instrument navigation changes using RUM agent (#67633) * feat: instrument navigation changes using RUM agent * chore: rebase and change application contract * chore: fix type tests * docs: update public.md doc * chore: remove internal application export --- .github/CODEOWNERS | 3 +-- package.json | 2 +- src/core/public/core_system.ts | 4 +++ src/core/public/kbn_bootstrap.ts | 30 +++++++++++++++++++--- src/core/public/public.api.md | 8 +++++- src/legacy/ui/apm/index.js | 10 ++------ src/legacy/ui/ui_render/ui_render_mixin.js | 2 +- x-pack/package.json | 2 +- yarn.lock | 28 ++++++++++---------- 9 files changed, 57 insertions(+), 32 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 00573e04396b4..681564b44297f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -66,11 +66,10 @@ # APM /x-pack/plugins/apm/ @elastic/apm-ui -/x-pack/plugins/apm/ @elastic/apm-ui /x-pack/test/functional/apps/apm/ @elastic/apm-ui /src/legacy/core_plugins/apm_oss/ @elastic/apm-ui /src/plugins/apm_oss/ @elastic/apm-ui -/src/apm.js @watson +/src/apm.js @watson @vigneshshanmugam # Beats /x-pack/legacy/plugins/beats_management/ @elastic/beats diff --git a/package.json b/package.json index 89f380e5a7a0a..b886e6ae0f5d3 100644 --- a/package.json +++ b/package.json @@ -122,7 +122,7 @@ "@babel/core": "^7.10.2", "@babel/plugin-transform-modules-commonjs": "^7.10.1", "@babel/register": "^7.10.1", - "@elastic/apm-rum": "^5.1.1", + "@elastic/apm-rum": "^5.2.0", "@elastic/charts": "19.2.0", "@elastic/datemath": "5.0.3", "@elastic/ems-client": "7.9.3", diff --git a/src/core/public/core_system.ts b/src/core/public/core_system.ts index aa52212344f4d..d6172b77d3ca5 100644 --- a/src/core/public/core_system.ts +++ b/src/core/public/core_system.ts @@ -300,6 +300,10 @@ export class CoreSystem { plugins: mapToObject(plugins.contracts), targetDomElement: rendering.legacyTargetDomElement, }); + + return { + application, + }; } catch (error) { if (this.fatalErrorsSetup) { this.fatalErrorsSetup.add(error); diff --git a/src/core/public/kbn_bootstrap.ts b/src/core/public/kbn_bootstrap.ts index caeb95a540de3..0f86061816701 100644 --- a/src/core/public/kbn_bootstrap.ts +++ b/src/core/public/kbn_bootstrap.ts @@ -38,11 +38,17 @@ export function __kbnBootstrap__() { * `apmConfig` would be populated with relavant APM RUM agent * configuration if server is started with `ELASTIC_APM_ACTIVE=true` */ - if (process.env.IS_KIBANA_DISTRIBUTABLE !== 'true' && injectedMetadata.vars.apmConfig != null) { + const apmConfig = injectedMetadata.vars.apmConfig; + const APM_ENABLED = process.env.IS_KIBANA_DISTRIBUTABLE !== 'true' && apmConfig != null; + + if (APM_ENABLED) { // @ts-ignore // eslint-disable-next-line @typescript-eslint/no-var-requires - const { init } = require('@elastic/apm-rum'); - init(injectedMetadata.vars.apmConfig); + const { init, apm } = require('@elastic/apm-rum'); + if (apmConfig.globalLabels) { + apm.addLabels(apmConfig.globalLabels); + } + init(apmConfig); } i18n @@ -60,6 +66,22 @@ export function __kbnBootstrap__() { setup.fatalErrors.add(i18nError); } - await coreSystem.start(); + const start = await coreSystem.start(); + + if (APM_ENABLED && start) { + /** + * Register listeners for navigation changes and capture them as + * route-change transactions after Kibana app is bootstrapped + */ + start.application.currentAppId$.subscribe((appId) => { + const apmInstance = (window as any).elasticApm; + if (appId && apmInstance && typeof apmInstance.startTransaction === 'function') { + apmInstance.startTransaction(`/app/${appId}`, 'route-change', { + managed: true, + canReuse: true, + }); + } + }); + } }); } diff --git a/src/core/public/public.api.md b/src/core/public/public.api.md index 1914fa7be89ec..0fdb5e415ec0e 100644 --- a/src/core/public/public.api.md +++ b/src/core/public/public.api.md @@ -562,7 +562,9 @@ export class CoreSystem { fatalErrors: FatalErrorsSetup; } | undefined>; // (undocumented) - start(): Promise; + start(): Promise<{ + application: InternalApplicationStart; + } | undefined>; // (undocumented) stop(): void; } @@ -1587,4 +1589,8 @@ export interface UserProvidedValues { } +// Warnings were encountered during analysis: +// +// src/core/public/core_system.ts:216:21 - (ae-forgotten-export) The symbol "InternalApplicationStart" needs to be exported by the entry point index.d.ts + ``` diff --git a/src/legacy/ui/apm/index.js b/src/legacy/ui/apm/index.js index f1074091e2624..c43b7b01d1159 100644 --- a/src/legacy/ui/apm/index.js +++ b/src/legacy/ui/apm/index.js @@ -30,21 +30,15 @@ export function apmInit(config) { return apmEnabled ? `init(${config})` : ''; } -export function getApmConfig(app) { +export function getApmConfig(requestPath) { if (!apmEnabled) { return null; } - /** - * we use the injected app metadata from the server to extract the - * app id to be used for page-load transaction - */ - const appId = app.getId(); - const config = { ...getConfig('kibana-frontend'), ...{ active: true, - pageLoadTransactionName: appId, + pageLoadTransactionName: requestPath, }, }; /** diff --git a/src/legacy/ui/ui_render/ui_render_mixin.js b/src/legacy/ui/ui_render/ui_render_mixin.js index 673e19155879a..b4f8255297240 100644 --- a/src/legacy/ui/ui_render/ui_render_mixin.js +++ b/src/legacy/ui/ui_render/ui_render_mixin.js @@ -241,7 +241,7 @@ export function uiRenderMixin(kbnServer, server, config) { savedObjects.getClient(h.request) ); const vars = await legacy.getVars(app.getId(), h.request, { - apmConfig: getApmConfig(app), + apmConfig: getApmConfig(h.request.path), ...overrides, }); const content = await rendering.render(h.request, uiSettings, { diff --git a/x-pack/package.json b/x-pack/package.json index 172a6bc30125b..c582cc8be9bbd 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -188,7 +188,7 @@ "@babel/core": "^7.10.2", "@babel/register": "^7.10.1", "@babel/runtime": "^7.10.2", - "@elastic/apm-rum-react": "^1.1.1", + "@elastic/apm-rum-react": "^1.1.2", "@elastic/datemath": "5.0.3", "@elastic/ems-client": "7.9.3", "@elastic/eui": "24.1.0", diff --git a/yarn.lock b/yarn.lock index 14e4cdd62955a..0188957073965 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2076,29 +2076,29 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@elastic/apm-rum-core@^5.2.0": - version "5.2.0" - resolved "https://registry.yarnpkg.com/@elastic/apm-rum-core/-/apm-rum-core-5.2.0.tgz#2ed30dc226c9b5779532ab2e6065a155587bcea4" - integrity sha512-3ti2dhrqfxjHFXgArQI/sVAG2AgZH0kB1nx+2WjLpuAh8gGS4R772M5VXcWcGQb8UW9jrANwwbW2hT2GKv+uOA== +"@elastic/apm-rum-core@^5.3.0": + version "5.3.0" + resolved "https://registry.yarnpkg.com/@elastic/apm-rum-core/-/apm-rum-core-5.3.0.tgz#3ae5e84eba5b5287b92458a49755f6e39e7bba5b" + integrity sha512-b/qAnPqi3km808BhSYo+ROpTINm3eVBQ6hNcxOELwKitS3O/HikkwRn5aPkVIhQXOVrbPSufMl1A991nrE3daA== dependencies: error-stack-parser "^1.3.5" opentracing "^0.14.3" promise-polyfill "^8.1.3" -"@elastic/apm-rum-react@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@elastic/apm-rum-react/-/apm-rum-react-1.1.1.tgz#3a2ba91efc9260da55ef6c31cce642a476eba828" - integrity sha512-ZMixw+82VbZIDBnz0dj5Fo4PZ7pnXlLjAA7XTi3AtSIEjpsZa7YIuCFzJdrgb/nOq7MOFkODkFPTiIYAM/yCqg== +"@elastic/apm-rum-react@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@elastic/apm-rum-react/-/apm-rum-react-1.1.2.tgz#274cc414074d05e33e8f0afcad25ef9a30d99452" + integrity sha512-2/wEaPF4EQaVzU8Qj5aYucDc+VFr7438AieON31fx8wsbvnxh9iG+iV7xky2YtT/mf53BbFgZm35L5y/pxCKwA== dependencies: - "@elastic/apm-rum" "^5.1.1" + "@elastic/apm-rum" "^5.2.0" hoist-non-react-statics "^3.3.0" -"@elastic/apm-rum@^5.1.1": - version "5.1.1" - resolved "https://registry.yarnpkg.com/@elastic/apm-rum/-/apm-rum-5.1.1.tgz#02d29fa606e66f9a3a88f629d468b02457b1b183" - integrity sha512-A0O/0ZffcHm1taLuXyFoUmV2+aARr+9+xbmsEDIExLV0yKaNlaLl3UaZrodSOZ1ijlCEsRRS+y2i0md93YKQTA== +"@elastic/apm-rum@^5.2.0": + version "5.2.0" + resolved "https://registry.yarnpkg.com/@elastic/apm-rum/-/apm-rum-5.2.0.tgz#b0cfd6e5771b1e765fda2715a38c87746f49f1aa" + integrity sha512-l8/Ji1GMuahMCN5DsALIf+fioKi1QeY4pU0izfVI37se2/fxsMNEDpw52WxJknHdfBE0Imh3FPg4T56J5MO+IQ== dependencies: - "@elastic/apm-rum-core" "^5.2.0" + "@elastic/apm-rum-core" "^5.3.0" "@elastic/charts@19.2.0": version "19.2.0" From a9d73e868395c7d29ee5b96a38756b758ae6e802 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 16 Jun 2020 18:04:52 +0200 Subject: [PATCH 03/41] [Uptime] Monitor availability reporting (#67790) Co-authored-by: Elastic Machine --- .../translations/translations/ja-JP.json | 6 - .../translations/translations/zh-CN.json | 6 - .../uptime/common/runtime_types/common.ts | 15 +- .../common/runtime_types/monitor/locations.ts | 12 +- .../components/certificates/translations.ts | 4 + .../public/components/common/translations.ts | 11 + .../uptime/public/components/monitor/index.ts | 4 +- .../__snapshots__/location_map.test.tsx.snap | 282 ----- .../location_status_tags.test.tsx.snap | 682 ----------- .../monitor/location_map/location_map.tsx | 95 -- .../location_map/location_status_tags.tsx | 130 -- .../monitor_status.bar.test.tsx.snap | 55 - .../monitor_status_bar/ssl_certificate.tsx | 100 -- .../monitor_status_bar/status_bar.tsx | 61 - .../monitor_status_details/translations.ts | 50 - .../monitor_status.bar.test.tsx.snap | 73 ++ .../ssl_certificate.test.tsx.snap | 114 +- .../status_by_location.test.tsx.snap | 0 .../__test__/monitor_status.bar.test.tsx | 28 +- .../__test__/ssl_certificate.test.tsx | 24 +- .../__test__/status_by_location.test.tsx | 30 + .../availability_reporting.test.tsx.snap | 381 ++++++ .../location_status_tags.test.tsx.snap | 1085 +++++++++++++++++ .../__snapshots__/tag_label.test.tsx.snap | 56 + .../__tests__/availability_reporting.test.tsx | 42 + .../__tests__/location_status_tags.test.tsx | 32 +- .../__tests__/tag_label.test.tsx | 21 + .../availability_reporting.tsx | 87 ++ .../availability_reporting/index.ts | 9 + .../location_status_tags.tsx | 73 ++ .../availability_reporting/tag_label.tsx | 35 + .../index.ts | 6 +- .../location_availability.test.tsx.snap | 234 ++++ .../__tests__/location_availability.test.tsx} | 52 +- .../location_availability.tsx | 90 ++ .../location_availability/toggle_view_btn.tsx | 61 + .../use_selected_view.ts | 26 + .../__snapshots__/location_map.test.tsx.snap | 27 + .../location_missing.test.tsx.snap | 1 + .../__tests__/location_map.test.tsx | 33 + .../__tests__/location_missing.test.tsx | 0 .../embeddables/__tests__/__mocks__/mock.ts | 6 + .../embeddables/__tests__/map_config.test.ts | 14 +- .../location_map/embeddables/embedded_map.tsx | 55 +- .../embeddables/low_poly_layer.json | 0 .../location_map/embeddables/map_config.ts | 8 +- .../location_map/embeddables/map_tool_tip.tsx | 90 ++ .../location_map/embeddables/translations.ts | 0 .../location_map/index.ts | 2 +- .../location_map/location_map.tsx | 34 + .../location_map/location_missing.tsx | 3 +- .../status_bar}/index.ts | 3 +- .../status_bar/ssl_certificate.tsx | 41 + .../status_details/status_bar/status_bar.tsx | 82 ++ .../status_bar}/status_by_location.tsx | 0 .../status_bar/use_status_bar.ts} | 31 +- .../status_details.tsx | 27 +- .../status_details_container.tsx | 4 +- .../translations.ts | 53 + .../monitor_list/cert_status_column.tsx | 31 +- .../overview/monitor_list/monitor_list.tsx | 3 +- .../overview/monitor_list/translations.ts | 4 - .../__snapshots__/page_header.test.tsx.snap | 40 +- .../uptime/public/pages/page_header.tsx | 7 +- .../lib/requests/get_monitor_locations.ts | 27 +- x-pack/test/accessibility/apps/uptime.ts | 2 +- .../test/functional/apps/uptime/locations.ts | 73 +- .../test/functional/services/uptime/common.ts | 4 +- .../functional/services/uptime/monitor.ts | 11 + .../functional/services/uptime/navigation.ts | 9 + 70 files changed, 3125 insertions(+), 1672 deletions(-) create mode 100644 x-pack/plugins/uptime/public/components/common/translations.ts delete mode 100644 x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_map.test.tsx.snap delete mode 100644 x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap delete mode 100644 x-pack/plugins/uptime/public/components/monitor/location_map/location_map.tsx delete mode 100644 x-pack/plugins/uptime/public/components/monitor/location_map/location_status_tags.tsx delete mode 100644 x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap delete mode 100644 x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx delete mode 100644 x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar.tsx delete mode 100644 x-pack/plugins/uptime/public/components/monitor/monitor_status_details/translations.ts create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details => status_details}/__test__/__snapshots__/ssl_certificate.test.tsx.snap (61%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details => status_details}/__test__/__snapshots__/status_by_location.test.tsx.snap (100%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details => status_details}/__test__/monitor_status.bar.test.tsx (70%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details => status_details}/__test__/ssl_certificate.test.tsx (75%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details => status_details}/__test__/status_by_location.test.tsx (77%) create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/availability_reporting.test.tsx.snap create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/location_status_tags.test.tsx.snap create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/tag_label.test.tsx.snap create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/availability_reporting.test.tsx rename x-pack/plugins/uptime/public/components/monitor/{location_map => status_details/availability_reporting}/__tests__/location_status_tags.test.tsx (84%) create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/tag_label.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/availability_reporting.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/index.ts create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/location_status_tags.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/tag_label.tsx rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details => status_details}/index.ts (63%) create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/__tests__/__snapshots__/location_availability.test.tsx.snap rename x-pack/plugins/uptime/public/components/monitor/{location_map/__tests__/location_map.test.tsx => status_details/location_availability/__tests__/location_availability.test.tsx} (64%) create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/location_availability.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/toggle_view_btn.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/use_selected_view.ts create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/__snapshots__/location_map.test.tsx.snap rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap (99%) create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/location_map.test.tsx rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/__tests__/location_missing.test.tsx (100%) rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/embeddables/__tests__/__mocks__/mock.ts (96%) rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/embeddables/__tests__/map_config.test.ts (65%) rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/embeddables/embedded_map.tsx (68%) rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/embeddables/low_poly_layer.json (100%) rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/embeddables/map_config.ts (94%) create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/embeddables/translations.ts (100%) rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/index.ts (81%) create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/location_map/location_map.tsx rename x-pack/plugins/uptime/public/components/monitor/{ => status_details}/location_map/location_missing.tsx (96%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details/monitor_status_bar => status_details/status_bar}/index.ts (72%) create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/ssl_certificate.tsx create mode 100644 x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/status_bar.tsx rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details/monitor_status_bar => status_details/status_bar}/status_by_location.tsx (100%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details/monitor_status_bar/status_bar_container.tsx => status_details/status_bar/use_status_bar.ts} (66%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details => status_details}/status_details.tsx (72%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details => status_details}/status_details_container.tsx (92%) rename x-pack/plugins/uptime/public/components/monitor/{monitor_status_details/monitor_status_bar => status_details}/translations.ts (50%) diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index a1b0fb8a3de70..7b887867b43b8 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -16606,7 +16606,6 @@ "xpack.uptime.locationMap.locations.missing.message": "重要な位置情報構成がありません。{codeBlock}フィールドを使用して、アップタイムチェック用に一意の地域を作成できます。", "xpack.uptime.locationMap.locations.missing.message1": "詳細については、ドキュメンテーションを参照してください。", "xpack.uptime.locationMap.locations.missing.title": "地理情報の欠測", - "xpack.uptime.locationMap.locations.tags.others": "{otherLoc}その他 ...", "xpack.uptime.locationName.helpLinkAnnotation": "場所を追加", "xpack.uptime.ml.durationChart.exploreInMlApp": "ML アプリで探索", "xpack.uptime.ml.enableAnomalyDetectionPanel.anomalyDetectionTitle": "異常検知", @@ -16690,12 +16689,7 @@ "xpack.uptime.monitorStatusBar.locations.oneLocStatus": "{loc}場所での{status}", "xpack.uptime.monitorStatusBar.locations.upStatus": "{loc}場所での{status}", "xpack.uptime.monitorStatusBar.monitorUrlLinkAriaLabel": "監視 URL リンク", - "xpack.uptime.monitorStatusBar.sslCertificate.overview": "証明書概要", "xpack.uptime.monitorStatusBar.sslCertificate.title": "証明書", - "xpack.uptime.monitorStatusBar.sslCertificateExpired.badgeContent": "{emphasizedText}が期限切れになりました", - "xpack.uptime.monitorStatusBar.sslCertificateExpired.label.ariaLabel": "{validityDate}に期限切れになりました", - "xpack.uptime.monitorStatusBar.sslCertificateExpiry.badgeContent": "{emphasizedText}が期限切れになります", - "xpack.uptime.monitorStatusBar.sslCertificateExpiry.label.ariaLabel": "{validityDate}に期限切れになります", "xpack.uptime.monitorStatusBar.timestampFromNowTextAriaLabel": "最終確認からの経過時間", "xpack.uptime.navigateToAlertingButton.content": "アラートを管理", "xpack.uptime.navigateToAlertingUi": "Uptime を離れてアラート管理ページに移動します", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 6047de1deb12a..e821c4fb22899 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -16612,7 +16612,6 @@ "xpack.uptime.locationMap.locations.missing.message": "重要的地理位置配置缺失。您可以使用 {codeBlock} 字段为您的运行时间检查创建独特的地理区域。", "xpack.uptime.locationMap.locations.missing.message1": "在我们的文档中获取更多的信息。", "xpack.uptime.locationMap.locations.missing.title": "地理信息缺失", - "xpack.uptime.locationMap.locations.tags.others": "{otherLoc} 其他......", "xpack.uptime.locationName.helpLinkAnnotation": "添加位置", "xpack.uptime.ml.durationChart.exploreInMlApp": "在 ML 应用中浏览", "xpack.uptime.ml.enableAnomalyDetectionPanel.anomalyDetectionTitle": "异常检测", @@ -16696,12 +16695,7 @@ "xpack.uptime.monitorStatusBar.locations.oneLocStatus": "在 {loc} 位置{status}", "xpack.uptime.monitorStatusBar.locations.upStatus": "在 {loc} 位置{status}", "xpack.uptime.monitorStatusBar.monitorUrlLinkAriaLabel": "监测 URL 链接", - "xpack.uptime.monitorStatusBar.sslCertificate.overview": "证书概览", "xpack.uptime.monitorStatusBar.sslCertificate.title": "证书", - "xpack.uptime.monitorStatusBar.sslCertificateExpired.badgeContent": "{emphasizedText}过期", - "xpack.uptime.monitorStatusBar.sslCertificateExpired.label.ariaLabel": "已于 {validityDate}过期", - "xpack.uptime.monitorStatusBar.sslCertificateExpiry.badgeContent": "{emphasizedText}过期", - "xpack.uptime.monitorStatusBar.sslCertificateExpiry.label.ariaLabel": "将于 {validityDate}过期", "xpack.uptime.monitorStatusBar.timestampFromNowTextAriaLabel": "自上次检查以来经过的时间", "xpack.uptime.navigateToAlertingButton.content": "管理告警", "xpack.uptime.navigateToAlertingUi": "离开 Uptime 并前往“Alerting 管理”页面", diff --git a/x-pack/plugins/uptime/common/runtime_types/common.ts b/x-pack/plugins/uptime/common/runtime_types/common.ts index e07c46fa01cfe..603d242d4dcd0 100644 --- a/x-pack/plugins/uptime/common/runtime_types/common.ts +++ b/x-pack/plugins/uptime/common/runtime_types/common.ts @@ -6,15 +6,19 @@ import * as t from 'io-ts'; -export const LocationType = t.partial({ +export const LocationType = t.type({ lat: t.string, lon: t.string, }); -export const CheckGeoType = t.partial({ - name: t.string, - location: LocationType, -}); +export const CheckGeoType = t.intersection([ + t.type({ + name: t.string, + }), + t.partial({ + location: LocationType, + }), +]); export const SummaryType = t.partial({ up: t.number, @@ -34,5 +38,6 @@ export const DateRangeType = t.type({ export type Summary = t.TypeOf; export type Location = t.TypeOf; +export type GeoPoint = t.TypeOf; export type StatesIndexStatus = t.TypeOf; export type DateRange = t.TypeOf; diff --git a/x-pack/plugins/uptime/common/runtime_types/monitor/locations.ts b/x-pack/plugins/uptime/common/runtime_types/monitor/locations.ts index ea3cfe677ca99..00ed1dc407e98 100644 --- a/x-pack/plugins/uptime/common/runtime_types/monitor/locations.ts +++ b/x-pack/plugins/uptime/common/runtime_types/monitor/locations.ts @@ -7,17 +7,23 @@ import * as t from 'io-ts'; import { CheckGeoType, SummaryType } from '../common'; // IO type for validation -export const MonitorLocationType = t.partial({ +export const MonitorLocationType = t.type({ + up_history: t.number, + down_history: t.number, + timestamp: t.string, summary: SummaryType, geo: CheckGeoType, - timestamp: t.string, }); // Typescript type for type checking export type MonitorLocation = t.TypeOf; export const MonitorLocationsType = t.intersection([ - t.type({ monitorId: t.string }), + t.type({ + monitorId: t.string, + up_history: t.number, + down_history: t.number, + }), t.partial({ locations: t.array(MonitorLocationType) }), ]); export type MonitorLocations = t.TypeOf; diff --git a/x-pack/plugins/uptime/public/components/certificates/translations.ts b/x-pack/plugins/uptime/public/components/certificates/translations.ts index 518eddf1211a4..176625d647ca0 100644 --- a/x-pack/plugins/uptime/public/components/certificates/translations.ts +++ b/x-pack/plugins/uptime/public/components/certificates/translations.ts @@ -18,6 +18,10 @@ export const EXPIRES_SOON = i18n.translate('xpack.uptime.certs.expireSoon', { defaultMessage: 'Expires soon', }); +export const EXPIRES = i18n.translate('xpack.uptime.certs.expires', { + defaultMessage: 'Expires', +}); + export const SEARCH_CERTS = i18n.translate('xpack.uptime.certs.searchCerts', { defaultMessage: 'Search certificates', }); diff --git a/x-pack/plugins/uptime/public/components/common/translations.ts b/x-pack/plugins/uptime/public/components/common/translations.ts new file mode 100644 index 0000000000000..d2c466ddf0c83 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/common/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 URL_LABEL = i18n.translate('xpack.uptime.monitorList.table.url.name', { + defaultMessage: 'Url', +}); diff --git a/x-pack/plugins/uptime/public/components/monitor/index.ts b/x-pack/plugins/uptime/public/components/monitor/index.ts index cb7b27afded02..fd9a9a2c897d7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/index.ts +++ b/x-pack/plugins/uptime/public/components/monitor/index.ts @@ -6,7 +6,7 @@ export * from './ml'; export * from './ping_list'; -export * from './location_map'; -export * from './monitor_status_details'; +export * from './status_details/location_map'; +export * from './status_details'; export * from './ping_histogram'; export * from './monitor_charts'; diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_map.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_map.test.tsx.snap deleted file mode 100644 index 7b847782fe1ac..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_map.test.tsx.snap +++ /dev/null @@ -1,282 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`LocationMap component doesnt shows warning if geo is provided 1`] = ` - - - - - - - - - - - - - - -`; - -exports[`LocationMap component renders correctly against snapshot 1`] = ` - - - - - - - - - - - - - - - -`; - -exports[`LocationMap component renders named locations that have missing geo data 1`] = ` - - - - - - - - - - - - - - - -`; - -exports[`LocationMap component shows warning if geo information is missing 1`] = ` - - - - - - - - - - - - - - - -`; diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap deleted file mode 100644 index f2a390792918a..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap +++ /dev/null @@ -1,682 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`LocationStatusTags component renders properly against props 1`] = ` - - - - - - - - Berlin - - - - - - 1 Mon ago - - - - - - - - - - Berlin - - - - - - 1 Mon ago - - - - - - - - Islamabad - - - - - - 1 Mon ago - - - - - - -`; - -exports[`LocationStatusTags component renders when all locations are down 1`] = ` -.c3 { - display: inline-block; - margin-left: 4px; -} - -.c2 { - font-weight: 600; -} - -.c1 { - margin-bottom: 5px; - white-space: nowrap; -} - -.c0 { - max-height: 229px; - overflow: hidden; - margin-top: auto; -} - -@media (max-width:1042px) { - .c1 { - display: inline-block; - margin-right: 16px; - } -} - -
- -
- - - -
-
- Islamabad -
-
-
-
-
- -
-
- 5s ago -
-
-
-
-
- - - -
-
- Berlin -
-
-
-
-
- -
-
- 5m ago -
-
-
-
-
- -
-`; - -exports[`LocationStatusTags component renders when all locations are up 1`] = ` -.c3 { - display: inline-block; - margin-left: 4px; -} - -.c2 { - font-weight: 600; -} - -.c1 { - margin-bottom: 5px; - white-space: nowrap; -} - -.c0 { - max-height: 229px; - overflow: hidden; - margin-top: auto; -} - -@media (max-width:1042px) { - .c1 { - display: inline-block; - margin-right: 16px; - } -} - -
- - -
- - - -
-
- Berlin -
-
-
-
-
- -
-
- 5d ago -
-
-
-
-
- - - -
-
- Islamabad -
-
-
-
-
- -
-
- 5s ago -
-
-
-
-
-
-`; - -exports[`LocationStatusTags component renders when there are many location 1`] = ` -Array [ - .c3 { - display: inline-block; - margin-left: 4px; -} - -.c2 { - font-weight: 600; -} - -.c1 { - margin-bottom: 5px; - white-space: nowrap; -} - -.c0 { - max-height: 229px; - overflow: hidden; - margin-top: auto; -} - -@media (max-width:1042px) { - .c1 { - display: inline-block; - margin-right: 16px; - } -} - -
- -
- - - -
-
- Islamabad -
-
-
-
-
- -
-
- 5s ago -
-
-
-
-
- - - -
-
- Berlin -
-
-
-
-
- -
-
- 5m ago -
-
-
-
-
- - - -
-
- st-paul -
-
-
-
-
- -
-
- 5h ago -
-
-
-
-
- - - -
-
- Tokyo -
-
-
-
-
- -
-
- 5d ago -
-
-
-
-
- - - -
-
- New York -
-
-
-
-
- -
-
- 1 Mon ago -
-
-
-
-
- - - -
-
- Toronto -
-
-
-
-
- -
-
- 5 Mon ago -
-
-
-
-
- - - -
-
- Sydney -
-
-
-
-
- -
-
- 5 Yr ago -
-
-
-
-
- - - -
-
- Paris -
-
-
-
-
- -
-
- 5 Yr ago -
-
-
-
-
- -
, - .c0 { - padding-left: 18px; -} - -@media (max-width:1042px) { - -} - -
-
-
-

- 1 Others ... -

-
-
-
, -] -`; diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/location_map.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/location_map.tsx deleted file mode 100644 index 916f1cbb63e53..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/location_map.tsx +++ /dev/null @@ -1,95 +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 styled from 'styled-components'; -import { EuiFlexGroup, EuiFlexItem, EuiErrorBoundary, EuiHideFor } from '@elastic/eui'; -import { LocationStatusTags } from './location_status_tags'; -import { EmbeddedMap, LocationPoint } from './embeddables/embedded_map'; -import { MonitorLocations, MonitorLocation } from '../../../../common/runtime_types'; -import { UNNAMED_LOCATION } from '../../../../common/constants'; -import { LocationMissingWarning } from './location_missing'; - -// These height/width values are used to make sure map is in center of panel -// And to make sure, it doesn't take too much space -const MapPanel = styled.div` - height: 240px; - width: 520px; - @media (min-width: 1300px) { - margin-right: 20px; - } - @media (max-width: 574px) { - height: 250px; - width: 100%; - margin-right: 0; - } -`; - -const EuiFlexItemTags = styled(EuiFlexItem)` - padding-top: 5px; - @media (max-width: 1042px) { - flex-basis: 80% !important; - flex-grow: 0 !important; - order: 1; - } -`; - -const FlexGroup = styled(EuiFlexGroup)` - @media (max-width: 850px) { - justify-content: center; - } -`; - -interface LocationMapProps { - monitorLocations: MonitorLocations; -} - -export const LocationMap = ({ monitorLocations }: LocationMapProps) => { - const upPoints: LocationPoint[] = []; - const downPoints: LocationPoint[] = []; - - let isGeoInfoMissing = false; - - if (monitorLocations?.locations) { - monitorLocations.locations.forEach((item: MonitorLocation) => { - if (item.geo?.name === UNNAMED_LOCATION || !item.geo?.location) { - isGeoInfoMissing = true; - } else if ( - item.geo?.name !== UNNAMED_LOCATION && - !!item.geo.location.lat && - !!item.geo.location.lon - ) { - // TypeScript doesn't infer that the above checks in this block's condition - // ensure that lat and lon are defined when we try to pass the location object directly, - // but if we destructure the values it does. Improvement to this block is welcome. - const { lat, lon } = item.geo.location; - if (item?.summary?.down === 0) { - upPoints.push({ lat, lon }); - } else { - downPoints.push({ lat, lon }); - } - } - }); - } - - return ( - - - - - - - - {isGeoInfoMissing && } - - - - - - - - ); -}; diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/location_status_tags.tsx b/x-pack/plugins/uptime/public/components/monitor/location_map/location_status_tags.tsx deleted file mode 100644 index db84fd5e2ca42..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/location_status_tags.tsx +++ /dev/null @@ -1,130 +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, { useContext } from 'react'; -import moment from 'moment'; -import styled from 'styled-components'; -import { EuiBadge, EuiText } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { UptimeThemeContext } from '../../../contexts'; -import { MonitorLocation } from '../../../../common/runtime_types'; -import { SHORT_TIMESPAN_LOCALE, SHORT_TS_LOCALE } from '../../../../common/constants'; - -const TimeStampSpan = styled.span` - display: inline-block; - margin-left: 4px; -`; - -const TextStyle = styled.div` - font-weight: 600; -`; - -const BadgeItem = styled.div` - margin-bottom: 5px; - white-space: nowrap; - @media (max-width: 1042px) { - display: inline-block; - margin-right: 16px; - } -`; - -// Set height so that it remains within panel, enough height to display 7 locations tags -const TagContainer = styled.div` - max-height: 229px; - overflow: hidden; - margin-top: auto; -`; - -const OtherLocationsDiv = styled.div` - padding-left: 18px; -`; - -interface Props { - locations: MonitorLocation[]; -} - -interface StatusTag { - label: string; - timestamp: number; -} - -export const LocationStatusTags = ({ locations }: Props) => { - const { - colors: { gray, danger }, - } = useContext(UptimeThemeContext); - - const upLocations: StatusTag[] = []; - const downLocations: StatusTag[] = []; - - locations.forEach((item: any) => { - if (item.summary.down === 0) { - upLocations.push({ label: item.geo.name, timestamp: new Date(item.timestamp).valueOf() }); - } else { - downLocations.push({ label: item.geo.name, timestamp: new Date(item.timestamp).valueOf() }); - } - }); - - // Sort lexicographically by label - upLocations.sort((a, b) => { - return a.label > b.label ? 1 : b.label > a.label ? -1 : 0; - }); - - const tagLabel = (item: StatusTag, ind: number, color: string) => { - return ( - - - - {item.label} - - - - {moment(item.timestamp).fromNow()} - - - ); - }; - - const prevLocal: string = moment.locale() ?? 'en'; - - const renderTags = () => { - const shortLocale = moment.locale(SHORT_TS_LOCALE) === SHORT_TS_LOCALE; - if (!shortLocale) { - moment.defineLocale(SHORT_TS_LOCALE, SHORT_TIMESPAN_LOCALE); - } - - const tags = ( - - {downLocations.map((item, ind) => tagLabel(item, ind, danger))} - {upLocations.map((item, ind) => tagLabel(item, ind, gray))} - - ); - - // Need to reset locale so it doesn't effect other parts of the app - moment.locale(prevLocal); - return tags; - }; - - return ( - <> - {renderTags()} - {locations.length > 7 && ( - - -

- -

-
-
- )} - - ); -}; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap deleted file mode 100644 index ff63b3695fb8d..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap +++ /dev/null @@ -1,55 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`MonitorStatusBar component renders duration in ms, not us 1`] = ` -
-
-
-

- Up in 2 Locations -

-
-
- -
- -

- id1 -

-
-
-
-
-
-`; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx deleted file mode 100644 index 73b58e8a33f6b..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/ssl_certificate.tsx +++ /dev/null @@ -1,100 +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 moment from 'moment'; -import { i18n } from '@kbn/i18n'; -import { Link } from 'react-router-dom'; -import { EuiSpacer, EuiText, EuiBadge, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { FormattedMessage } from '@kbn/i18n/react'; -import { Tls } from '../../../../../common/runtime_types'; -import { useCertStatus } from '../../../../hooks'; -import { CERT_STATUS, CERTIFICATES_ROUTE } from '../../../../../common/constants'; - -interface Props { - /** - * TLS information coming from monitor in ES heartbeat index - */ - tls: Tls | null | undefined; -} - -export const MonitorSSLCertificate = ({ tls }: Props) => { - const certStatus = useCertStatus(tls?.not_after); - - const isExpiringSoon = certStatus === CERT_STATUS.EXPIRING_SOON; - - const isExpired = certStatus === CERT_STATUS.EXPIRED; - - const relativeDate = moment(tls?.not_after).fromNow(); - - return certStatus ? ( - <> - - {i18n.translate('xpack.uptime.monitorStatusBar.sslCertificate.title', { - defaultMessage: 'Certificate:', - })} - - - - - - {isExpired ? ( - {relativeDate}, - }} - /> - ) : ( - - {relativeDate} - - ), - }} - /> - )} - - - - - - {i18n.translate('xpack.uptime.monitorStatusBar.sslCertificate.overview', { - defaultMessage: 'Certificate overview', - })} - - - - - - ) : null; -}; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar.tsx b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar.tsx deleted file mode 100644 index 36159dc29eccd..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar.tsx +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -import React from 'react'; -import { - EuiLink, - EuiTitle, - EuiTextColor, - EuiSpacer, - EuiText, - EuiFlexGroup, - EuiFlexItem, -} from '@elastic/eui'; -import { MonitorSSLCertificate } from './ssl_certificate'; -import * as labels from './translations'; -import { StatusByLocations } from './status_by_location'; -import { Ping } from '../../../../../common/runtime_types'; -import { MonitorLocations } from '../../../../../common/runtime_types'; - -interface MonitorStatusBarProps { - monitorId: string; - monitorStatus: Ping | null; - monitorLocations: MonitorLocations; -} - -export const MonitorStatusBarComponent: React.FC = ({ - monitorId, - monitorStatus, - monitorLocations, -}) => { - const full = monitorStatus?.url?.full ?? ''; - - return ( - - - - - - - - {full} - - - - - - -

{monitorId}

-
-
-
- - - - -
- ); -}; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/translations.ts b/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/translations.ts deleted file mode 100644 index f60a1ceeaafb8..0000000000000 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/translations.ts +++ /dev/null @@ -1,50 +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'; - -export const healthStatusMessageAriaLabel = i18n.translate( - 'xpack.uptime.monitorStatusBar.healthStatusMessageAriaLabel', - { - defaultMessage: 'Monitor status', - } -); - -export const upLabel = i18n.translate('xpack.uptime.monitorStatusBar.healthStatusMessage.upLabel', { - defaultMessage: 'Up', -}); - -export const downLabel = i18n.translate( - 'xpack.uptime.monitorStatusBar.healthStatusMessage.downLabel', - { - defaultMessage: 'Down', - } -); - -export const monitorUrlLinkAriaLabel = i18n.translate( - 'xpack.uptime.monitorStatusBar.monitorUrlLinkAriaLabel', - { - defaultMessage: 'Monitor URL link', - } -); - -export const durationTextAriaLabel = i18n.translate( - 'xpack.uptime.monitorStatusBar.durationTextAriaLabel', - { - defaultMessage: 'Monitor duration in milliseconds', - } -); - -export const timestampFromNowTextAriaLabel = i18n.translate( - 'xpack.uptime.monitorStatusBar.timestampFromNowTextAriaLabel', - { - defaultMessage: 'Time since last check', - } -); - -export const loadingMessage = i18n.translate('xpack.uptime.monitorStatusBar.loadingMessage', { - defaultMessage: 'Loading…', -}); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap new file mode 100644 index 0000000000000..d53f338b60aed --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/__snapshots__/monitor_status.bar.test.tsx.snap @@ -0,0 +1,73 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MonitorStatusBar component renders 1`] = ` +Array [ +
+
+

+ Up in 2 Locations +

+
+
, +
, + .c0.c0.c0 { + width: 35%; +} + +.c1.c1.c1 { + width: 65%; + overflow-wrap: anywhere; +} + +
+
+ Overall availability +
+
+ 0.00 % +
+
+ Url +
+
+ + +
+ +
+
+ Monitor ID +
+
+
, +] +`; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap similarity index 61% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap index 628e1d576181e..5b63a09d4f7c4 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/__snapshots__/ssl_certificate.test.tsx.snap @@ -2,61 +2,91 @@ exports[`SSL Certificate component renders 1`] = ` Array [ -
- Certificate: -
, + TLS Certificate + ,
, -
-
-
- Expires - - - - in 2 months - - - -
-
- , + + + , ] `; -exports[`SSL Certificate component renders null if invalid date 1`] = `null`; +exports[`SSL Certificate component renders null if invalid date 1`] = ` +Array [ + .c0.c0.c0 { + width: 35%; +} + +
+ TLS Certificate +
, +
, + .c0.c0.c0 { + width: 65%; + overflow-wrap: anywhere; +} + +
+ + + -- + + +
, +] +`; exports[`SSL Certificate component shallow renders 1`] = ` { let monitorStatus: Ping; @@ -49,18 +50,21 @@ describe('MonitorStatusBar component', () => { const spy = jest.spyOn(redux, 'useDispatch'); spy.mockReturnValue(jest.fn()); - const spy1 = jest.spyOn(redux, 'useSelector'); - spy1.mockReturnValue(true); + jest.spyOn(redux, 'useSelector').mockImplementation((fn, d) => { + if (fn.name === ' monitorStatusSelector') { + return monitorStatus; + } else { + return monitorLocations; + } + }); }); - it('renders duration in ms, not us', () => { - const component = renderWithIntl( - - ); + it('renders', () => { + const history = createMemoryHistory({ + initialEntries: ['/aWQx/'], + }); + history.location.key = 'test'; + const component = renderWithRouter(, history); expect(component).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/ssl_certificate.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/ssl_certificate.test.tsx similarity index 75% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/ssl_certificate.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/__test__/ssl_certificate.test.tsx index e8ffc3bf26c42..a4b360ea690d0 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/ssl_certificate.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/ssl_certificate.test.tsx @@ -6,9 +6,9 @@ import React from 'react'; import moment from 'moment'; -import { EuiBadge } from '@elastic/eui'; +import { EuiIcon } from '@elastic/eui'; import { Tls } from '../../../../../common/runtime_types'; -import { MonitorSSLCertificate } from '../monitor_status_bar'; +import { MonitorSSLCertificate } from '../status_bar'; import * as redux from 'react-redux'; import { mountWithRouter, renderWithRouter, shallowWithRouter } from '../../../../lib'; import { DYNAMIC_SETTINGS_DEFAULTS } from '../../../../../common/constants'; @@ -58,14 +58,12 @@ describe('SSL Certificate component', () => { }; const component = mountWithRouter(); - const badgeComponent = component.find(EuiBadge); + const lockIcon = component.find(EuiIcon); - expect(badgeComponent.props().color).toBe('warning'); + expect(lockIcon.props().color).toBe('warning'); - const badgeComponentText = component.find('.euiBadge__text'); - expect(badgeComponentText.text()).toBe(moment(dateIn5Days).fromNow()); - - expect(badgeComponent.find('span.euiBadge--warning')).toBeTruthy(); + const componentText = component.find('h4'); + expect(componentText.text()).toBe('Expires soon ' + moment(dateIn5Days).fromNow()); }); it('does not render the expiration date with a warning state if expiry date is greater than a month', () => { @@ -75,12 +73,10 @@ describe('SSL Certificate component', () => { }; const component = mountWithRouter(); - const badgeComponent = component.find(EuiBadge); - expect(badgeComponent.props().color).toBe('default'); - - const badgeComponentText = component.find('.euiBadge__text'); - expect(badgeComponentText.text()).toBe(moment(dateIn40Days).fromNow()); + const lockIcon = component.find(EuiIcon); + expect(lockIcon.props().color).toBe('success'); - expect(badgeComponent.find('span.euiBadge--warning')).toHaveLength(0); + const componentText = component.find('h4'); + expect(componentText.text()).toBe('Expires ' + moment(dateIn40Days).fromNow()); }); }); diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/status_by_location.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/status_by_location.test.tsx similarity index 77% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/status_by_location.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/__test__/status_by_location.test.tsx index b2619825311d7..b171a8bedb8a7 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/__test__/status_by_location.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/__test__/status_by_location.test.tsx @@ -17,10 +17,16 @@ describe('StatusByLocation component', () => { { summary: { up: 4, down: 0 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, { summary: { up: 4, down: 0 }, geo: { name: 'st-paul', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, ]; const component = shallowWithIntl(); @@ -32,10 +38,16 @@ describe('StatusByLocation component', () => { { summary: { up: 4, down: 0 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, { summary: { up: 4, down: 0 }, geo: { name: 'st-paul', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, ]; const component = renderWithIntl(); @@ -47,6 +59,9 @@ describe('StatusByLocation component', () => { { summary: { up: 4, down: 0 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, ]; const component = renderWithIntl(); @@ -58,6 +73,9 @@ describe('StatusByLocation component', () => { { summary: { up: 0, down: 4 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, ]; const component = renderWithIntl(); @@ -69,10 +87,16 @@ describe('StatusByLocation component', () => { { summary: { up: 0, down: 4 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, { summary: { up: 0, down: 4 }, geo: { name: 'st-paul', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, ]; const component = renderWithIntl(); @@ -84,10 +108,16 @@ describe('StatusByLocation component', () => { { summary: { up: 0, down: 4 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, { summary: { up: 4, down: 0 }, geo: { name: 'st-paul', location: { lat: '52.487448', lon: ' 13.394798' } }, + up_history: 4, + down_history: 0, + timestamp: '2020-01-13T22:50:06.536Z', }, ]; const component = renderWithIntl(); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/availability_reporting.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/availability_reporting.test.tsx.snap new file mode 100644 index 0000000000000..9496274a69171 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/availability_reporting.test.tsx.snap @@ -0,0 +1,381 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`AvailabilityReporting component renders correctly against snapshot 1`] = ` +Array [ + @media (max-width:1042px) { + +} + +
, + .c0 { + white-space: nowrap; + display: inline-block; +} + +@media (max-width:1042px) { + .c0 { + display: inline-block; + margin-right: 16px; + } +} + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Location + +
+
+
+ + Availability + +
+
+
+ + Last check + +
+
+
+ Location +
+
+
+ + + +
+

+ au-heartbeat +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 36m ago + +
+
+
+ Location +
+
+
+ + + +
+

+ nyc-heartbeat +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 36m ago + +
+
+
+ Location +
+
+
+ + + +
+

+ spa-heartbeat +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 36m ago + +
+
+
+
, +] +`; + +exports[`AvailabilityReporting component shallow renders correctly against snapshot 1`] = ` + + + + +`; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/location_status_tags.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/location_status_tags.test.tsx.snap new file mode 100644 index 0000000000000..05e0b50a86f35 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/location_status_tags.test.tsx.snap @@ -0,0 +1,1085 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocationStatusTags component renders properly against props 1`] = ` + + + + + +`; + +exports[`LocationStatusTags component renders when all locations are down 1`] = ` +.c1 { + white-space: nowrap; + display: inline-block; +} + +.c0 { + max-height: 246px; + overflow: hidden; +} + +@media (max-width:1042px) { + .c1 { + display: inline-block; + margin-right: 16px; + } +} + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + +
+
+
+ + Location + +
+
+
+ + Availability + +
+
+
+ + Last check + +
+
+
+ Location +
+
+
+ + + +
+

+ Berlin +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 5m ago + +
+
+
+ Location +
+
+
+ + + +
+

+ Islamabad +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 5s ago + +
+
+
+
+
+`; + +exports[`LocationStatusTags component renders when all locations are up 1`] = ` +.c1 { + white-space: nowrap; + display: inline-block; +} + +.c0 { + max-height: 246px; + overflow: hidden; +} + +@media (max-width:1042px) { + .c1 { + display: inline-block; + margin-right: 16px; + } +} + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + +
+
+
+ + Location + +
+
+
+ + Availability + +
+
+
+ + Last check + +
+
+
+ Location +
+
+
+ + + +
+

+ Berlin +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 5d ago + +
+
+
+ Location +
+
+
+ + + +
+

+ Islamabad +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 5s ago + +
+
+
+
+
+`; + +exports[`LocationStatusTags component renders when there are many location 1`] = ` +.c1 { + white-space: nowrap; + display: inline-block; +} + +.c0 { + max-height: 246px; + overflow: hidden; +} + +@media (max-width:1042px) { + .c1 { + display: inline-block; + margin-right: 16px; + } +} + +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + Location + +
+
+
+ + Availability + +
+
+
+ + Last check + +
+
+
+ Location +
+
+
+ + + +
+

+ Berlin +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 5m ago + +
+
+
+ Location +
+
+
+ + + +
+

+ Islamabad +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 5s ago + +
+
+
+ Location +
+
+
+ + + +
+

+ New York +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 1 Mon ago + +
+
+
+ Location +
+
+
+ + + +
+

+ Paris +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 5 Yr ago + +
+
+
+ Location +
+
+
+ + + +
+

+ Sydney +

+
+
+
+
+
+
+
+
+ Availability +
+
+ + 100.00 % + +
+
+
+ Last check +
+
+ + 5 Yr ago + +
+
+
+
+
+
+
+
+
+ + + + +
+
+
+
+
+
+`; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/tag_label.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/tag_label.test.tsx.snap new file mode 100644 index 0000000000000..3381efa62286b --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/__snapshots__/tag_label.test.tsx.snap @@ -0,0 +1,56 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`TagLabel component renders correctly against snapshot 1`] = ` +.c0 { + white-space: nowrap; + display: inline-block; +} + +@media (max-width:1042px) { + .c0 { + display: inline-block; + margin-right: 16px; + } +} + +
+ + + +
+

+ US-East +

+
+
+
+
+
+`; + +exports[`TagLabel component shallow render correctly against snapshot 1`] = ` + + + +

+ US-East +

+
+
+
+`; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/availability_reporting.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/availability_reporting.test.tsx new file mode 100644 index 0000000000000..de9f6b0d3b30f --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/availability_reporting.test.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 from 'react'; +import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { AvailabilityReporting } from '../availability_reporting'; +import { StatusTag } from '../location_status_tags'; + +describe('AvailabilityReporting component', () => { + let allLocations: StatusTag[]; + + beforeEach(() => { + allLocations = [ + { + label: 'au-heartbeat', + timestamp: '36m ago', + color: '#d3dae6', + availability: 100, + }, + { + label: 'nyc-heartbeat', + timestamp: '36m ago', + color: '#d3dae6', + availability: 100, + }, + { label: 'spa-heartbeat', timestamp: '36m ago', color: '#d3dae6', availability: 100 }, + ]; + }); + + it('shallow renders correctly against snapshot', () => { + const component = shallowWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('renders correctly against snapshot', () => { + const component = renderWithIntl(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_status_tags.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/location_status_tags.test.tsx similarity index 84% rename from x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_status_tags.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/location_status_tags.test.tsx index 28b4482401793..bfeaa6085e998 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_status_tags.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/location_status_tags.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import moment from 'moment'; import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; -import { MonitorLocation } from '../../../../../common/runtime_types/monitor'; +import { MonitorLocation } from '../../../../../../common/runtime_types/monitor'; import { LocationStatusTags } from '../index'; describe('LocationStatusTags component', () => { @@ -19,16 +19,22 @@ describe('LocationStatusTags component', () => { summary: { up: 4, down: 0 }, geo: { name: 'Islamabad', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'w').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 4, down: 0 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'w').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 2 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'w').toISOString(), + up_history: 4, + down_history: 0, }, ]; const component = shallowWithIntl(); @@ -41,41 +47,57 @@ describe('LocationStatusTags component', () => { summary: { up: 0, down: 1 }, geo: { name: 'Islamabad', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 's').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 1 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'm').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 1 }, geo: { name: 'st-paul', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'h').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 1 }, geo: { name: 'Tokyo', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'd').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 1 }, geo: { name: 'New York', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'w').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 1 }, geo: { name: 'Toronto', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'M').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 1 }, geo: { name: 'Sydney', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'y').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 1 }, geo: { name: 'Paris', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'y').toISOString(), + up_history: 4, + down_history: 0, }, ]; const component = renderWithIntl(); @@ -88,11 +110,15 @@ describe('LocationStatusTags component', () => { summary: { up: 4, down: 0 }, geo: { name: 'Islamabad', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 's').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 4, down: 0 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'd').toISOString(), + up_history: 4, + down_history: 0, }, ]; const component = renderWithIntl(); @@ -105,11 +131,15 @@ describe('LocationStatusTags component', () => { summary: { up: 0, down: 2 }, geo: { name: 'Islamabad', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 's').toISOString(), + up_history: 4, + down_history: 0, }, { summary: { up: 0, down: 2 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: moment().subtract('5', 'm').toISOString(), + up_history: 4, + down_history: 0, }, ]; const component = renderWithIntl(); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/tag_label.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/tag_label.test.tsx new file mode 100644 index 0000000000000..3560784122298 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/__tests__/tag_label.test.tsx @@ -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 React from 'react'; +import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { TagLabel } from '../tag_label'; + +describe('TagLabel component', () => { + it('shallow render correctly against snapshot', () => { + const component = shallowWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('renders correctly against snapshot', () => { + const component = renderWithIntl(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/availability_reporting.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/availability_reporting.tsx new file mode 100644 index 0000000000000..8fed5db5e0271 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/availability_reporting.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, { useState } from 'react'; +import { EuiBasicTable, EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { Pagination } from '@elastic/eui/src/components/basic_table/pagination_bar'; +import { StatusTag } from './location_status_tags'; +import { TagLabel } from './tag_label'; +import { AvailabilityLabel, LastCheckLabel, LocationLabel } from '../translations'; + +interface Props { + allLocations: StatusTag[]; +} + +export const formatAvailabilityValue = (val: number) => { + const result = Math.round(val * 100) / 100; + return result.toFixed(2); +}; + +export const AvailabilityReporting: React.FC = ({ allLocations }) => { + const [pageIndex, setPageIndex] = useState(0); + + const cols = [ + { + field: 'label', + name: LocationLabel, + truncateText: true, + render: (val: string, item: StatusTag) => { + return ; + }, + }, + { + field: 'availability', + name: AvailabilityLabel, + align: 'right' as const, + render: (val: number) => { + return ( + + + + ); + }, + }, + { + name: LastCheckLabel, + field: 'timestamp', + align: 'right' as const, + }, + ]; + const pageSize = 5; + + const pagination: Pagination = { + pageIndex, + pageSize, + totalItemCount: allLocations.length, + hidePerPageOptions: true, + }; + + const onTableChange = ({ page }: any) => { + setPageIndex(page.index); + }; + + const paginationProps = allLocations.length > pageSize ? { pagination } : {}; + + return ( + <> + + + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/index.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/index.ts new file mode 100644 index 0000000000000..fb42a162522a8 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { AvailabilityReporting } from './availability_reporting'; +export { LocationStatusTags } from './location_status_tags'; +export { TagLabel } from './tag_label'; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/location_status_tags.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/location_status_tags.tsx new file mode 100644 index 0000000000000..6096499213a10 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/location_status_tags.tsx @@ -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. + */ + +import React, { useContext } from 'react'; +import moment from 'moment'; +import styled from 'styled-components'; +import { UptimeThemeContext } from '../../../../contexts'; +import { MonitorLocation } from '../../../../../common/runtime_types'; +import { SHORT_TIMESPAN_LOCALE, SHORT_TS_LOCALE } from '../../../../../common/constants'; +import { AvailabilityReporting } from '../index'; + +// Set height so that it remains within panel, enough height to display 7 locations tags +const TagContainer = styled.div` + max-height: 246px; + overflow: hidden; +`; + +interface Props { + locations: MonitorLocation[]; +} + +export interface StatusTag { + label: string; + timestamp: string; + color: string; + availability: number; +} + +export const LocationStatusTags = ({ locations }: Props) => { + const { + colors: { gray, danger }, + } = useContext(UptimeThemeContext); + + const allLocations: StatusTag[] = []; + const prevLocal: string = moment.locale() ?? 'en'; + + const shortLocale = moment.locale(SHORT_TS_LOCALE) === SHORT_TS_LOCALE; + if (!shortLocale) { + moment.defineLocale(SHORT_TS_LOCALE, SHORT_TIMESPAN_LOCALE); + } + + locations.forEach((item: MonitorLocation) => { + allLocations.push({ + label: item.geo.name!, + timestamp: moment(new Date(item.timestamp).valueOf()).fromNow(), + color: item.summary.down === 0 ? gray : danger, + availability: (item.up_history / (item.up_history + item.down_history)) * 100, + }); + }); + + // Need to reset locale so it doesn't effect other parts of the app + moment.locale(prevLocal); + + // Sort lexicographically by label + allLocations.sort((a, b) => { + return a.label > b.label ? 1 : b.label > a.label ? -1 : 0; + }); + + if (allLocations.length === 0) { + return null; + } + + return ( + <> + + + + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/tag_label.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/tag_label.tsx new file mode 100644 index 0000000000000..dbd73fc7d440b --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/availability_reporting/tag_label.tsx @@ -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 React from 'react'; +import styled from 'styled-components'; +import { EuiBadge, EuiText } from '@elastic/eui'; + +const BadgeItem = styled.div` + white-space: nowrap; + display: inline-block; + @media (max-width: 1042px) { + display: inline-block; + margin-right: 16px; + } +`; + +interface Props { + color: string; + label: string; +} + +export const TagLabel: React.FC = ({ color, label }) => { + return ( + + + +

{label}

+
+
+
+ ); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/index.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/index.ts similarity index 63% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/index.ts rename to x-pack/plugins/uptime/public/components/monitor/status_details/index.ts index e95f14472e9e8..ae3a07d231da3 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/index.ts +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/index.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -export { MonitorStatusBarComponent } from './monitor_status_bar'; export { MonitorStatusDetailsComponent } from './status_details'; -export { StatusByLocations } from './monitor_status_bar/status_by_location'; +export { StatusByLocations } from './status_bar/status_by_location'; export { MonitorStatusDetails } from './status_details_container'; -export { MonitorStatusBar } from './monitor_status_bar/status_bar_container'; +export { MonitorStatusBar } from './status_bar/status_bar'; +export { AvailabilityReporting } from './availability_reporting/availability_reporting'; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/__tests__/__snapshots__/location_availability.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/__tests__/__snapshots__/location_availability.test.tsx.snap new file mode 100644 index 0000000000000..94cbeb49a32cf --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/__tests__/__snapshots__/location_availability.test.tsx.snap @@ -0,0 +1,234 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocationAvailability component doesnt shows warning if geo is provided 1`] = ` + + + + + + + + + + + + + +`; + +exports[`LocationAvailability component renders correctly against snapshot 1`] = ` + + + + +

+ Monitoring from +

+
+
+ + + +
+ + + + + +
+`; + +exports[`LocationAvailability component renders named locations that have missing geo data 1`] = ` + + + + + + + + + + + + + + + +`; + +exports[`LocationAvailability component shows warning if geo information is missing 1`] = ` + + + + + + + + + + + + + + + +`; diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_map.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/__tests__/location_availability.test.tsx similarity index 64% rename from x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_map.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/__tests__/location_availability.test.tsx index 1913e677dd674..d00cb1f24def8 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_map.test.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/__tests__/location_availability.test.tsx @@ -6,59 +6,85 @@ import React from 'react'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; -import { LocationMap } from '../location_map'; -import { MonitorLocations } from '../../../../../common/runtime_types'; -import { LocationMissingWarning } from '../location_missing'; +import { LocationAvailability } from '../location_availability'; +import { MonitorLocations } from '../../../../../../common/runtime_types'; +import { LocationMissingWarning } from '../../location_map/location_missing'; // Note For shallow test, we need absolute time strings -describe('LocationMap component', () => { +describe('LocationAvailability component', () => { let monitorLocations: MonitorLocations; + let localStorageMock: any; + + let selectedView = 'list'; beforeEach(() => { + localStorageMock = { + getItem: jest.fn().mockImplementation(() => selectedView), + setItem: jest.fn(), + }; + + // @ts-ignore replacing a call to localStorage we use for monitor list size + global.localStorage = localStorageMock; + monitorLocations = { monitorId: 'wapo', + up_history: 12, + down_history: 0, locations: [ { summary: { up: 4, down: 0 }, geo: { name: 'New York', location: { lat: '40.730610', lon: ' -73.935242' } }, timestamp: '2020-01-13T22:50:06.536Z', + up_history: 4, + down_history: 0, }, { summary: { up: 4, down: 0 }, geo: { name: 'Tokyo', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: '2020-01-13T22:50:04.354Z', + up_history: 4, + down_history: 0, }, { summary: { up: 4, down: 0 }, geo: { name: 'Unnamed-location' }, timestamp: '2020-01-13T22:50:02.753Z', + up_history: 4, + down_history: 0, }, ], }; }); it('renders correctly against snapshot', () => { - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component).toMatchSnapshot(); }); it('shows warning if geo information is missing', () => { + selectedView = 'map'; monitorLocations = { monitorId: 'wapo', + up_history: 8, + down_history: 0, locations: [ { summary: { up: 4, down: 0 }, geo: { name: 'Tokyo', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: '2020-01-13T22:50:04.354Z', + up_history: 4, + down_history: 0, }, { summary: { up: 4, down: 0 }, geo: { name: 'Unnamed-location' }, timestamp: '2020-01-13T22:50:02.753Z', + up_history: 4, + down_history: 0, }, ], }; - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component).toMatchSnapshot(); const warningComponent = component.find(LocationMissingWarning); @@ -68,20 +94,26 @@ describe('LocationMap component', () => { it('doesnt shows warning if geo is provided', () => { monitorLocations = { monitorId: 'wapo', + up_history: 8, + down_history: 0, locations: [ { summary: { up: 4, down: 0 }, geo: { name: 'New York', location: { lat: '40.730610', lon: ' -73.935242' } }, timestamp: '2020-01-13T22:50:06.536Z', + up_history: 4, + down_history: 0, }, { summary: { up: 4, down: 0 }, geo: { name: 'Tokyo', location: { lat: '52.487448', lon: ' 13.394798' } }, timestamp: '2020-01-13T22:50:04.354Z', + up_history: 4, + down_history: 0, }, ], }; - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component).toMatchSnapshot(); const warningComponent = component.find(LocationMissingWarning); @@ -91,16 +123,20 @@ describe('LocationMap component', () => { it('renders named locations that have missing geo data', () => { monitorLocations = { monitorId: 'wapo', + up_history: 4, + down_history: 0, locations: [ { summary: { up: 4, down: 0 }, geo: { name: 'New York', location: undefined }, timestamp: '2020-01-13T22:50:06.536Z', + up_history: 4, + down_history: 0, }, ], }; - const component = shallowWithIntl(); + const component = shallowWithIntl(); expect(component).toMatchSnapshot(); }); }); diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/location_availability.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/location_availability.tsx new file mode 100644 index 0000000000000..89b969fdcf691 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/location_availability.tsx @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React, { useState } from 'react'; +import styled from 'styled-components'; +import { EuiFlexGroup, EuiFlexItem, EuiErrorBoundary, EuiTitle } from '@elastic/eui'; +import { LocationStatusTags } from '../availability_reporting'; +import { LocationPoint } from '../location_map/embeddables/embedded_map'; +import { MonitorLocations, MonitorLocation } from '../../../../../common/runtime_types'; +import { UNNAMED_LOCATION } from '../../../../../common/constants'; +import { LocationMissingWarning } from '../location_map/location_missing'; +import { useSelectedView } from './use_selected_view'; +import { LocationMap } from '../location_map'; +import { MonitoringFrom } from '../translations'; +import { ToggleViewBtn } from './toggle_view_btn'; + +const EuiFlexItemTags = styled(EuiFlexItem)` + width: 350px; + @media (max-width: 1042px) { + width: 100%; + } +`; + +interface LocationMapProps { + monitorLocations: MonitorLocations; +} + +export const LocationAvailability = ({ monitorLocations }: LocationMapProps) => { + const upPoints: LocationPoint[] = []; + const downPoints: LocationPoint[] = []; + + let isAnyGeoInfoMissing = false; + + if (monitorLocations?.locations) { + monitorLocations.locations.forEach(({ geo, summary }: MonitorLocation) => { + if (geo?.name === UNNAMED_LOCATION || !geo?.location) { + isAnyGeoInfoMissing = true; + } else if (!!geo.location.lat && !!geo.location.lon) { + if (summary?.down === 0) { + upPoints.push(geo as LocationPoint); + } else { + downPoints.push(geo as LocationPoint); + } + } + }); + } + const { selectedView: initialView } = useSelectedView(); + + const [selectedView, setSelectedView] = useState(initialView); + + return ( + + + {selectedView === 'list' && ( + + +

{MonitoringFrom}

+
+
+ )} + {selectedView === 'map' && ( + {isAnyGeoInfoMissing && } + )} + + { + setSelectedView(val); + }} + /> + +
+ + + {selectedView === 'list' && ( + + + + )} + {selectedView === 'map' && ( + + + + )} + +
+ ); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/toggle_view_btn.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/toggle_view_btn.tsx new file mode 100644 index 0000000000000..dfce583945cce --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/toggle_view_btn.tsx @@ -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 * as React from 'react'; +import styled from 'styled-components'; +import { EuiButtonGroup } from '@elastic/eui'; +import { useSelectedView } from './use_selected_view'; +import { ChangeToListView, ChangeToMapView } from '../translations'; + +const ToggleViewButtons = styled.span` + margin-left: auto; +`; + +interface Props { + onChange: (val: string) => void; +} + +export const ToggleViewBtn = ({ onChange }: Props) => { + const toggleButtons = [ + { + id: `listBtn`, + label: ChangeToMapView, + name: 'listView', + iconType: 'list', + 'data-test-subj': 'uptimeMonitorToggleListBtn', + 'aria-label': ChangeToMapView, + }, + { + id: `mapBtn`, + label: ChangeToListView, + name: 'mapView', + iconType: 'mapMarker', + 'data-test-subj': 'uptimeMonitorToggleMapBtn', + 'aria-label': ChangeToListView, + }, + ]; + + const { selectedView, setSelectedView } = useSelectedView(); + + const onChangeView = (optionId: string) => { + const currView = optionId === 'listBtn' ? 'list' : 'map'; + setSelectedView(currView); + onChange(currView); + }; + + return ( + + onChangeView(id)} + type="multi" + isIconOnly + style={{ marginLeft: 'auto' }} + /> + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/use_selected_view.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/use_selected_view.ts new file mode 100644 index 0000000000000..f132f502666f0 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_availability/use_selected_view.ts @@ -0,0 +1,26 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { useEffect, useState } from 'react'; + +const localKey = 'xpack.uptime.detailPage.selectedView'; + +interface Props { + selectedView: string; + setSelectedView: (val: string) => void; +} + +export const useSelectedView = (): Props => { + const getSelectedView = localStorage.getItem(localKey) ?? 'list'; + + const [selectedView, setSelectedView] = useState(getSelectedView); + + useEffect(() => { + localStorage.setItem(localKey, selectedView); + }, [selectedView]); + + return { selectedView, setSelectedView }; +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/__snapshots__/location_map.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/__snapshots__/location_map.test.tsx.snap new file mode 100644 index 0000000000000..6b3d157c23fee --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/__snapshots__/location_map.test.tsx.snap @@ -0,0 +1,27 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`LocationMap component renders correctly against snapshot 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap similarity index 99% rename from x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap index 150c4581dfd13..cd282f916f46c 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/__snapshots__/location_missing.test.tsx.snap @@ -4,6 +4,7 @@ exports[`LocationMissingWarning component renders correctly against snapshot 1`] .c0 { margin-left: auto; margin-bottom: 3px; + margin-right: 5px; }
{ + let upPoints: LocationPoint[]; + + beforeEach(() => { + upPoints = [ + { + name: 'New York', + location: { lat: '40.730610', lon: ' -73.935242' }, + }, + { + name: 'Tokyo', + location: { lat: '52.487448', lon: ' 13.394798' }, + }, + ]; + }); + + it('renders correctly against snapshot', () => { + const component = shallowWithIntl(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_missing.test.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/location_missing.test.tsx similarity index 100% rename from x-pack/plugins/uptime/public/components/monitor/location_map/__tests__/location_missing.test.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/__tests__/location_missing.test.tsx diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/__mocks__/mock.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/__tests__/__mocks__/mock.ts similarity index 96% rename from x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/__mocks__/mock.ts rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/__tests__/__mocks__/mock.ts index 291ab555fbdc6..626011e3d09c9 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/__mocks__/mock.ts +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/__tests__/__mocks__/mock.ts @@ -14,6 +14,7 @@ export const mockDownPointsLayer = { __featureCollection: { features: [ { + id: 'Asia', type: 'feature', geometry: { type: 'Point', @@ -21,6 +22,7 @@ export const mockDownPointsLayer = { }, }, { + id: 'APJ', type: 'feature', geometry: { type: 'Point', @@ -28,6 +30,7 @@ export const mockDownPointsLayer = { }, }, { + id: 'Canada', type: 'feature', geometry: { type: 'Point', @@ -79,6 +82,7 @@ export const mockUpPointsLayer = { __featureCollection: { features: [ { + id: 'US-EAST', type: 'feature', geometry: { type: 'Point', @@ -86,6 +90,7 @@ export const mockUpPointsLayer = { }, }, { + id: 'US-WEST', type: 'feature', geometry: { type: 'Point', @@ -93,6 +98,7 @@ export const mockUpPointsLayer = { }, }, { + id: 'Europe', type: 'feature', geometry: { type: 'Point', diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/map_config.test.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/__tests__/map_config.test.ts similarity index 65% rename from x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/map_config.test.ts rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/__tests__/map_config.test.ts index 7d53d784ff338..09a41bd9eb4b9 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/__tests__/map_config.test.ts +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/__tests__/map_config.test.ts @@ -7,7 +7,7 @@ import { getLayerList } from '../map_config'; import { mockLayerList } from './__mocks__/mock'; import { LocationPoint } from '../embedded_map'; -import { UptimeAppColors } from '../../../../../uptime_app'; +import { UptimeAppColors } from '../../../../../../uptime_app'; jest.mock('uuid', () => { return { @@ -22,14 +22,14 @@ describe('map_config', () => { beforeEach(() => { upPoints = [ - { lat: '52.487239', lon: '13.399262' }, - { lat: '55.487239', lon: '13.399262' }, - { lat: '54.487239', lon: '14.399262' }, + { name: 'US-EAST', location: { lat: '52.487239', lon: '13.399262' } }, + { location: { lat: '55.487239', lon: '13.399262' }, name: 'US-WEST' }, + { location: { lat: '54.487239', lon: '14.399262' }, name: 'Europe' }, ]; downPoints = [ - { lat: '52.487239', lon: '13.399262' }, - { lat: '55.487239', lon: '13.399262' }, - { lat: '54.487239', lon: '14.399262' }, + { location: { lat: '52.487239', lon: '13.399262' }, name: 'Asia' }, + { location: { lat: '55.487239', lon: '13.399262' }, name: 'APJ' }, + { location: { lat: '54.487239', lon: '14.399262' }, name: 'Canada' }, ]; colors = { danger: '#BC261E', diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx similarity index 68% rename from x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx index 06cdb07bd8bcd..648418c02489a 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/embedded_map.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/embedded_map.tsx @@ -7,24 +7,30 @@ import React, { useEffect, useState, useContext, useRef } from 'react'; import uuid from 'uuid'; import styled from 'styled-components'; -import { MapEmbeddable, MapEmbeddableInput } from '../../../../../../../legacy/plugins/maps/public'; +import { createPortalNode, InPortal, OutPortal } from 'react-reverse-portal'; +import { + MapEmbeddable, + MapEmbeddableInput, +} from '../../../../../../../../legacy/plugins/maps/public'; import * as i18n from './translations'; -import { Location } from '../../../../../common/runtime_types'; +import { GeoPoint } from '../../../../../../common/runtime_types'; import { getLayerList } from './map_config'; -import { UptimeThemeContext, UptimeStartupPluginsContext } from '../../../../contexts'; +import { UptimeThemeContext, UptimeStartupPluginsContext } from '../../../../../contexts'; import { isErrorEmbeddable, ViewMode, ErrorEmbeddable, -} from '../../../../../../../../src/plugins/embeddable/public'; -import { MAP_SAVED_OBJECT_TYPE } from '../../../../../../maps/public'; +} from '../../../../../../../../../src/plugins/embeddable/public'; +import { MAP_SAVED_OBJECT_TYPE } from '../../../../../../../maps/public'; +import { MapToolTipComponent } from './map_tool_tip'; +import { RenderTooltipContentParams } from '../../../../../../../../legacy/plugins/maps/public'; export interface EmbeddedMapProps { upPoints: LocationPoint[]; downPoints: LocationPoint[]; } -export type LocationPoint = Required; +export type LocationPoint = Required; const EmbeddedPanel = styled.div` z-index: auto; @@ -54,6 +60,8 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp } const factory: any = embeddablePlugin.getEmbeddableFactory(MAP_SAVED_OBJECT_TYPE); + const portalNode = React.useMemo(() => createPortalNode(), []); + const input: MapEmbeddableInput = { id: uuid.v4(), filters: [], @@ -73,12 +81,38 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp zoom: 0, }, disableInteractive: true, - disableTooltipControl: true, hideToolbarOverlay: true, hideLayerControl: true, hideViewControl: true, }; + const renderTooltipContent = ({ + addFilters, + closeTooltip, + features, + isLocked, + getLayerName, + loadFeatureProperties, + loadFeatureGeometry, + }: RenderTooltipContentParams) => { + const props = { + addFilters, + closeTooltip, + isLocked, + getLayerName, + loadFeatureProperties, + loadFeatureGeometry, + }; + const relevantFeatures = features.filter( + (item: any) => item.layerId === 'up_points' || item.layerId === 'down_points' + ); + if (relevantFeatures.length > 0) { + return ; + } + closeTooltip(); + return null; + }; + useEffect(() => { async function setupEmbeddable() { if (!factory) { @@ -90,11 +124,13 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp }); if (embeddableObject && !isErrorEmbeddable(embeddableObject)) { - embeddableObject.setLayerList(getLayerList(upPoints, downPoints, colors)); + embeddableObject.setRenderTooltipContent(renderTooltipContent); + await embeddableObject.setLayerList(getLayerList(upPoints, downPoints, colors)); } setEmbeddable(embeddableObject); } + setupEmbeddable(); // we want this effect to execute exactly once after the component mounts @@ -122,6 +158,9 @@ export const EmbeddedMap = React.memo(({ upPoints, downPoints }: EmbeddedMapProp className="embPanel__content" ref={embeddableRoot} /> + + + ); }); diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/low_poly_layer.json b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/low_poly_layer.json similarity index 100% rename from x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/low_poly_layer.json rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/low_poly_layer.json diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/map_config.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_config.ts similarity index 94% rename from x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/map_config.ts rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_config.ts index f1b530c767f1f..e766641102a24 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/map_config.ts +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_config.ts @@ -6,7 +6,7 @@ import lowPolyLayerFeatures from './low_poly_layer.json'; import { LocationPoint } from './embedded_map'; -import { UptimeAppColors } from '../../../../uptime_app'; +import { UptimeAppColors } from '../../../../../uptime_app'; /** * Returns `Source/Destination Point-to-point` Map LayerList configuration, with a source, @@ -70,9 +70,10 @@ export const getLowPolyLayer = () => { export const getDownPointsLayer = (downPoints: LocationPoint[], dangerColor: string) => { const features = downPoints?.map((point) => ({ type: 'feature', + id: point.name, geometry: { type: 'Point', - coordinates: [+point.lon, +point.lat], + coordinates: [+point.location.lon, +point.location.lat], }, })); return { @@ -122,9 +123,10 @@ export const getDownPointsLayer = (downPoints: LocationPoint[], dangerColor: str export const getUpPointsLayer = (upPoints: LocationPoint[]) => { const features = upPoints?.map((point) => ({ type: 'feature', + id: point.name, geometry: { type: 'Point', - coordinates: [+point.lon, +point.lat], + coordinates: [+point.location.lon, +point.location.lat], }, })); return { diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx new file mode 100644 index 0000000000000..0d54d91007a8d --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/map_tool_tip.tsx @@ -0,0 +1,90 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import moment from 'moment'; +import { i18n } from '@kbn/i18n'; +import React, { useContext } from 'react'; +import { useSelector } from 'react-redux'; +import { + EuiDescriptionList, + EuiDescriptionListDescription, + EuiDescriptionListTitle, + EuiOutsideClickDetector, + EuiPopoverTitle, +} from '@elastic/eui'; +import { TagLabel } from '../../availability_reporting'; +import { UptimeThemeContext } from '../../../../../contexts'; +import { AppState } from '../../../../../state'; +import { monitorLocationsSelector } from '../../../../../state/selectors'; +import { useMonitorId } from '../../../../../hooks'; +import { MonitorLocation } from '../../../../../../common/runtime_types/monitor'; +import { RenderTooltipContentParams } from '../../../../../../../../legacy/plugins/maps/public'; +import { formatAvailabilityValue } from '../../availability_reporting/availability_reporting'; +import { LastCheckLabel } from '../../translations'; + +type MapToolTipProps = Partial; + +export const MapToolTipComponent = ({ closeTooltip, features = [] }: MapToolTipProps) => { + const { id: featureId, layerId } = features[0] ?? {}; + const locationName = featureId?.toString(); + const { + colors: { gray, danger }, + } = useContext(UptimeThemeContext); + + const monitorId = useMonitorId(); + + const monitorLocations = useSelector((state: AppState) => + monitorLocationsSelector(state, monitorId) + ); + if (!locationName || !monitorLocations?.locations) { + return null; + } + const { + timestamp, + up_history: ups, + down_history: downs, + }: MonitorLocation = monitorLocations.locations!.find( + ({ geo }: MonitorLocation) => geo.name === locationName + )!; + + const availability = (ups / (ups + downs)) * 100; + + return ( + { + if (closeTooltip != null) { + closeTooltip(); + } + }} + > + <> + + {layerId === 'up_points' ? ( + + ) : ( + + )} + + + Availability + + {i18n.translate('xpack.uptime.mapToolTip.AvailabilityStat.title', { + defaultMessage: '{value} %', + values: { value: formatAvailabilityValue(availability) }, + description: 'A percentage value like 23.5%', + })} + + {LastCheckLabel} + + {moment(timestamp).fromNow()} + + + + + ); +}; + +export const MapToolTip = React.memo(MapToolTipComponent); diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/translations.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/translations.ts similarity index 100% rename from x-pack/plugins/uptime/public/components/monitor/location_map/embeddables/translations.ts rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/embeddables/translations.ts diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/index.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/index.ts similarity index 81% rename from x-pack/plugins/uptime/public/components/monitor/location_map/index.ts rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/index.ts index 140d33bbeef66..4261400bebc6f 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/index.ts +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/index.ts @@ -5,4 +5,4 @@ */ export * from './location_map'; -export * from './location_status_tags'; +export * from '../availability_reporting/location_status_tags'; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/location_map.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/location_map.tsx new file mode 100644 index 0000000000000..3d0a097d20d70 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/location_map.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 styled from 'styled-components'; +import { EmbeddedMap, LocationPoint } from './embeddables/embedded_map'; + +// These height/width values are used to make sure map is in center of panel +// And to make sure, it doesn't take too much space +const MapPanel = styled.div` + height: 240px; + width: 520px; + margin-right: 65px; + @media (max-width: 574px) { + height: 250px; + width: 100%; + } +`; + +interface Props { + upPoints: LocationPoint[]; + downPoints: LocationPoint[]; +} + +export const LocationMap = ({ upPoints, downPoints }: Props) => { + return ( + + + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/location_map/location_missing.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/location_missing.tsx similarity index 96% rename from x-pack/plugins/uptime/public/components/monitor/location_map/location_missing.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/location_map/location_missing.tsx index 6ce31e4cc8243..e364b6b8940b3 100644 --- a/x-pack/plugins/uptime/public/components/monitor/location_map/location_missing.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/location_map/location_missing.tsx @@ -16,11 +16,12 @@ import { } from '@elastic/eui'; import styled from 'styled-components'; import { FormattedMessage } from '@kbn/i18n/react'; -import { LocationLink } from '../../common/location_link'; +import { LocationLink } from '../../../common/location_link'; const EuiPopoverRight = styled(EuiFlexItem)` margin-left: auto; margin-bottom: 3px; + margin-right: 5px; `; export const LocationMissingWarning = () => { diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/index.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/index.ts similarity index 72% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/index.ts rename to x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/index.ts index 3c861412a39e9..22a059d603778 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/index.ts +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/index.ts @@ -5,5 +5,4 @@ */ export { MonitorSSLCertificate } from './ssl_certificate'; -export { MonitorStatusBarComponent } from './status_bar'; -export { MonitorStatusBar } from './status_bar_container'; +export { MonitorStatusBar } from './status_bar'; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/ssl_certificate.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/ssl_certificate.tsx new file mode 100644 index 0000000000000..93720ab313ee3 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/ssl_certificate.tsx @@ -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 React from 'react'; +import { Link } from 'react-router-dom'; +import { EuiSpacer } from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { Tls } from '../../../../../common/runtime_types'; +import { CERTIFICATES_ROUTE } from '../../../../../common/constants'; +import { MonListDescription, MonListTitle } from './status_bar'; +import { CertStatusColumn } from '../../../overview/monitor_list/cert_status_column'; + +interface Props { + /** + * TLS information coming from monitor in ES heartbeat index + */ + tls: Tls | undefined; +} + +export const MonitorSSLCertificate = ({ tls }: Props) => { + return tls?.not_after ? ( + <> + + + + + + + + + + + + ) : null; +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/status_bar.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/status_bar.tsx new file mode 100644 index 0000000000000..afcc8fae7a8ac --- /dev/null +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/status_bar.tsx @@ -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 React from 'react'; +import styled from 'styled-components'; +import { + EuiLink, + EuiIcon, + EuiSpacer, + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, +} from '@elastic/eui'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { MonitorSSLCertificate } from './ssl_certificate'; +import * as labels from '../translations'; +import { StatusByLocations } from './status_by_location'; +import { useStatusBar } from './use_status_bar'; +import { MonitorIDLabel, OverallAvailability } from '../translations'; +import { URL_LABEL } from '../../../common/translations'; +import { MonitorLocations } from '../../../../../common/runtime_types/monitor'; +import { formatAvailabilityValue } from '../availability_reporting/availability_reporting'; + +export const MonListTitle = styled(EuiDescriptionListTitle)` + &&& { + width: 35%; + } +`; + +export const MonListDescription = styled(EuiDescriptionListDescription)` + &&& { + width: 65%; + overflow-wrap: anywhere; + } +`; + +export const MonitorStatusBar: React.FC = () => { + const { monitorId, monitorStatus, monitorLocations = {} } = useStatusBar(); + + const { locations, up_history: ups, down_history: downs } = monitorLocations as MonitorLocations; + + const full = monitorStatus?.url?.full ?? ''; + + const availability = (ups === 0 && downs === 0) || !ups ? 0 : (ups / (ups + downs)) * 100; + + return ( + <> +
+ +
+ + + {OverallAvailability} + + + + {URL_LABEL} + + + {full} + + + {MonitorIDLabel} + {monitorId} + + + + ); +}; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_by_location.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/status_by_location.tsx similarity index 100% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_by_location.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/status_by_location.tsx diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar_container.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/use_status_bar.ts similarity index 66% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar_container.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/use_status_bar.ts index 9562295437515..27e953aab1b71 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/status_bar_container.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/status_bar/use_status_bar.ts @@ -4,24 +4,33 @@ * you may not use this file except in compliance with the Elastic License. */ -import React, { useContext, useEffect } from 'react'; +import { useContext, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import { monitorLocationsSelector, monitorStatusSelector } from '../../../../state/selectors'; -import { MonitorStatusBarComponent } from './index'; -import { getMonitorStatusAction } from '../../../../state/actions'; -import { useGetUrlParams } from '../../../../hooks'; import { UptimeRefreshContext } from '../../../../contexts'; -import { MonitorIdParam } from '../../../../../common/types'; +import { useGetUrlParams, useMonitorId } from '../../../../hooks'; +import { monitorLocationsSelector, monitorStatusSelector } from '../../../../state/selectors'; import { AppState } from '../../../../state'; +import { getMonitorStatusAction } from '../../../../state/actions'; +import { Ping } from '../../../../../common/runtime_types/ping'; +import { MonitorLocations } from '../../../../../common/runtime_types/monitor'; -export const MonitorStatusBar: React.FC = ({ monitorId }) => { +interface MonitorStatusBarProps { + monitorId: string; + monitorStatus: Ping | null; + monitorLocations?: MonitorLocations; +} + +export const useStatusBar = (): MonitorStatusBarProps => { const { lastRefresh } = useContext(UptimeRefreshContext); const { dateRangeStart: dateStart, dateRangeEnd: dateEnd } = useGetUrlParams(); const dispatch = useDispatch(); + const monitorId = useMonitorId(); + const monitorStatus = useSelector(monitorStatusSelector); + const monitorLocations = useSelector((state: AppState) => monitorLocationsSelector(state, monitorId) ); @@ -30,11 +39,5 @@ export const MonitorStatusBar: React.FC = ({ monitorId }) => { dispatch(getMonitorStatusAction({ dateStart, dateEnd, monitorId })); }, [monitorId, dateStart, dateEnd, lastRefresh, dispatch]); - return ( - - ); + return { monitorStatus, monitorLocations, monitorId }; }; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/status_details.tsx similarity index 72% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/status_details.tsx index 3766ac86785f7..dea39494646a6 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/status_details.tsx @@ -7,31 +7,24 @@ import React, { useContext, useEffect, useState } from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui'; import styled from 'styled-components'; -import { LocationMap } from '../location_map'; +import { LocationAvailability } from './location_availability/location_availability'; import { UptimeRefreshContext } from '../../../contexts'; import { MonitorLocations } from '../../../../common/runtime_types'; -import { MonitorStatusBar } from './monitor_status_bar'; +import { MonitorStatusBar } from './status_bar'; interface MonitorStatusDetailsProps { - monitorId: string; monitorLocations: MonitorLocations; } const WrapFlexItem = styled(EuiFlexItem)` &&& { - @media (max-width: 768px) { - width: 100%; - } - @media (max-width: 1042px) { - flex-basis: 520px; + @media (max-width: 800px) { + flex-basis: 100%; } } `; -export const MonitorStatusDetailsComponent = ({ - monitorId, - monitorLocations, -}: MonitorStatusDetailsProps) => { +export const MonitorStatusDetailsComponent = ({ monitorLocations }: MonitorStatusDetailsProps) => { const { refreshApp } = useContext(UptimeRefreshContext); const [isTabActive] = useState(document.visibilityState); @@ -56,12 +49,12 @@ export const MonitorStatusDetailsComponent = ({ return ( - - - + + + - - + + diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details_container.tsx b/x-pack/plugins/uptime/public/components/monitor/status_details/status_details_container.tsx similarity index 92% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details_container.tsx rename to x-pack/plugins/uptime/public/components/monitor/status_details/status_details_container.tsx index 251f3562f9d1a..92e144bd1b9cc 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/status_details_container.tsx +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/status_details_container.tsx @@ -28,7 +28,5 @@ export const MonitorStatusDetails: React.FC = ({ monitorId }) => dispatch(getMonitorLocationsAction({ dateStart, dateEnd, monitorId })); }, [monitorId, dateStart, dateEnd, lastRefresh, dispatch]); - return ( - - ); + return ; }; diff --git a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/translations.ts b/x-pack/plugins/uptime/public/components/monitor/status_details/translations.ts similarity index 50% rename from x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/translations.ts rename to x-pack/plugins/uptime/public/components/monitor/status_details/translations.ts index f60a1ceeaafb8..f593525fa0942 100644 --- a/x-pack/plugins/uptime/public/components/monitor/monitor_status_details/monitor_status_bar/translations.ts +++ b/x-pack/plugins/uptime/public/components/monitor/status_details/translations.ts @@ -48,3 +48,56 @@ export const timestampFromNowTextAriaLabel = i18n.translate( export const loadingMessage = i18n.translate('xpack.uptime.monitorStatusBar.loadingMessage', { defaultMessage: 'Loading…', }); + +export const MonitorIDLabel = i18n.translate('xpack.uptime.monitorStatusBar.monitor.id', { + defaultMessage: 'Monitor ID', +}); + +export const OverallAvailability = i18n.translate( + 'xpack.uptime.monitorStatusBar.monitor.availability', + { + defaultMessage: 'Overall availability', + } +); + +export const MonitoringFrom = i18n.translate( + 'xpack.uptime.monitorStatusBar.monitor.monitoringFrom', + { + defaultMessage: 'Monitoring from', + } +); + +export const ChangeToMapView = i18n.translate( + 'xpack.uptime.monitorStatusBar.monitor.monitoringFrom.listToMap', + { + defaultMessage: 'Change to map view to check availability by location.', + } +); + +export const ChangeToListView = i18n.translate( + 'xpack.uptime.monitorStatusBar.monitor.monitoringFrom.MapToList', + { + defaultMessage: 'Change to list view to check availability by location.', + } +); + +export const LocationLabel = i18n.translate( + 'xpack.uptime.monitorStatusBar.monitor.availabilityReport.location', + { + defaultMessage: 'Location', + } +); + +export const AvailabilityLabel = i18n.translate( + 'xpack.uptime.monitorStatusBar.monitor.availabilityReport.availability', + { + defaultMessage: 'Availability', + } +); + +export const LastCheckLabel = i18n.translate( + 'xpack.uptime.monitorStatusBar.monitor.availabilityReport.lastCheck', + { + defaultMessage: 'Last check', + } +); diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/cert_status_column.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/cert_status_column.tsx index 5ad0f4d3d1d49..b7c70198912fc 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/cert_status_column.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/cert_status_column.tsx @@ -8,13 +8,14 @@ import React from 'react'; import moment from 'moment'; import styled from 'styled-components'; import { EuiIcon, EuiText, EuiToolTip } from '@elastic/eui'; -import { Cert } from '../../../../common/runtime_types'; +import { Cert, Tls } from '../../../../common/runtime_types'; import { useCertStatus } from '../../../hooks'; -import { EXPIRED, EXPIRES_SOON } from '../../certificates/translations'; +import { EXPIRED, EXPIRES, EXPIRES_SOON } from '../../certificates/translations'; import { CERT_STATUS } from '../../../../common/constants'; interface Props { - cert: Cert; + cert: Cert | Tls; + boldStyle?: boolean; } const Span = styled.span` @@ -22,7 +23,15 @@ const Span = styled.span` vertical-align: middle; `; -export const CertStatusColumn: React.FC = ({ cert }) => { +const H4Text = styled.h4` + &&& { + margin: 0 0 0 4px; + display: inline-block; + color: inherit; + } +`; + +export const CertStatusColumn: React.FC = ({ cert, boldStyle = false }) => { const certStatus = useCertStatus(cert?.not_after); const relativeDate = moment(cert?.not_after).fromNow(); @@ -32,9 +41,15 @@ export const CertStatusColumn: React.FC = ({ cert }) => { - - {text} {relativeDate} - + {boldStyle ? ( + + {text} {relativeDate} + + ) : ( + + {text} {relativeDate} + + )} ); @@ -47,5 +62,5 @@ export const CertStatusColumn: React.FC = ({ cert }) => { return ; } - return certStatus ? : --; + return certStatus ? : --; }; diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx index 1526838460957..75d587579f66f 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/monitor_list.tsx @@ -30,6 +30,7 @@ import { MonitorListProps } from './monitor_list_container'; import { MonitorList } from '../../../state/reducers/monitor_list'; import { CertStatusColumn } from './cert_status_column'; import { MonitorListHeader } from './monitor_list_header'; +import { URL_LABEL } from '../../common/translations'; interface Props extends MonitorListProps { pageSize: number; @@ -106,7 +107,7 @@ export const MonitorListComponent: React.FC = ({ { align: 'left' as const, field: 'state.url.full', - name: labels.URL, + name: URL_LABEL, render: (url: string, summary: MonitorSummary) => ( {url} diff --git a/x-pack/plugins/uptime/public/components/overview/monitor_list/translations.ts b/x-pack/plugins/uptime/public/components/overview/monitor_list/translations.ts index e70eef1d91161..ee922a9ef803f 100644 --- a/x-pack/plugins/uptime/public/components/overview/monitor_list/translations.ts +++ b/x-pack/plugins/uptime/public/components/overview/monitor_list/translations.ts @@ -62,10 +62,6 @@ export const NO_DATA_MESSAGE = i18n.translate('xpack.uptime.monitorList.noItemMe description: 'This message is shown if the monitors table is rendered but has no items.', }); -export const URL = i18n.translate('xpack.uptime.monitorList.table.url.name', { - defaultMessage: 'Url', -}); - export const UP = i18n.translate('xpack.uptime.monitorList.statusColumn.upLabel', { defaultMessage: 'Up', }); diff --git a/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap b/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap index ec0ee120b6283..dbdfd6b27e69f 100644 --- a/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap +++ b/x-pack/plugins/uptime/public/pages/__tests__/__snapshots__/page_header.test.tsx.snap @@ -2,21 +2,25 @@ exports[`PageHeader shallow renders extra links: page_header_with_extra_links 1`] = ` Array [ - @media only screen and (max-width:1024px) and (min-width:868px) { - .c0.c0.c0 .euiSuperDatePicker__flexWrapper { + .c0 { + white-space: nowrap; +} + +@media only screen and (max-width:1024px) and (min-width:868px) { + .c1.c1.c1 .euiSuperDatePicker__flexWrapper { width: 500px; } } @media only screen and (max-width:880px) { - .c0.c0.c0 { + .c1.c1.c1 { -webkit-box-flex: 1; -webkit-flex-grow: 1; -ms-flex-positive: 1; flex-grow: 1; } - .c0.c0.c0 .euiSuperDatePicker__flexWrapper { + .c1.c1.c1 .euiSuperDatePicker__flexWrapper { width: calc(100% + 8px); } } @@ -28,7 +32,7 @@ Array [ class="euiFlexItem" >

TestingHeading

@@ -103,7 +107,7 @@ Array [

TestingHeading

@@ -250,7 +258,7 @@ Array [ class="euiFlexItem euiFlexItem--flexGrowZero" />

TestingHeading

diff --git a/x-pack/plugins/uptime/public/pages/page_header.tsx b/x-pack/plugins/uptime/public/pages/page_header.tsx index d2e1f9036a24a..3b228afe904f4 100644 --- a/x-pack/plugins/uptime/public/pages/page_header.tsx +++ b/x-pack/plugins/uptime/public/pages/page_header.tsx @@ -18,6 +18,7 @@ interface PageHeaderProps { extraLinks?: boolean; datePicker?: boolean; } + const SETTINGS_LINK_TEXT = i18n.translate('xpack.uptime.page_header.settingsLink', { defaultMessage: 'Settings', }); @@ -38,6 +39,10 @@ const StyledPicker = styled(EuiFlexItem)` } `; +const H1Text = styled.h1` + white-space: nowrap; +`; + export const PageHeader = React.memo( ({ headingText, extraLinks = false, datePicker = true }: PageHeaderProps) => { const DatePickerComponent = () => @@ -73,7 +78,7 @@ export const PageHeader = React.memo( > -

{headingText}

+ {headingText}
{extraLinkComponents} diff --git a/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts b/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts index c8d3ca043edc5..17d79002e6f7d 100644 --- a/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts +++ b/x-pack/plugins/uptime/server/lib/requests/get_monitor_locations.ts @@ -32,7 +32,7 @@ export const getMonitorLocations: UMElasticsearchQueryFn< bool: { filter: [ { - match: { + term: { 'monitor.id': monitorId, }, }, @@ -70,6 +70,18 @@ export const getMonitorLocations: UMElasticsearchQueryFn< _source: ['monitor', 'summary', 'observer', '@timestamp'], }, }, + down_history: { + sum: { + field: 'summary.down', + missing: 0, + }, + }, + up_history: { + sum: { + field: 'summary.up', + missing: 0, + }, + }, }, }, }, @@ -99,10 +111,17 @@ export const getMonitorLocations: UMElasticsearchQueryFn< } }; + let totalUps = 0; + let totalDowns = 0; + const monLocs: MonitorLocation[] = []; - locations.forEach((loc: any) => { - const mostRecentLocation = loc.most_recent.hits.hits[0]._source; + locations.forEach(({ most_recent: mostRecent, up_history, down_history }: any) => { + const mostRecentLocation = mostRecent.hits.hits[0]._source; + totalUps += up_history.value; + totalDowns += down_history.value; const location: MonitorLocation = { + up_history: up_history.value ?? 0, + down_history: down_history.value ?? 0, summary: mostRecentLocation?.summary, geo: getGeo(mostRecentLocation?.observer?.geo), timestamp: mostRecentLocation['@timestamp'], @@ -113,5 +132,7 @@ export const getMonitorLocations: UMElasticsearchQueryFn< return { monitorId, locations: monLocs, + up_history: totalUps, + down_history: totalDowns, }; }; diff --git a/x-pack/test/accessibility/apps/uptime.ts b/x-pack/test/accessibility/apps/uptime.ts index dccce4ba1b0b1..ebd120fa0feea 100644 --- a/x-pack/test/accessibility/apps/uptime.ts +++ b/x-pack/test/accessibility/apps/uptime.ts @@ -65,7 +65,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { it('detail page', async () => { await uptimeService.navigation.goToMonitor(A11Y_TEST_MONITOR_ID); - await uptimeService.monitor.locationMapIsRendered(); + await uptimeService.monitor.displayOverallAvailability('0.00 %'); await a11y.testAppSnapshot(); }); diff --git a/x-pack/test/functional/apps/uptime/locations.ts b/x-pack/test/functional/apps/uptime/locations.ts index 27c42a365ec74..8aefca6a70195 100644 --- a/x-pack/test/functional/apps/uptime/locations.ts +++ b/x-pack/test/functional/apps/uptime/locations.ts @@ -11,41 +11,58 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default ({ getPageObjects, getService }: FtrProviderContext) => { const { uptime: uptimePage } = getPageObjects(['uptime']); const uptime = getService('uptime'); + const es = getService('legacyEs'); const monitor = () => uptime.monitor; + const MONITOR_ID = 'location-testing-id'; + + const LessAvailMonitor = 'less-availability-monitor'; + + const addMonitorWithNoLocation = async () => { + /** + * This mogrify function will strip the documents of their location + * data (but preserve their location name), which is necessary for + * this test to work as desired. + * @param d current document + */ + const mogrifyNoLocation = (d: any) => { + if (d.observer?.geo?.location) { + d.observer.geo.location = undefined; + } + return d; + }; + await makeChecksWithStatus(es, MONITOR_ID, 5, 2, 10000, {}, 'up', mogrifyNoLocation); + }; + + const addLessAvailMonitor = async () => { + await makeChecksWithStatus(es, LessAvailMonitor, 5, 2, 10000, {}, 'up'); + await makeChecksWithStatus(es, LessAvailMonitor, 5, 2, 10000, {}, 'down'); + }; describe('Observer location', () => { const start = moment().subtract('15', 'm').toISOString(); const end = moment().toISOString(); - const MONITOR_ID = 'location-testing-id'; + before(async () => { + await addMonitorWithNoLocation(); + await addLessAvailMonitor(); + await uptime.navigation.goToUptime(); + await uptimePage.goToRoot(true); + }); beforeEach(async () => { - /** - * This mogrify function will strip the documents of their location - * data (but preserve their location name), which is necessary for - * this test to work as desired. - * @param d current document - */ - const mogrifyNoLocation = (d: any) => { - if (d.observer?.geo?.location) { - d.observer.geo.location = undefined; - } - return d; - }; - await makeChecksWithStatus( - getService('legacyEs'), - MONITOR_ID, - 5, - 2, - 10000, - {}, - 'up', - mogrifyNoLocation - ); - await uptime.navigation.goToUptime(); + await addMonitorWithNoLocation(); + await addLessAvailMonitor(); + if (!(await uptime.navigation.isOnDetailsPage())) + await uptimePage.loadDataAndGoToMonitorPage(start, end, MONITOR_ID); + }); + + it('displays the overall availability', async () => { + await monitor().displayOverallAvailability('100.00 %'); + }); - await uptimePage.loadDataAndGoToMonitorPage(start, end, MONITOR_ID); + it('can change the view to map', async () => { + await monitor().toggleToMapView(); }); it('renders the location panel and canvas', async () => { @@ -55,5 +72,11 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { it('renders the location missing popover when monitor has location name, but no geo data', async () => { await monitor().locationMissingExists(); }); + + it('displays less monitor availability', async () => { + await uptime.navigation.goToHomeViaBreadCrumb(); + await uptimePage.loadDataAndGoToMonitorPage(start, end, LessAvailMonitor); + await monitor().displayOverallAvailability('50.00 %'); + }); }); }; diff --git a/x-pack/test/functional/services/uptime/common.ts b/x-pack/test/functional/services/uptime/common.ts index b5be1e29a0e8c..5f544b5e46010 100644 --- a/x-pack/test/functional/services/uptime/common.ts +++ b/x-pack/test/functional/services/uptime/common.ts @@ -58,13 +58,13 @@ export function UptimeCommonProvider({ getService }: FtrProviderContext) { '[data-test-subj="xpack.uptime.filterBar.filterStatusUp"]' ); if (await upFilter.elementHasClass('euiFilterButton-hasActiveFilters')) { - this.setStatusFilterUp(); + await this.setStatusFilterUp(); } const downFilter = await find.byCssSelector( '[data-test-subj="xpack.uptime.filterBar.filterStatusDown"]' ); if (await downFilter.elementHasClass('euiFilterButton-hasActiveFilters')) { - this.setStatusFilterDown(); + await this.setStatusFilterDown(); } }, async selectFilterItem(filterType: string, option: string) { diff --git a/x-pack/test/functional/services/uptime/monitor.ts b/x-pack/test/functional/services/uptime/monitor.ts index 3137711698ba4..593950fbb7619 100644 --- a/x-pack/test/functional/services/uptime/monitor.ts +++ b/x-pack/test/functional/services/uptime/monitor.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import expect from '@kbn/expect/expect.js'; import { FtrProviderContext } from '../../ftr_provider_context'; export function UptimeMonitorProvider({ getService }: FtrProviderContext) { @@ -17,6 +18,13 @@ export function UptimeMonitorProvider({ getService }: FtrProviderContext) { timeout: 3000, }); }, + async displayOverallAvailability(availabilityVal: string) { + return retry.tryForTime(60 * 1000, async () => { + await testSubjects.existOrFail('uptimeOverallAvailability'); + const availability = await testSubjects.getVisibleText('uptimeOverallAvailability'); + expect(availability).to.be(availabilityVal); + }); + }, async locationMapIsRendered() { return retry.tryForTime(15000, async () => { await testSubjects.existOrFail('xpack.uptime.locationMap.embeddedPanel', { @@ -45,5 +53,8 @@ export function UptimeMonitorProvider({ getService }: FtrProviderContext) { ); }); }, + async toggleToMapView() { + await testSubjects.click('uptimeMonitorToggleMapBtn'); + }, }; } diff --git a/x-pack/test/functional/services/uptime/navigation.ts b/x-pack/test/functional/services/uptime/navigation.ts index 7c5a4632f8627..f8e0c0cff41f4 100644 --- a/x-pack/test/functional/services/uptime/navigation.ts +++ b/x-pack/test/functional/services/uptime/navigation.ts @@ -56,6 +56,7 @@ export function UptimeNavigationProvider({ getService, getPageObjects }: FtrProv }, goToMonitor: async (monitorId: string) => { + // only go to monitor page if not already there if (!(await testSubjects.exists('uptimeMonitorPage', { timeout: 0 }))) { await testSubjects.click(`monitor-page-link-${monitorId}`); await testSubjects.existOrFail('uptimeMonitorPage', { @@ -80,5 +81,13 @@ export function UptimeNavigationProvider({ getService, getPageObjects }: FtrProv await PageObjects.timePicker.setAbsoluteRange(dateStart, dateEnd); await this.goToMonitor(monitorId); }, + + async isOnDetailsPage() { + return await testSubjects.exists('uptimeMonitorPage', { timeout: 0 }); + }, + + async goToHomeViaBreadCrumb() { + await testSubjects.click('breadcrumb first'); + }, }; } From 9c881447270926c5fb63153c392871cd22eb908a Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 16 Jun 2020 09:30:02 -0700 Subject: [PATCH 04/41] [DOCS] Adds classification to data frame analytics overview (#69068) --- docs/user/ml/index.asciidoc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/user/ml/index.asciidoc b/docs/user/ml/index.asciidoc index f82bb0a406511..1bc74ce87de08 100644 --- a/docs/user/ml/index.asciidoc +++ b/docs/user/ml/index.asciidoc @@ -87,12 +87,14 @@ and {ml-docs}/xpack-ml.html[{ml-cap} {anomaly-detect}]. [[xpack-ml-dfanalytics]] == {dfanalytics-cap} +experimental[] + The Elastic {ml} {dfanalytics} feature enables you to analyze your data using -{oldetection} and {regression} algorithms and generate new indices that contain -the results alongside your source data. +{classification}, {oldetection}, and {regression} algorithms and generate new +indices that contain the results alongside your source data. If you have a license that includes the {ml-features}, you can create -{oldetection} {dfanalytics-jobs} and view their results on the *Analytics* page +{dfanalytics-jobs} and view their results on the *Analytics* page in {kib}. For example: [role="screenshot"] From fb97d91789faf2c7fe9771a832876e4c38020492 Mon Sep 17 00:00:00 2001 From: patrykkopycinski Date: Tue, 16 Jun 2020 18:44:34 +0200 Subject: [PATCH 05/41] Bump react-redux (#69182) --- package.json | 4 ++-- x-pack/package.json | 4 ++-- yarn.lock | 17 ++++++++--------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/package.json b/package.json index b886e6ae0f5d3..85eba40c6251a 100644 --- a/package.json +++ b/package.json @@ -243,7 +243,7 @@ "react-input-range": "^1.3.0", "react-markdown": "^4.3.1", "react-monaco-editor": "~0.27.0", - "react-redux": "^7.1.3", + "react-redux": "^7.2.0", "react-resize-detector": "^4.2.0", "react-router": "^5.1.2", "react-router-dom": "^5.1.2", @@ -375,7 +375,7 @@ "@types/react": "^16.9.36", "@types/react-dom": "^16.9.8", "@types/react-grid-layout": "^0.16.7", - "@types/react-redux": "^7.1.7", + "@types/react-redux": "^7.1.9", "@types/react-resize-detector": "^4.0.1", "@types/react-router": "^5.1.3", "@types/react-router-dom": "^5.1.3", diff --git a/x-pack/package.json b/x-pack/package.json index c582cc8be9bbd..e24d75cc0d968 100644 --- a/x-pack/package.json +++ b/x-pack/package.json @@ -98,7 +98,7 @@ "@types/react": "^16.9.36", "@types/react-beautiful-dnd": "^12.1.1", "@types/react-dom": "^16.9.8", - "@types/react-redux": "^7.1.7", + "@types/react-redux": "^7.1.9", "@types/react-router-dom": "^5.1.3", "@types/react-sticky": "^6.0.3", "@types/react-test-renderer": "^16.9.1", @@ -322,7 +322,7 @@ "react-markdown": "^4.3.1", "react-moment-proptypes": "^1.7.0", "react-portal": "^3.2.0", - "react-redux": "^7.1.3", + "react-redux": "^7.2.0", "react-reverse-portal": "^1.0.4", "react-router": "^5.1.2", "react-router-dom": "^5.1.2", diff --git a/yarn.lock b/yarn.lock index 0188957073965..e43cb2997e531 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5550,10 +5550,10 @@ "@types/prop-types" "*" "@types/react" "*" -"@types/react-redux@^7.1.7": - version "7.1.7" - resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.7.tgz#12a0c529aba660696947384a059c5c6e08185c7a" - integrity sha512-U+WrzeFfI83+evZE2dkZ/oF/1vjIYgqrb5dGgedkqVV8HEfDFujNgWCwHL89TDuWKb47U0nTBT6PLGq4IIogWg== +"@types/react-redux@^7.1.9": + version "7.1.9" + resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.9.tgz#280c13565c9f13ceb727ec21e767abe0e9b4aec3" + integrity sha512-mpC0jqxhP4mhmOl3P4ipRsgTgbNofMRXJb08Ms6gekViLj61v1hOZEKWDCyWsdONr6EjEA6ZHXC446wdywDe0w== dependencies: "@types/hoist-non-react-statics" "^3.3.0" "@types/react" "*" @@ -25452,14 +25452,13 @@ react-redux@^5.1.2: react-is "^16.6.0" react-lifecycles-compat "^3.0.0" -react-redux@^7.1.0, react-redux@^7.1.1, react-redux@^7.1.3: - version "7.1.3" - resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.1.3.tgz#717a3d7bbe3a1b2d535c94885ce04cdc5a33fc79" - integrity sha512-uI1wca+ECG9RoVkWQFF4jDMqmaw0/qnvaSvOoL/GA4dNxf6LoV8sUAcNDvE5NWKs4hFpn0t6wswNQnY3f7HT3w== +react-redux@^7.1.0, react-redux@^7.1.1, react-redux@^7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.0.tgz#f970f62192b3981642fec46fd0db18a074fe879d" + integrity sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA== dependencies: "@babel/runtime" "^7.5.5" hoist-non-react-statics "^3.3.0" - invariant "^2.2.4" loose-envify "^1.4.0" prop-types "^15.7.2" react-is "^16.9.0" From 62f25506d384fc0c430486fa97c9a5c98e597264 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 16 Jun 2020 09:54:41 -0700 Subject: [PATCH 06/41] [kbn/es] only make one attempt in tests to avoid timeout (#69197) Co-authored-by: spalger Co-authored-by: Elastic Machine --- packages/kbn-es/src/utils/native_realm.js | 30 ++++++++++--------- .../kbn-es/src/utils/native_realm.test.js | 10 +++---- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/kbn-es/src/utils/native_realm.js b/packages/kbn-es/src/utils/native_realm.js index 573944a8cc6d0..5075cfb965c08 100644 --- a/packages/kbn-es/src/utils/native_realm.js +++ b/packages/kbn-es/src/utils/native_realm.js @@ -37,13 +37,8 @@ exports.NativeRealm = class NativeRealm { this._log = log; } - async setPassword(username, password = this._elasticPassword, { attempt = 1 } = {}) { - await this._autoRetry(async () => { - this._log.info( - (attempt > 1 ? `attempt ${attempt}: ` : '') + - `setting ${chalk.bold(username)} password to ${chalk.bold(password)}` - ); - + async setPassword(username, password = this._elasticPassword, retryOpts = {}) { + await this._autoRetry(retryOpts, async () => { try { await this._client.security.changePassword({ username, @@ -83,8 +78,8 @@ exports.NativeRealm = class NativeRealm { ); } - async getReservedUsers() { - return await this._autoRetry(async () => { + async getReservedUsers(retryOpts = {}) { + return await this._autoRetry(retryOpts, async () => { const resp = await this._client.security.getUser(); const usernames = Object.keys(resp.body).filter( (user) => resp.body[user].metadata._reserved === true @@ -98,9 +93,9 @@ exports.NativeRealm = class NativeRealm { }); } - async isSecurityEnabled() { + async isSecurityEnabled(retryOpts = {}) { try { - return await this._autoRetry(async () => { + return await this._autoRetry(retryOpts, async () => { const { body: { features }, } = await this._client.xpack.info({ categories: 'features' }); @@ -115,18 +110,25 @@ exports.NativeRealm = class NativeRealm { } } - async _autoRetry(fn, attempt = 1) { + async _autoRetry(opts, fn) { + const { attempt = 1, maxAttempts = 3 } = opts; + try { return await fn(attempt); } catch (error) { - if (attempt >= 3) { + if (attempt >= maxAttempts) { throw error; } const sec = 1.5 * attempt; this._log.warning(`assuming ES isn't initialized completely, trying again in ${sec} seconds`); await new Promise((resolve) => setTimeout(resolve, sec * 1000)); - return await this._autoRetry(fn, attempt + 1); + + const nextOpts = { + ...opts, + attempt: attempt + 1, + }; + return await this._autoRetry(nextOpts, fn); } } }; diff --git a/packages/kbn-es/src/utils/native_realm.test.js b/packages/kbn-es/src/utils/native_realm.test.js index 54732f7136fcc..cd124c97dfdd4 100644 --- a/packages/kbn-es/src/utils/native_realm.test.js +++ b/packages/kbn-es/src/utils/native_realm.test.js @@ -85,7 +85,7 @@ describe('isSecurityEnabled', () => { throw error; }); - expect(await nativeRealm.isSecurityEnabled()).toBe(false); + expect(await nativeRealm.isSecurityEnabled({ maxAttempts: 1 })).toBe(false); }); test('rejects if unexpected error is thrown', async () => { @@ -97,9 +97,9 @@ describe('isSecurityEnabled', () => { throw error; }); - await expect(nativeRealm.isSecurityEnabled()).rejects.toThrowErrorMatchingInlineSnapshot( - `"ResponseError"` - ); + await expect( + nativeRealm.isSecurityEnabled({ maxAttempts: 1 }) + ).rejects.toThrowErrorMatchingInlineSnapshot(`"ResponseError"`); }); }); @@ -226,7 +226,7 @@ describe('setPassword', () => { }); await expect( - nativeRealm.setPassword('kibana_system', 'foo') + nativeRealm.setPassword('kibana_system', 'foo', { maxAttempts: 1 }) ).rejects.toThrowErrorMatchingInlineSnapshot(`"SomeError"`); }); }); From 3de93501c6df2007312e22dc872135e039f1ff0d Mon Sep 17 00:00:00 2001 From: Larry Gregory Date: Tue, 16 Jun 2020 12:55:18 -0400 Subject: [PATCH 07/41] Resolve security cloud test failures (#68935) Co-authored-by: Joe Portner <5295965+jportner@users.noreply.github.com> Co-authored-by: Elastic Machine --- .../functional/page_objects/security_page.ts | 173 ++++++++---------- 1 file changed, 72 insertions(+), 101 deletions(-) diff --git a/x-pack/test/functional/page_objects/security_page.ts b/x-pack/test/functional/page_objects/security_page.ts index 57f62ab33e39a..395e41a91f53a 100644 --- a/x-pack/test/functional/page_objects/security_page.ts +++ b/x-pack/test/functional/page_objects/security_page.ts @@ -16,6 +16,7 @@ export function SecurityPageProvider({ getService, getPageObjects }: FtrProvider const testSubjects = getService('testSubjects'); const esArchiver = getService('esArchiver'); const userMenu = getService('userMenu'); + const comboBox = getService('comboBox'); const PageObjects = getPageObjects(['common', 'header', 'settings', 'home', 'error']); interface LoginOptions { @@ -273,11 +274,7 @@ export function SecurityPageProvider({ getService, getPageObjects }: FtrProvider async addIndexToRole(index: string) { log.debug(`Adding index ${index} to role`); - const indexInput = await retry.try(() => - find.byCssSelector('[data-test-subj="indicesInput0"] input') - ); - await indexInput.type(index); - await indexInput.type('\n'); + await comboBox.setCustom('indicesInput0', index); } async addPrivilegeToRole(privilege: string) { @@ -400,104 +397,78 @@ export function SecurityPageProvider({ getService, getPageObjects }: FtrProvider } } - addRole(roleName: string, roleObj: Role) { + async addRole(roleName: string, roleObj: Role) { const self = this; - return ( - this.clickNewRole() - .then(function () { - // We have to use non-test-subject selectors because this markup is generated by ui-select. - log.debug('roleObj.indices[0].names = ' + roleObj.elasticsearch.indices[0].names); - return testSubjects.append('roleFormNameInput', roleName); - }) - .then(function () { - return find.setValue( - '[data-test-subj="indicesInput0"] input', - roleObj.elasticsearch.indices[0].names + '\n' - ); - }) - .then(function () { - return testSubjects.click('restrictDocumentsQuery0'); - }) - .then(function () { - if (roleObj.elasticsearch.indices[0].query) { - return testSubjects.setValue('queryInput0', roleObj.elasticsearch.indices[0].query); - } - }) - - // KibanaPrivilege - .then(async () => { - const globalPrivileges = (roleObj.kibana as any).global; - if (globalPrivileges) { - for (const privilegeName of globalPrivileges) { - const button = await testSubjects.find('addSpacePrivilegeButton'); - await button.click(); - - const spaceSelector = await testSubjects.find('spaceSelectorComboBox'); - await spaceSelector.click(); - - const globalSpaceOption = await find.byCssSelector(`#spaceOption_\\*`); - await globalSpaceOption.click(); - - const basePrivilegeSelector = await testSubjects.find('basePrivilegeComboBox'); - await basePrivilegeSelector.click(); - - const privilegeOption = await find.byCssSelector(`#basePrivilege_${privilegeName}`); - await privilegeOption.click(); - - const createPrivilegeButton = await testSubjects.find('createSpacePrivilegeButton'); - await createPrivilegeButton.click(); - } - } - }) - - .then(function () { - function addPrivilege(privileges: string[]) { - return privileges.reduce(function (promise: Promise, privilegeName: string) { - // We have to use non-test-subject selectors because this markup is generated by ui-select. - return promise - .then(() => self.addPrivilegeToRole(privilegeName)) - .then(() => PageObjects.common.sleep(250)); - }, Promise.resolve()); - } - return addPrivilege(roleObj.elasticsearch.indices[0].privileges); - }) - // clicking the Granted fields and removing the asterix - .then(async function () { - function addGrantedField(field: string[]) { - return field.reduce(function (promise: Promise, fieldName: string) { - return promise - .then(function () { - return find.setValue('[data-test-subj="fieldInput0"] input', fieldName + '\n'); - }) - .then(function () { - return PageObjects.common.sleep(1000); - }); - }, Promise.resolve()); - } - - if (roleObj.elasticsearch.indices[0].field_security) { - // Toggle FLS switch - await testSubjects.click('restrictFieldsQuery0'); - - // have to remove the '*' - return find - .clickByCssSelector( - 'div[data-test-subj="fieldInput0"] [title="Remove * from selection in this group"] svg.euiIcon' - ) - .then(function () { - return addGrantedField(roleObj.elasticsearch.indices[0].field_security!.grant!); - }); - } - }) // clicking save button - .then(async () => { - log.debug('click save button'); - await testSubjects.click('roleFormSaveButton'); - }) - .then(function () { - return PageObjects.common.sleep(5000); - }) - ); + await this.clickNewRole(); + + // We have to use non-test-subject selectors because this markup is generated by ui-select. + log.debug('roleObj.indices[0].names = ' + roleObj.elasticsearch.indices[0].names); + await testSubjects.append('roleFormNameInput', roleName); + + for (const indexName of roleObj.elasticsearch.indices[0].names) { + await comboBox.setCustom('indicesInput0', indexName); + } + + if (roleObj.elasticsearch.indices[0].query) { + await testSubjects.click('restrictDocumentsQuery0'); + await testSubjects.setValue('queryInput0', roleObj.elasticsearch.indices[0].query); + } + + const globalPrivileges = (roleObj.kibana as any).global; + if (globalPrivileges) { + for (const privilegeName of globalPrivileges) { + await testSubjects.click('addSpacePrivilegeButton'); + + await testSubjects.click('spaceSelectorComboBox'); + + const globalSpaceOption = await find.byCssSelector(`#spaceOption_\\*`); + await globalSpaceOption.click(); + + await testSubjects.click('basePrivilegeComboBox'); + + const privilegeOption = await find.byCssSelector(`#basePrivilege_${privilegeName}`); + await privilegeOption.click(); + + await testSubjects.click('createSpacePrivilegeButton'); + } + } + + function addPrivilege(privileges: string[]) { + return privileges.reduce(function (promise: Promise, privilegeName: string) { + return promise + .then(() => self.addPrivilegeToRole(privilegeName)) + .then(() => PageObjects.common.sleep(250)); + }, Promise.resolve()); + } + + await addPrivilege(roleObj.elasticsearch.indices[0].privileges); + + async function addGrantedField(fields: string[]) { + for (const entry of fields) { + await comboBox.setCustom('fieldInput0', entry); + } + } + + // clicking the Granted fields and removing the asterix + if (roleObj.elasticsearch.indices[0].field_security) { + // Toggle FLS switch + await testSubjects.click('restrictFieldsQuery0'); + + // have to remove the '*' + await find.clickByCssSelector( + 'div[data-test-subj="fieldInput0"] [title="Remove * from selection in this group"] svg.euiIcon' + ); + + await addGrantedField(roleObj.elasticsearch.indices[0].field_security!.grant!); + } + + log.debug('click save button'); + await testSubjects.click('roleFormSaveButton'); + + // Signifies that the role management page redirected back to the role grid page, + // and successfully refreshed the grid + await testSubjects.existOrFail('roleRow'); } async selectRole(role: string) { From d5785a0d6d91f6dd110ea2d2cb69e6c3bfded427 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Tue, 16 Jun 2020 12:02:40 -0600 Subject: [PATCH 08/41] SIEM] Moves validation up to the common section ## Summary Moves validation up to the common section so it can be used by others in common for API boundary validation. --- .../update_exception_list_item_schema.test.ts | 2 +- .../exception_list_item_schema.test.ts | 2 +- .../plugins/lists/common/siem_common_deps.ts | 2 ++ .../create_exception_list_item_route.ts | 8 ++--- .../routes/create_exception_list_route.ts | 8 ++--- .../server/routes/create_list_index_route.ts | 3 +- .../server/routes/create_list_item_route.ts | 8 ++--- .../lists/server/routes/create_list_route.ts | 8 ++--- .../delete_exception_list_item_route.ts | 8 ++--- .../routes/delete_exception_list_route.ts | 8 ++--- .../server/routes/delete_list_index_route.ts | 3 +- .../server/routes/delete_list_item_route.ts | 8 ++--- .../lists/server/routes/delete_list_route.ts | 8 ++--- .../routes/find_exception_list_item_route.ts | 8 ++--- .../routes/find_exception_list_route.ts | 8 ++--- .../server/routes/find_list_item_route.ts | 8 ++--- .../lists/server/routes/find_list_route.ts | 8 ++--- .../server/routes/import_list_item_route.ts | 8 ++--- .../server/routes/patch_list_item_route.ts | 8 ++--- .../lists/server/routes/patch_list_route.ts | 8 ++--- .../routes/read_exception_list_item_route.ts | 8 ++--- .../routes/read_exception_list_route.ts | 8 ++--- .../server/routes/read_list_index_route.ts | 3 +- .../server/routes/read_list_item_route.ts | 8 ++--- .../lists/server/routes/read_list_route.ts | 8 ++--- .../update_exception_list_item_route.ts | 8 ++--- .../routes/update_exception_list_route.ts | 8 ++--- .../server/routes/update_list_item_route.ts | 8 ++--- .../lists/server/routes/update_list_route.ts | 8 ++--- .../plugins/lists/server/siem_server_deps.ts | 1 - .../security_solution/common/validate.test.ts | 34 +++++++++++++++++++ .../security_solution/common/validate.ts | 25 ++++++++++++++ .../plugins/security_solution/server/index.ts | 1 - .../rules/add_prepackaged_rules_route.ts | 2 +- .../routes/rules/create_rules_bulk_route.ts | 3 +- .../routes/rules/delete_rules_bulk_route.ts | 3 +- .../get_prepackaged_rules_status_route.ts | 2 +- .../routes/rules/import_rules_route.ts | 2 +- .../routes/rules/patch_rules_bulk_route.ts | 3 +- .../routes/rules/update_rules_bulk_route.ts | 3 +- .../routes/rules/validate.test.ts | 23 ------------- .../detection_engine/routes/rules/validate.ts | 15 +------- .../timeline/routes/import_timelines_route.ts | 2 +- 43 files changed, 128 insertions(+), 190 deletions(-) create mode 100644 x-pack/plugins/security_solution/common/validate.test.ts create mode 100644 x-pack/plugins/security_solution/common/validate.ts diff --git a/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.test.ts b/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.test.ts index 38541e205598b..69702a5e8a4f9 100644 --- a/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.test.ts +++ b/x-pack/plugins/lists/common/schemas/request/update_exception_list_item_schema.test.ts @@ -147,7 +147,7 @@ describe('update_exception_list_item_schema', () => { // TODO: Is it expected behavior for it not to auto-generate a uui or throw // error if item_id is not passed in? - xtest('it should accept an undefined for "item_id" and auto generate a uuid', () => { + test.skip('it should accept an undefined for "item_id" and auto generate a uuid', () => { const inputPayload = getUpdateExceptionListItemSchemaMock(); delete inputPayload.item_id; const decoded = updateExceptionListItemSchema.decode(inputPayload); diff --git a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.test.ts b/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.test.ts index b9d142fbccbee..ff900104251b7 100644 --- a/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.test.ts +++ b/x-pack/plugins/lists/common/schemas/response/exception_list_item_schema.test.ts @@ -101,7 +101,7 @@ describe('exception_list_item_schema', () => { // TODO: Should this throw an error? "namespace_type" gets auto-populated // with default "single", is that desired behavior? - xtest('it should NOT accept an undefined for "namespace_type"', () => { + test.skip('it should NOT accept an undefined for "namespace_type"', () => { const payload = getExceptionListItemSchemaMock(); delete payload.namespace_type; const decoded = exceptionListItemSchema.decode(payload); diff --git a/x-pack/plugins/lists/common/siem_common_deps.ts b/x-pack/plugins/lists/common/siem_common_deps.ts index 3759305987f79..b1bb7d8aace36 100644 --- a/x-pack/plugins/lists/common/siem_common_deps.ts +++ b/x-pack/plugins/lists/common/siem_common_deps.ts @@ -9,3 +9,5 @@ export { DefaultUuid } from '../../security_solution/common/detection_engine/sch export { DefaultStringArray } from '../../security_solution/common/detection_engine/schemas/types/default_string_array'; export { exactCheck } from '../../security_solution/common/exact_check'; export { getPaths, foldLeftRight } from '../../security_solution/common/test_utils'; +export { validate } from '../../security_solution/common/validate'; +export { formatErrors } from '../../security_solution/common/format_errors'; diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts index 2cafd435e0853..375d25c6fa5f8 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { CreateExceptionListItemSchemaDecoded, createExceptionListItemSchema, diff --git a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts index 9be6b72dcd255..bd29a65c9450a 100644 --- a/x-pack/plugins/lists/server/routes/create_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_exception_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { CreateExceptionListSchemaDecoded, createExceptionListSchema, diff --git a/x-pack/plugins/lists/server/routes/create_list_index_route.ts b/x-pack/plugins/lists/server/routes/create_list_index_route.ts index 1c893fb757c5d..5ec2b36da61b0 100644 --- a/x-pack/plugins/lists/server/routes/create_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/create_list_index_route.ts @@ -6,7 +6,8 @@ import { IRouter } from 'kibana/server'; -import { buildSiemResponse, transformError, validate } from '../siem_server_deps'; +import { buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { LIST_INDEX } from '../../common/constants'; import { acknowledgeSchema } from '../../common/schemas'; diff --git a/x-pack/plugins/lists/server/routes/create_list_item_route.ts b/x-pack/plugins/lists/server/routes/create_list_item_route.ts index 68622e98cbc52..2e1b7fa07221f 100644 --- a/x-pack/plugins/lists/server/routes/create_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/create_list_item_route.ts @@ -7,13 +7,9 @@ import { IRouter } from 'kibana/server'; import { LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; import { createListItemSchema, listItemSchema } from '../../common/schemas'; +import { validate } from '../../common/siem_common_deps'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/create_list_route.ts b/x-pack/plugins/lists/server/routes/create_list_route.ts index 0f3c404c53cfd..9872bbfa09e23 100644 --- a/x-pack/plugins/lists/server/routes/create_list_route.ts +++ b/x-pack/plugins/lists/server/routes/create_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { createListSchema, listSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts index 2c91fe3c28681..f363252dada50 100644 --- a/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_exception_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { DeleteExceptionListItemSchemaDecoded, deleteExceptionListItemSchema, diff --git a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts b/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts index b4c67c0ab1418..b1bf705dcc5f6 100644 --- a/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_exception_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { DeleteExceptionListSchemaDecoded, deleteExceptionListSchema, diff --git a/x-pack/plugins/lists/server/routes/delete_list_index_route.ts b/x-pack/plugins/lists/server/routes/delete_list_index_route.ts index 424c3f45aac40..cb2e16b3602a7 100644 --- a/x-pack/plugins/lists/server/routes/delete_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_list_index_route.ts @@ -7,7 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_INDEX } from '../../common/constants'; -import { buildSiemResponse, transformError, validate } from '../siem_server_deps'; +import { buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { acknowledgeSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/delete_list_item_route.ts b/x-pack/plugins/lists/server/routes/delete_list_item_route.ts index 82dfe8a4f29d0..510be764cefba 100644 --- a/x-pack/plugins/lists/server/routes/delete_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { deleteListItemSchema, listItemArraySchema, listItemSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/delete_list_route.ts b/x-pack/plugins/lists/server/routes/delete_list_route.ts index e89355b7689c5..600e4b00c29ca 100644 --- a/x-pack/plugins/lists/server/routes/delete_list_route.ts +++ b/x-pack/plugins/lists/server/routes/delete_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { deleteListSchema, listSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts index 1820ffdeadb88..a6c2a18bb8c8a 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { FindExceptionListItemSchemaDecoded, findExceptionListItemSchema, diff --git a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts b/x-pack/plugins/lists/server/routes/find_exception_list_route.ts index 3181deda8b91d..97e1de834cd37 100644 --- a/x-pack/plugins/lists/server/routes/find_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/find_exception_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { FindExceptionListSchemaDecoded, findExceptionListSchema, diff --git a/x-pack/plugins/lists/server/routes/find_list_item_route.ts b/x-pack/plugins/lists/server/routes/find_list_item_route.ts index 37b5fe44b919c..1ccb948d0ad21 100644 --- a/x-pack/plugins/lists/server/routes/find_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/find_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { findListItemSchema, foundListItemSchema } from '../../common/schemas'; import { decodeCursor } from '../services/utils'; diff --git a/x-pack/plugins/lists/server/routes/find_list_route.ts b/x-pack/plugins/lists/server/routes/find_list_route.ts index 04b33e3d67075..2fa43c6368b5c 100644 --- a/x-pack/plugins/lists/server/routes/find_list_route.ts +++ b/x-pack/plugins/lists/server/routes/find_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { findListSchema, foundListSchema } from '../../common/schemas'; import { decodeCursor } from '../services/utils'; diff --git a/x-pack/plugins/lists/server/routes/import_list_item_route.ts b/x-pack/plugins/lists/server/routes/import_list_item_route.ts index c951c9b337131..67f345c2c6c1d 100644 --- a/x-pack/plugins/lists/server/routes/import_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/import_list_item_route.ts @@ -9,12 +9,8 @@ import { Readable } from 'stream'; import { IRouter } from 'kibana/server'; import { LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { importListItemQuerySchema, importListItemSchema, listSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/patch_list_item_route.ts b/x-pack/plugins/lists/server/routes/patch_list_item_route.ts index e18fd0618b133..f706559dffdbd 100644 --- a/x-pack/plugins/lists/server/routes/patch_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/patch_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { listItemSchema, patchListItemSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/patch_list_route.ts b/x-pack/plugins/lists/server/routes/patch_list_route.ts index 9d3fa4db8ccd0..3a0d8714a14cd 100644 --- a/x-pack/plugins/lists/server/routes/patch_list_route.ts +++ b/x-pack/plugins/lists/server/routes/patch_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { listSchema, patchListSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts index 083d4d7a0d479..c4e969b27fcf4 100644 --- a/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/read_exception_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { ReadExceptionListItemSchemaDecoded, exceptionListItemSchema, diff --git a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts b/x-pack/plugins/lists/server/routes/read_exception_list_route.ts index c295f045b38c2..6cb91c10aea55 100644 --- a/x-pack/plugins/lists/server/routes/read_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/read_exception_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { ReadExceptionListSchemaDecoded, exceptionListSchema, diff --git a/x-pack/plugins/lists/server/routes/read_list_index_route.ts b/x-pack/plugins/lists/server/routes/read_list_index_route.ts index 21f539d97fc74..4664bed3e7a8b 100644 --- a/x-pack/plugins/lists/server/routes/read_list_index_route.ts +++ b/x-pack/plugins/lists/server/routes/read_list_index_route.ts @@ -7,7 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_INDEX } from '../../common/constants'; -import { buildSiemResponse, transformError, validate } from '../siem_server_deps'; +import { buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { listItemIndexExistSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/read_list_item_route.ts b/x-pack/plugins/lists/server/routes/read_list_item_route.ts index 10c7f781f554c..24011d3b50d27 100644 --- a/x-pack/plugins/lists/server/routes/read_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/read_list_item_route.ts @@ -7,13 +7,9 @@ import { IRouter } from 'kibana/server'; import { LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; import { listItemArraySchema, listItemSchema, readListItemSchema } from '../../common/schemas'; +import { validate } from '../../common/siem_common_deps'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/read_list_route.ts b/x-pack/plugins/lists/server/routes/read_list_route.ts index c30eadfca0b65..34924b70fd4df 100644 --- a/x-pack/plugins/lists/server/routes/read_list_route.ts +++ b/x-pack/plugins/lists/server/routes/read_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { listSchema, readListSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts index 73392c326056e..0ec33b7651982 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { UpdateExceptionListItemSchemaDecoded, exceptionListItemSchema, diff --git a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts index fe45d403c040f..cff78614d05ba 100644 --- a/x-pack/plugins/lists/server/routes/update_exception_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_exception_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { EXCEPTION_LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { UpdateExceptionListSchemaDecoded, exceptionListSchema, diff --git a/x-pack/plugins/lists/server/routes/update_list_item_route.ts b/x-pack/plugins/lists/server/routes/update_list_item_route.ts index 494d57b93b8e4..3e231e319104b 100644 --- a/x-pack/plugins/lists/server/routes/update_list_item_route.ts +++ b/x-pack/plugins/lists/server/routes/update_list_item_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_ITEM_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { listItemSchema, updateListItemSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/routes/update_list_route.ts b/x-pack/plugins/lists/server/routes/update_list_route.ts index 6ace61e46a780..a6d9f8329c7c8 100644 --- a/x-pack/plugins/lists/server/routes/update_list_route.ts +++ b/x-pack/plugins/lists/server/routes/update_list_route.ts @@ -7,12 +7,8 @@ import { IRouter } from 'kibana/server'; import { LIST_URL } from '../../common/constants'; -import { - buildRouteValidation, - buildSiemResponse, - transformError, - validate, -} from '../siem_server_deps'; +import { buildRouteValidation, buildSiemResponse, transformError } from '../siem_server_deps'; +import { validate } from '../../common/siem_common_deps'; import { listSchema, updateListSchema } from '../../common/schemas'; import { getListClient } from '.'; diff --git a/x-pack/plugins/lists/server/siem_server_deps.ts b/x-pack/plugins/lists/server/siem_server_deps.ts index df4b07fc46322..87a623c7a1892 100644 --- a/x-pack/plugins/lists/server/siem_server_deps.ts +++ b/x-pack/plugins/lists/server/siem_server_deps.ts @@ -17,5 +17,4 @@ export { createBootstrapIndex, getIndexExists, buildRouteValidation, - validate, } from '../../security_solution/server'; diff --git a/x-pack/plugins/security_solution/common/validate.test.ts b/x-pack/plugins/security_solution/common/validate.test.ts new file mode 100644 index 0000000000000..032f6d9590168 --- /dev/null +++ b/x-pack/plugins/security_solution/common/validate.test.ts @@ -0,0 +1,34 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 t from 'io-ts'; + +import { validate } from './validate'; + +describe('validate', () => { + test('it should do a validation correctly', () => { + const schema = t.exact(t.type({ a: t.number })); + const payload = { a: 1 }; + const [validated, errors] = validate(payload, schema); + + expect(validated).toEqual(payload); + expect(errors).toEqual(null); + }); + + test('it should do an in-validation correctly', () => { + const schema = t.exact(t.type({ a: t.number })); + const payload = { a: 'some other value' }; + const [validated, errors] = validate(payload, schema); + + expect(validated).toEqual(null); + expect(errors).toEqual('Invalid value "some other value" supplied to "a"'); + }); +}); diff --git a/x-pack/plugins/security_solution/common/validate.ts b/x-pack/plugins/security_solution/common/validate.ts new file mode 100644 index 0000000000000..db9e286e2ebc2 --- /dev/null +++ b/x-pack/plugins/security_solution/common/validate.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 { fold } from 'fp-ts/lib/Either'; +import { pipe } from 'fp-ts/lib/pipeable'; +import * as t from 'io-ts'; +import { exactCheck } from './exact_check'; +import { formatErrors } from './format_errors'; + +export const validate = ( + obj: object, + schema: T +): [t.TypeOf | null, string | null] => { + const decoded = schema.decode(obj); + const checked = exactCheck(obj, decoded); + const left = (errors: t.Errors): [T | null, string | null] => [ + null, + formatErrors(errors).join(','), + ]; + const right = (output: T): [T | null, string | null] => [output, null]; + return pipe(checked, fold(left, right)); +}; diff --git a/x-pack/plugins/security_solution/server/index.ts b/x-pack/plugins/security_solution/server/index.ts index 586b9dec2f4ab..8a77137c20c11 100644 --- a/x-pack/plugins/security_solution/server/index.ts +++ b/x-pack/plugins/security_solution/server/index.ts @@ -27,5 +27,4 @@ export { getPolicyExists } from './lib/detection_engine/index/get_policy_exists' export { createBootstrapIndex } from './lib/detection_engine/index/create_bootstrap_index'; export { getIndexExists } from './lib/detection_engine/index/get_index_exists'; export { buildRouteValidation } from './utils/build_validation/route_validation'; -export { validate } from './lib/detection_engine/routes/rules/validate'; export { transformError, buildSiemResponse } from './lib/detection_engine/routes/utils'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts index 39eea16c6290a..9878521c49322 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/add_prepackaged_rules_route.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { validate } from '../../../../../common/validate'; import { PrePackagedRulesSchema, prePackagedRulesSchema, @@ -18,7 +19,6 @@ import { updatePrepackagedRules } from '../../rules/update_prepacked_rules'; import { getRulesToInstall } from '../../rules/get_rules_to_install'; import { getRulesToUpdate } from '../../rules/get_rules_to_update'; import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules'; -import { validate } from './validate'; export const addPrepackedRulesRoute = (router: IRouter) => { router.put( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts index 7af58adca7529..92a7ea17e7eaf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/create_rules_bulk_route.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { validate } from '../../../../../common/validate'; import { createRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/create_rules_type_dependents'; import { RuleAlertAction } from '../../../../../common/detection_engine/types'; import { @@ -19,7 +20,7 @@ import { throwHttpError } from '../../../machine_learning/validation'; import { createRules } from '../../rules/create_rules'; import { readRules } from '../../rules/read_rules'; import { getDuplicates } from './utils'; -import { transformValidateBulkError, validate } from './validate'; +import { transformValidateBulkError } from './validate'; import { getIndexExists } from '../../index/get_index_exists'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts index 12f908ce7e8b5..99bf16aadc815 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/delete_rules_bulk_route.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { validate } from '../../../../../common/validate'; import { queryRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/query_rules_type_dependents'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import { @@ -14,7 +15,7 @@ import { rulesBulkSchema } from '../../../../../common/detection_engine/schemas/ import { IRouter, RouteConfig, RequestHandler } from '../../../../../../../../src/core/server'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { getIdBulkError } from './utils'; -import { transformValidateBulkError, validate } from './validate'; +import { transformValidateBulkError } from './validate'; import { transformBulkError, buildSiemResponse, createBulkErrorObject } from '../utils'; import { deleteRules } from '../../rules/delete_rules'; import { deleteNotifications } from '../../notifications/delete_notifications'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts index c3f4695a20461..bc199ee132e96 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/get_prepackaged_rules_status_route.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { validate } from '../../../../../common/validate'; import { PrePackagedRulesStatusSchema, prePackagedRulesStatusSchema, @@ -16,7 +17,6 @@ import { getRulesToInstall } from '../../rules/get_rules_to_install'; import { getRulesToUpdate } from '../../rules/get_rules_to_update'; import { findRules } from '../../rules/find_rules'; import { getExistingPrepackagedRules } from '../../rules/get_existing_prepackaged_rules'; -import { validate } from './validate'; export const getPrepackagedRulesStatusRoute = (router: IRouter) => { router.get( diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts index c8b61414608a9..a277f97ccf9f0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/import_rules_route.ts @@ -7,6 +7,7 @@ import { chunk } from 'lodash/fp'; import { extname } from 'path'; +import { validate } from '../../../../../common/validate'; import { importRulesQuerySchema, ImportRulesQuerySchemaDecoded, @@ -39,7 +40,6 @@ import { } from '../utils'; import { patchRules } from '../../rules/patch_rules'; import { getTupleDuplicateErrorsAndUniqueRules } from './utils'; -import { validate } from './validate'; import { createRulesStreamFromNdJson } from '../../rules/create_rules_stream_from_ndjson'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; import { HapiReadableStream } from '../../rules/types'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts index 16f491547a9e6..b2a9fdd103a68 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/patch_rules_bulk_route.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { validate } from '../../../../../common/validate'; import { RuleAlertAction } from '../../../../../common/detection_engine/types'; import { patchRulesBulkSchema, @@ -18,7 +19,7 @@ import { buildMlAuthz } from '../../../machine_learning/authz'; import { throwHttpError } from '../../../machine_learning/validation'; import { transformBulkError, buildSiemResponse } from '../utils'; import { getIdBulkError } from './utils'; -import { transformValidateBulkError, validate } from './validate'; +import { transformValidateBulkError } from './validate'; import { patchRules } from '../../rules/patch_rules'; import { updateRulesNotifications } from '../../rules/update_rules_notifications'; import { ruleStatusSavedObjectsClientFactory } from '../../signals/rule_status_saved_objects_client'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts index 3ca4a28dd93ee..1e6815a357154 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/update_rules_bulk_route.ts @@ -4,6 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ +import { validate } from '../../../../../common/validate'; import { updateRuleValidateTypeDependents } from '../../../../../common/detection_engine/schemas/request/update_rules_type_dependents'; import { RuleAlertAction } from '../../../../../common/detection_engine/types'; import { buildRouteValidation } from '../../../../utils/build_validation/route_validation'; @@ -18,7 +19,7 @@ import { SetupPlugins } from '../../../../plugin'; import { buildMlAuthz } from '../../../machine_learning/authz'; import { throwHttpError } from '../../../machine_learning/validation'; import { getIdBulkError } from './utils'; -import { transformValidateBulkError, validate } from './validate'; +import { transformValidateBulkError } from './validate'; import { transformBulkError, buildSiemResponse, createBulkErrorObject } from '../utils'; import { updateRules } from '../../rules/update_rules'; import { updateRulesNotifications } from '../../rules/update_rules_notifications'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts index 07b891e2bf021..1f5442e23d884 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.test.ts @@ -4,10 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import * as t from 'io-ts'; - import { - validate, transformValidate, transformValidateFindAlerts, transformValidateBulkError, @@ -121,26 +118,6 @@ describe('validate', () => { unSetFeatureFlagsForTestsOnly(); }); - describe('validate', () => { - test('it should do a validation correctly', () => { - const schema = t.exact(t.type({ a: t.number })); - const payload = { a: 1 }; - const [validated, errors] = validate(payload, schema); - - expect(validated).toEqual(payload); - expect(errors).toEqual(null); - }); - - test('it should do an in-validation correctly', () => { - const schema = t.exact(t.type({ a: t.number })); - const payload = { a: 'some other value' }; - const [validated, errors] = validate(payload, schema); - - expect(validated).toEqual(null); - expect(errors).toEqual('Invalid value "some other value" supplied to "a"'); - }); - }); - describe('transformValidate', () => { test('it should do a validation correctly of a partial alert', () => { const ruleAlert = getResult(); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts index 7b0bf5997d12f..983382b28ab38 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/rules/validate.ts @@ -9,6 +9,7 @@ import { fold } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; import * as t from 'io-ts'; +import { validate } from '../../../../../common/validate'; import { findRulesSchema } from '../../../../../common/detection_engine/schemas/response/find_rules_schema'; import { RulesSchema, @@ -113,17 +114,3 @@ export const transformValidateBulkError = ( }); } }; - -export const validate = ( - obj: object, - schema: T -): [t.TypeOf | null, string | null] => { - const decoded = schema.decode(obj); - const checked = exactCheck(obj, decoded); - const left = (errors: t.Errors): [T | null, string | null] => [ - null, - formatErrors(errors).join(','), - ]; - const right = (output: T): [T | null, string | null] => [output, null]; - return pipe(checked, fold(left, right)); -}; diff --git a/x-pack/plugins/security_solution/server/lib/timeline/routes/import_timelines_route.ts b/x-pack/plugins/security_solution/server/lib/timeline/routes/import_timelines_route.ts index 0f9e97cfc2106..5080142f22b15 100644 --- a/x-pack/plugins/security_solution/server/lib/timeline/routes/import_timelines_route.ts +++ b/x-pack/plugins/security_solution/server/lib/timeline/routes/import_timelines_route.ts @@ -7,6 +7,7 @@ import { extname } from 'path'; import { chunk, omit } from 'lodash/fp'; +import { validate } from '../../../../common/validate'; import { importRulesSchema } from '../../../../common/detection_engine/schemas/response/import_rules_schema'; import { createPromiseFromStreams } from '../../../../../../../src/legacy/utils'; import { IRouter } from '../../../../../../../src/core/server'; @@ -17,7 +18,6 @@ import { SetupPlugins } from '../../../plugin'; import { ConfigType } from '../../../config'; import { buildRouteValidation } from '../../../utils/build_validation/route_validation'; -import { validate } from '../../detection_engine/routes/rules/validate'; import { buildSiemResponse, createBulkErrorObject, From 9f7620b84dd0707666b6c2d20e3c98b1d0d8eb03 Mon Sep 17 00:00:00 2001 From: Dmitry Lemeshko Date: Tue, 16 Jun 2020 20:15:01 +0200 Subject: [PATCH 09/41] [QA] Code coverage: fix flaky tests (#69272) * skip test * [page_objects/common_page] update closing toast --- test/functional/apps/dashboard/dashboard_filter_bar.js | 2 ++ test/functional/page_objects/common_page.ts | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/test/functional/apps/dashboard/dashboard_filter_bar.js b/test/functional/apps/dashboard/dashboard_filter_bar.js index c931e6763f483..f9b0d0a370c06 100644 --- a/test/functional/apps/dashboard/dashboard_filter_bar.js +++ b/test/functional/apps/dashboard/dashboard_filter_bar.js @@ -170,6 +170,8 @@ export default function ({ getService, getPageObjects }) { }); describe('saved search filtering', function () { + // https://github.com/elastic/kibana/issues/47286#issuecomment-644687577 + this.tags('skipCoverage'); before(async () => { await filterBar.ensureFieldEditorModalIsClosed(); await PageObjects.dashboard.gotoDashboardLandingPage(); diff --git a/test/functional/page_objects/common_page.ts b/test/functional/page_objects/common_page.ts index fe5694efc35da..d08e88ecf47ea 100644 --- a/test/functional/page_objects/common_page.ts +++ b/test/functional/page_objects/common_page.ts @@ -409,7 +409,7 @@ export function CommonPageProvider({ getService, getPageObjects }: FtrProviderCo async closeToastIfExists() { const toastShown = await find.existsByCssSelector('.euiToast'); if (toastShown) { - await this.closeToast(); + await find.clickByCssSelector('.euiToast__closeButton'); } } From efbb4ccc31f314f51b2f10663a5635cbed78e148 Mon Sep 17 00:00:00 2001 From: Melissa Alvarez Date: Tue, 16 Jun 2020 14:29:11 -0400 Subject: [PATCH 10/41] use navigateToUrl instead of window location (#69167) --- .../back_to_list_panel/back_to_list_panel.tsx | 57 +++++++++++-------- .../analytics_list/action_clone.tsx | 18 ++++-- .../source_selection/source_selection.tsx | 18 ++++-- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/back_to_list_panel/back_to_list_panel.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/back_to_list_panel/back_to_list_panel.tsx index e437d27372a3e..b6b335afa53f5 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/back_to_list_panel/back_to_list_panel.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_creation/components/back_to_list_panel/back_to_list_panel.tsx @@ -7,29 +7,38 @@ import React, { FC, Fragment } from 'react'; import { EuiCard, EuiHorizontalRule, EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { useMlKibana } from '../../../../../contexts/kibana'; -function redirectToAnalyticsManagementPage() { - window.location.href = '#/data_frame_analytics?'; -} +export const BackToListPanel: FC = () => { + const { + services: { + application: { navigateToUrl }, + }, + } = useMlKibana(); -export const BackToListPanel: FC = () => ( - - - } - title={i18n.translate('xpack.ml.dataframe.analytics.create.analyticsListCardTitle', { - defaultMessage: 'Data Frame Analytics', - })} - description={i18n.translate( - 'xpack.ml.dataframe.analytics.create.analyticsListCardDescription', - { - defaultMessage: 'Return to the analytics management page.', - } - )} - onClick={redirectToAnalyticsManagementPage} - data-test-subj="analyticsWizardCardManagement" - /> - -); + const redirectToAnalyticsManagementPage = async () => { + await navigateToUrl('#/data_frame_analytics?'); + }; + + return ( + + + } + title={i18n.translate('xpack.ml.dataframe.analytics.create.analyticsListCardTitle', { + defaultMessage: 'Data Frame Analytics', + })} + description={i18n.translate( + 'xpack.ml.dataframe.analytics.create.analyticsListCardDescription', + { + defaultMessage: 'Return to the analytics management page.', + } + )} + onClick={redirectToAnalyticsManagementPage} + data-test-subj="analyticsWizardCardManagement" + /> + + ); +}; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.tsx index e8b1cd1a5696a..df7dce7217fd4 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/analytics_list/action_clone.tsx @@ -360,7 +360,14 @@ export const CloneAction: FC = ({ createAnalyticsForm, item }) defaultMessage: 'Clone job', }); - const { notifications, savedObjects } = useMlKibana().services; + const { + services: { + application: { navigateToUrl }, + notifications: { toasts }, + savedObjects, + }, + } = useMlKibana(); + const savedObjectsClient = savedObjects.client; const onClick = async () => { @@ -385,7 +392,6 @@ export const CloneAction: FC = ({ createAnalyticsForm, item }) sourceIndexId = ip.id; } } catch (e) { - const { toasts } = notifications; const error = extractErrorMessage(e); toasts.addDanger( @@ -401,9 +407,11 @@ export const CloneAction: FC = ({ createAnalyticsForm, item }) } if (sourceIndexId) { - window.location.href = `ml#/data_frame_analytics/new_job?index=${encodeURIComponent( - sourceIndexId - )}&jobId=${item.config.id}`; + await navigateToUrl( + `ml#/data_frame_analytics/new_job?index=${encodeURIComponent(sourceIndexId)}&jobId=${ + item.config.id + }` + ); } }; diff --git a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx index d20afe93d2b9d..b03a58a02309d 100644 --- a/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx +++ b/x-pack/plugins/ml/public/application/data_frame_analytics/pages/analytics_management/components/source_selection/source_selection.tsx @@ -26,12 +26,20 @@ interface Props { } export const SourceSelection: FC = ({ onClose }) => { - const { uiSettings, savedObjects } = useMlKibana().services; + const { + services: { + application: { navigateToUrl }, + savedObjects, + uiSettings, + }, + } = useMlKibana(); - const onSearchSelected = (id: string, type: string) => { - window.location.href = `ml#/data_frame_analytics/new_job?${ - type === 'index-pattern' ? 'index' : 'savedSearchId' - }=${encodeURIComponent(id)}`; + const onSearchSelected = async (id: string, type: string) => { + await navigateToUrl( + `ml#/data_frame_analytics/new_job?${ + type === 'index-pattern' ? 'index' : 'savedSearchId' + }=${encodeURIComponent(id)}` + ); }; return ( From db1df7bed03f624dca78630830b9bb0395666b20 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 16 Jun 2020 12:57:34 -0700 Subject: [PATCH 11/41] [kbn/optimizer] fix windows compatibility (#69304) Co-authored-by: spalger --- .../src/optimizer/observe_worker.ts | 66 +++++++++++++++---- .../src/worker/entry_point_creator.ts | 10 ++- .../kbn-optimizer/src/worker/run_worker.ts | 38 +++++++++-- .../src/worker/webpack.config.ts | 14 ++-- 4 files changed, 102 insertions(+), 26 deletions(-) diff --git a/packages/kbn-optimizer/src/optimizer/observe_worker.ts b/packages/kbn-optimizer/src/optimizer/observe_worker.ts index 4527052fa821a..fef3efc13a516 100644 --- a/packages/kbn-optimizer/src/optimizer/observe_worker.ts +++ b/packages/kbn-optimizer/src/optimizer/observe_worker.ts @@ -22,7 +22,7 @@ import { inspect } from 'util'; import execa from 'execa'; import * as Rx from 'rxjs'; -import { map, takeUntil } from 'rxjs/operators'; +import { map, takeUntil, first, ignoreElements } from 'rxjs/operators'; import { isWorkerMsg, WorkerConfig, WorkerMsg, Bundle, BundleRefs } from '../common'; @@ -68,19 +68,11 @@ if (inspectFlagIndex !== -1) { function usingWorkerProc( config: OptimizerConfig, - workerConfig: WorkerConfig, - bundles: Bundle[], fn: (proc: execa.ExecaChildProcess) => Rx.Observable ) { return Rx.using( (): ProcResource => { - const args = [ - JSON.stringify(workerConfig), - JSON.stringify(bundles.map((b) => b.toSpec())), - BundleRefs.fromBundles(config.bundles).toSpecJson(), - ]; - - const proc = execa.node(require.resolve('../worker/run_worker'), args, { + const proc = execa.node(require.resolve('../worker/run_worker'), [], { nodeOptions: [ ...(inspectFlag && config.inspectWorkers ? [`${inspectFlag}=${inspectPortCounter++}`] @@ -129,6 +121,51 @@ function observeStdio$(stream: Readable, name: WorkerStdio['stream']) { ); } +/** + * We used to pass configuration to the worker as JSON encoded arguments, but they + * grew too large for argv, especially on Windows, so we had to move to an async init + * where we send the args over IPC. To keep the logic simple we basically mock the + * argv behavior and don't use complicated messages or anything so that state can + * be initialized in the worker before most of the code is run. + */ +function initWorker( + proc: execa.ExecaChildProcess, + config: OptimizerConfig, + workerConfig: WorkerConfig, + bundles: Bundle[] +) { + const msg$ = Rx.fromEvent<[unknown]>(proc, 'message').pipe( + // validate the initialization messages from the process + map(([msg]) => { + if (typeof msg === 'string') { + switch (msg) { + case 'init': + return 'init' as const; + case 'ready': + return 'ready' as const; + } + } + + throw new Error(`unexpected message from worker while initializing: [${inspect(msg)}]`); + }) + ); + + return Rx.concat( + msg$.pipe(first((msg) => msg === 'init')), + Rx.defer(() => { + proc.send({ + args: [ + JSON.stringify(workerConfig), + JSON.stringify(bundles.map((b) => b.toSpec())), + BundleRefs.fromBundles(config.bundles).toSpecJson(), + ], + }); + return []; + }), + msg$.pipe(first((msg) => msg === 'ready')) + ).pipe(ignoreElements()); +} + /** * Start a worker process with the specified `workerConfig` and * `bundles` and return an observable of the events related to @@ -140,10 +177,11 @@ export function observeWorker( workerConfig: WorkerConfig, bundles: Bundle[] ): Rx.Observable { - return usingWorkerProc(config, workerConfig, bundles, (proc) => { - let lastMsg: WorkerMsg; + return usingWorkerProc(config, (proc) => { + const init$ = initWorker(proc, config, workerConfig, bundles); - return Rx.merge( + let lastMsg: WorkerMsg; + const worker$: Rx.Observable = Rx.merge( Rx.of({ type: 'worker started', bundles, @@ -201,5 +239,7 @@ export function observeWorker( ) ) ); + + return Rx.concat(init$, worker$); }); } diff --git a/packages/kbn-optimizer/src/worker/entry_point_creator.ts b/packages/kbn-optimizer/src/worker/entry_point_creator.ts index a613e3e8925a4..f8f41b2e13422 100644 --- a/packages/kbn-optimizer/src/worker/entry_point_creator.ts +++ b/packages/kbn-optimizer/src/worker/entry_point_creator.ts @@ -17,9 +17,13 @@ * under the License. */ -module.exports = function ({ entries }: { entries: Array<{ importId: string; relPath: string }> }) { - const lines = entries.map(({ importId, relPath }) => [ - `__kbnBundles__.define('${importId}', __webpack_require__, require.resolve('./${relPath}'))`, +module.exports = function ({ + entries, +}: { + entries: Array<{ importId: string; requirePath: string }>; +}) { + const lines = entries.map(({ importId, requirePath }) => [ + `__kbnBundles__.define('${importId}', __webpack_require__, require.resolve('${requirePath}'))`, ]); return { diff --git a/packages/kbn-optimizer/src/worker/run_worker.ts b/packages/kbn-optimizer/src/worker/run_worker.ts index 178637d39ab00..781cf83624a1e 100644 --- a/packages/kbn-optimizer/src/worker/run_worker.ts +++ b/packages/kbn-optimizer/src/worker/run_worker.ts @@ -17,7 +17,10 @@ * under the License. */ +import { inspect } from 'util'; + import * as Rx from 'rxjs'; +import { take, mergeMap } from 'rxjs/operators'; import { parseBundles, @@ -80,15 +83,38 @@ setInterval(() => { } }, 1000).unref(); +function assertInitMsg(msg: unknown): asserts msg is { args: string[] } { + if (typeof msg !== 'object' || !msg) { + throw new Error(`expected init message to be an object: ${inspect(msg)}`); + } + + const { args } = msg as Record; + if (!args || !Array.isArray(args) || !args.every((a) => typeof a === 'string')) { + throw new Error( + `expected init message to have an 'args' property that's an array of strings: ${inspect(msg)}` + ); + } +} + Rx.defer(() => { - const workerConfig = parseWorkerConfig(process.argv[2]); - const bundles = parseBundles(process.argv[3]); - const bundleRefs = BundleRefs.parseSpec(process.argv[4]); + process.send!('init'); + + return Rx.fromEvent<[unknown]>(process as any, 'message').pipe( + take(1), + mergeMap(([msg]) => { + assertInitMsg(msg); + process.send!('ready'); + + const workerConfig = parseWorkerConfig(msg.args[0]); + const bundles = parseBundles(msg.args[1]); + const bundleRefs = BundleRefs.parseSpec(msg.args[2]); - // set BROWSERSLIST_ENV so that style/babel loaders see it before running compilers - process.env.BROWSERSLIST_ENV = workerConfig.browserslistEnv; + // set BROWSERSLIST_ENV so that style/babel loaders see it before running compilers + process.env.BROWSERSLIST_ENV = workerConfig.browserslistEnv; - return runCompilers(workerConfig, bundles, bundleRefs); + return runCompilers(workerConfig, bundles, bundleRefs); + }) + ); }).subscribe( (msg) => { send(msg); diff --git a/packages/kbn-optimizer/src/worker/webpack.config.ts b/packages/kbn-optimizer/src/worker/webpack.config.ts index e361b186c30e0..11f5544cd9274 100644 --- a/packages/kbn-optimizer/src/worker/webpack.config.ts +++ b/packages/kbn-optimizer/src/worker/webpack.config.ts @@ -100,10 +100,16 @@ export function getWebpackConfig(bundle: Bundle, bundleRefs: BundleRefs, worker: entries: bundle.publicDirNames.map((name) => { const absolute = Path.resolve(bundle.contextDir, name); const newContext = Path.dirname(ENTRY_CREATOR); - return { - importId: `${bundle.type}/${bundle.id}/${name}`, - relPath: Path.relative(newContext, absolute), - }; + const importId = `${bundle.type}/${bundle.id}/${name}`; + + // relative path from context of the ENTRY_CREATOR, with linux path separators + let requirePath = Path.relative(newContext, absolute).split('\\').join('/'); + if (!requirePath.startsWith('.')) { + // ensure requirePath is identified by node as relative + requirePath = `./${requirePath}`; + } + + return { importId, requirePath }; }), }, }, From ade4c8dded247e4d29b9eb5b9baa934e214aa676 Mon Sep 17 00:00:00 2001 From: Lukas Olson Date: Tue, 16 Jun 2020 13:20:52 -0700 Subject: [PATCH 12/41] [Search service] Refactor the way server-side search strategies are registered (#68452) * [search] Refactor the way search strategies are registered/retrieved on the server * Fix types and tests and update docs * Fix failing test * Fix build of example plugin * Fix functional test * Make server strategies sync Co-authored-by: Liza K --- ...in-plugins-data-server.irequesttypesmap.md | 2 + ...n-plugins-data-server.iresponsetypesmap.md | 2 + ...bana-plugin-plugins-data-server.isearch.md | 2 +- ...lugin-plugins-data-server.isearchcancel.md | 2 +- ...gins-data-server.isearchcontext.config_.md | 11 -- ...plugins-data-server.isearchcontext.core.md | 11 -- ...ugin-plugins-data-server.isearchcontext.md | 19 --- ...ugin-plugins-data-server.isearchoptions.md | 2 +- ...ugins-data-server.isearchoptions.signal.md | 2 + ...plugin-plugins-data-server.isearchsetup.md | 18 +++ ...ver.isearchsetup.registersearchstrategy.md | 13 ++ ...a-server.isearchstart.getsearchstrategy.md | 13 ++ ...plugin-plugins-data-server.isearchstart.md | 18 +++ ...gins-data-server.isearchstrategy.cancel.md | 11 ++ ...gin-plugins-data-server.isearchstrategy.md | 21 ++++ ...gins-data-server.isearchstrategy.search.md | 11 ++ .../kibana-plugin-plugins-data-server.md | 10 +- ...plugin-plugins-data-server.plugin.setup.md | 8 +- ...plugin-plugins-data-server.plugin.start.md | 6 +- ...-plugin-plugins-data-server.pluginstart.md | 1 + ...-plugins-data-server.pluginstart.search.md | 11 ++ ...ins-data-server.tsearchstrategyprovider.md | 13 -- ...ugin-plugins-data-server.tstrategytypes.md | 19 +++ .../server/async_demo_search_strategy.ts | 50 ++++---- .../server/demo_search_strategy.ts | 8 +- examples/demo_search/server/index.ts | 5 +- examples/demo_search/server/plugin.ts | 15 +-- .../search_explorer/public/search_api.tsx | 13 -- .../mocks.ts} | 13 +- src/plugins/data/server/index.ts | 6 +- .../{search/i_search_context.ts => mocks.ts} | 24 +++- src/plugins/data/server/plugin.ts | 11 +- .../data/server/search/create_api.test.ts | 71 ----------- src/plugins/data/server/search/create_api.ts | 58 --------- .../es_search/es_search_strategy.test.ts | 55 +++------ .../search/es_search/es_search_strategy.ts | 22 ++-- src/plugins/data/server/search/i_search.ts | 55 --------- .../data/server/search/i_search_setup.ts | 40 ------- .../data/server/search/i_search_strategy.ts | 67 ----------- src/plugins/data/server/search/index.ts | 14 +-- src/plugins/data/server/search/mocks.ts | 18 +-- src/plugins/data/server/search/routes.test.ts | 67 ++++------- src/plugins/data/server/search/routes.ts | 19 ++- .../data/server/search/search_service.test.ts | 19 +-- .../data/server/search/search_service.ts | 92 +++++---------- .../data/server/search/strategy_types.ts | 39 ------ src/plugins/data/server/search/types.ts | 111 ++++++++++++++++++ src/plugins/data/server/server.api.md | 75 +++++++----- .../core_plugins/legacy_plugins.ts | 2 +- x-pack/plugins/data_enhanced/server/plugin.ts | 5 +- .../server/search/es_search_strategy.test.ts | 69 +++-------- .../server/search/es_search_strategy.ts | 24 ++-- 52 files changed, 552 insertions(+), 741 deletions(-) delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.config_.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.core.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.cancel.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.search.md delete mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tsearchstrategyprovider.md create mode 100644 docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tstrategytypes.md rename src/plugins/data/server/{search/i_route_handler_search_context.ts => field_formats/mocks.ts} (80%) rename src/plugins/data/server/{search/i_search_context.ts => mocks.ts} (60%) delete mode 100644 src/plugins/data/server/search/create_api.test.ts delete mode 100644 src/plugins/data/server/search/create_api.ts delete mode 100644 src/plugins/data/server/search/i_search.ts delete mode 100644 src/plugins/data/server/search/i_search_setup.ts delete mode 100644 src/plugins/data/server/search/i_search_strategy.ts delete mode 100644 src/plugins/data/server/search/strategy_types.ts create mode 100644 src/plugins/data/server/search/types.ts diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.irequesttypesmap.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.irequesttypesmap.md index a9bb8f1eb9d6d..3f5e4ba0f7799 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.irequesttypesmap.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.irequesttypesmap.md @@ -4,6 +4,8 @@ ## IRequestTypesMap interface +The map of search strategy IDs to the corresponding request type definitions. + Signature: ```typescript diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iresponsetypesmap.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iresponsetypesmap.md index fe5fa0a5d3a33..629ab4347eda8 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iresponsetypesmap.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.iresponsetypesmap.md @@ -4,6 +4,8 @@ ## IResponseTypesMap interface +The map of search strategy IDs to the corresponding response type definitions. + Signature: ```typescript diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearch.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearch.md index 6e037f5161b53..96991579c1716 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearch.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearch.md @@ -7,5 +7,5 @@ Signature: ```typescript -export declare type ISearch = (request: IRequestTypesMap[T], options?: ISearchOptions) => Promise; +export declare type ISearch = (context: RequestHandlerContext, request: IRequestTypesMap[T], options?: ISearchOptions) => Promise; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md index 99c30515e8da6..b5a687d1b19d8 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcancel.md @@ -7,5 +7,5 @@ Signature: ```typescript -export declare type ISearchCancel = (id: string) => Promise; +export declare type ISearchCancel = (context: RequestHandlerContext, id: string) => Promise; ``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.config_.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.config_.md deleted file mode 100644 index 364d44dba758a..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.config_.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchContext](./kibana-plugin-plugins-data-server.isearchcontext.md) > [config$](./kibana-plugin-plugins-data-server.isearchcontext.config_.md) - -## ISearchContext.config$ property - -Signature: - -```typescript -config$: Observable; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.core.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.core.md deleted file mode 100644 index 9d571c25d94bd..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.core.md +++ /dev/null @@ -1,11 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchContext](./kibana-plugin-plugins-data-server.isearchcontext.md) > [core](./kibana-plugin-plugins-data-server.isearchcontext.core.md) - -## ISearchContext.core property - -Signature: - -```typescript -core: CoreSetup; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.md deleted file mode 100644 index 1c3c5ec78f894..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchcontext.md +++ /dev/null @@ -1,19 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchContext](./kibana-plugin-plugins-data-server.isearchcontext.md) - -## ISearchContext interface - -Signature: - -```typescript -export interface ISearchContext -``` - -## Properties - -| Property | Type | Description | -| --- | --- | --- | -| [config$](./kibana-plugin-plugins-data-server.isearchcontext.config_.md) | Observable<SharedGlobalConfig> | | -| [core](./kibana-plugin-plugins-data-server.isearchcontext.core.md) | CoreSetup | | - diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.md index 0319048f4418b..49412fc42d3b5 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.md @@ -14,5 +14,5 @@ export interface ISearchOptions | Property | Type | Description | | --- | --- | --- | -| [signal](./kibana-plugin-plugins-data-server.isearchoptions.signal.md) | AbortSignal | | +| [signal](./kibana-plugin-plugins-data-server.isearchoptions.signal.md) | AbortSignal | An AbortSignal that allows the caller of search to abort a search request. | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.signal.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.signal.md index 7da5c182b2e0f..948dfd66da7a0 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.signal.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchoptions.signal.md @@ -4,6 +4,8 @@ ## ISearchOptions.signal property +An `AbortSignal` that allows the caller of `search` to abort a search request. + Signature: ```typescript diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md new file mode 100644 index 0000000000000..93e253b2e98a3 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) + +## ISearchSetup interface + +Signature: + +```typescript +export interface ISearchSetup +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) | TRegisterSearchStrategy | Extension point exposed for other plugins to register their own search strategies. | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md new file mode 100644 index 0000000000000..c06b8b00806bf --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) > [registerSearchStrategy](./kibana-plugin-plugins-data-server.isearchsetup.registersearchstrategy.md) + +## ISearchSetup.registerSearchStrategy property + +Extension point exposed for other plugins to register their own search strategies. + +Signature: + +```typescript +registerSearchStrategy: TRegisterSearchStrategy; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md new file mode 100644 index 0000000000000..0ba4bf578d6cc --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md @@ -0,0 +1,13 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) > [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) + +## ISearchStart.getSearchStrategy property + +Get other registered search strategies. For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. + +Signature: + +```typescript +getSearchStrategy: TGetSearchStrategy; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md new file mode 100644 index 0000000000000..abe72396f61e1 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstart.md @@ -0,0 +1,18 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) + +## ISearchStart interface + +Signature: + +```typescript +export interface ISearchStart +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [getSearchStrategy](./kibana-plugin-plugins-data-server.isearchstart.getsearchstrategy.md) | TGetSearchStrategy | Get other registered search strategies. For example, if a new strategy needs to use the already-registered ES search strategy, it can use this function to accomplish that. | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.cancel.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.cancel.md new file mode 100644 index 0000000000000..c1e0c3d9f2330 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.cancel.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) > [cancel](./kibana-plugin-plugins-data-server.isearchstrategy.cancel.md) + +## ISearchStrategy.cancel property + +Signature: + +```typescript +cancel?: ISearchCancel; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md new file mode 100644 index 0000000000000..167c6ab6e5a16 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.md @@ -0,0 +1,21 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) + +## ISearchStrategy interface + +Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. + +Signature: + +```typescript +export interface ISearchStrategy +``` + +## Properties + +| Property | Type | Description | +| --- | --- | --- | +| [cancel](./kibana-plugin-plugins-data-server.isearchstrategy.cancel.md) | ISearchCancel<T> | | +| [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) | ISearch<T> | | + diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md new file mode 100644 index 0000000000000..34a17ca87807a --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.isearchstrategy.search.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) > [search](./kibana-plugin-plugins-data-server.isearchstrategy.search.md) + +## ISearchStrategy.search property + +Signature: + +```typescript +search: ISearch; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md index 0efbe8ed4ed64..f492ba2843a69 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.md @@ -39,10 +39,12 @@ | [IIndexPattern](./kibana-plugin-plugins-data-server.iindexpattern.md) | | | [IndexPatternAttributes](./kibana-plugin-plugins-data-server.indexpatternattributes.md) | Use data plugin interface instead | | [IndexPatternFieldDescriptor](./kibana-plugin-plugins-data-server.indexpatternfielddescriptor.md) | | -| [IRequestTypesMap](./kibana-plugin-plugins-data-server.irequesttypesmap.md) | | -| [IResponseTypesMap](./kibana-plugin-plugins-data-server.iresponsetypesmap.md) | | -| [ISearchContext](./kibana-plugin-plugins-data-server.isearchcontext.md) | | +| [IRequestTypesMap](./kibana-plugin-plugins-data-server.irequesttypesmap.md) | The map of search strategy IDs to the corresponding request type definitions. | +| [IResponseTypesMap](./kibana-plugin-plugins-data-server.iresponsetypesmap.md) | The map of search strategy IDs to the corresponding response type definitions. | | [ISearchOptions](./kibana-plugin-plugins-data-server.isearchoptions.md) | | +| [ISearchSetup](./kibana-plugin-plugins-data-server.isearchsetup.md) | | +| [ISearchStart](./kibana-plugin-plugins-data-server.isearchstart.md) | | +| [ISearchStrategy](./kibana-plugin-plugins-data-server.isearchstrategy.md) | Search strategy interface contains a search method that takes in a request and returns a promise that resolves to a response. | | [KueryNode](./kibana-plugin-plugins-data-server.kuerynode.md) | | | [PluginSetup](./kibana-plugin-plugins-data-server.pluginsetup.md) | | | [PluginStart](./kibana-plugin-plugins-data-server.pluginstart.md) | | @@ -73,5 +75,5 @@ | [ISearch](./kibana-plugin-plugins-data-server.isearch.md) | | | [ISearchCancel](./kibana-plugin-plugins-data-server.isearchcancel.md) | | | [ParsedInterval](./kibana-plugin-plugins-data-server.parsedinterval.md) | | -| [TSearchStrategyProvider](./kibana-plugin-plugins-data-server.tsearchstrategyprovider.md) | Search strategy provider creates an instance of a search strategy with the request handler context bound to it. This way every search strategy can use whatever information they require from the request context. | +| [TStrategyTypes](./kibana-plugin-plugins-data-server.tstrategytypes.md) | Contains all known strategy type identifiers that will be used to map to request and response shapes. Plugins that wish to add their own custom search strategies should extend this type via:const MY\_STRATEGY = 'MY\_STRATEGY';declare module 'src/plugins/search/server' { export interface IRequestTypesMap { \[MY\_STRATEGY\]: IMySearchRequest; }export interface IResponseTypesMap { \[MY\_STRATEGY\]: IMySearchResponse } } | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md index bd617990a00a2..13c69d6bf7548 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.setup.md @@ -7,11 +7,11 @@ Signature: ```typescript -setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { +setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { + search: ISearchSetup; fieldFormats: { register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; - search: ISearchSetup; }; ``` @@ -19,15 +19,15 @@ setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { | Parameter | Type | Description | | --- | --- | --- | -| core | CoreSetup | | +| core | CoreSetup<object, DataPluginStart> | | | { usageCollection } | DataPluginSetupDependencies | | Returns: `{ + search: ISearchSetup; fieldFormats: { register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; - search: ISearchSetup; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md index 2a30cd3e68158..2c7a833ab641b 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.plugin.start.md @@ -8,8 +8,9 @@ ```typescript start(core: CoreStart): { + search: ISearchStart; fieldFormats: { - fieldFormatServiceFactory: (uiSettings: import("kibana/server").IUiSettingsClient) => Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; }; ``` @@ -23,8 +24,9 @@ start(core: CoreStart): { Returns: `{ + search: ISearchStart; fieldFormats: { - fieldFormatServiceFactory: (uiSettings: import("kibana/server").IUiSettingsClient) => Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; }` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.md index b7d6a7e8a83fd..1377d82123d41 100644 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.md +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.md @@ -15,4 +15,5 @@ export interface DataPluginStart | Property | Type | Description | | --- | --- | --- | | [fieldFormats](./kibana-plugin-plugins-data-server.pluginstart.fieldformats.md) | FieldFormatsStart | | +| [search](./kibana-plugin-plugins-data-server.pluginstart.search.md) | ISearchStart | | diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.search.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.search.md new file mode 100644 index 0000000000000..3144d8c40b780 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.pluginstart.search.md @@ -0,0 +1,11 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [PluginStart](./kibana-plugin-plugins-data-server.pluginstart.md) > [search](./kibana-plugin-plugins-data-server.pluginstart.search.md) + +## PluginStart.search property + +Signature: + +```typescript +search: ISearchStart; +``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tsearchstrategyprovider.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tsearchstrategyprovider.md deleted file mode 100644 index f528f48a68f72..0000000000000 --- a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tsearchstrategyprovider.md +++ /dev/null @@ -1,13 +0,0 @@ - - -[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TSearchStrategyProvider](./kibana-plugin-plugins-data-server.tsearchstrategyprovider.md) - -## TSearchStrategyProvider type - -Search strategy provider creates an instance of a search strategy with the request handler context bound to it. This way every search strategy can use whatever information they require from the request context. - -Signature: - -```typescript -export declare type TSearchStrategyProvider = (context: ISearchContext, caller: APICaller, search: ISearchGeneric) => ISearchStrategy; -``` diff --git a/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tstrategytypes.md b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tstrategytypes.md new file mode 100644 index 0000000000000..443d8d1b424d0 --- /dev/null +++ b/docs/development/plugins/data/server/kibana-plugin-plugins-data-server.tstrategytypes.md @@ -0,0 +1,19 @@ + + +[Home](./index.md) > [kibana-plugin-plugins-data-server](./kibana-plugin-plugins-data-server.md) > [TStrategyTypes](./kibana-plugin-plugins-data-server.tstrategytypes.md) + +## TStrategyTypes type + +Contains all known strategy type identifiers that will be used to map to request and response shapes. Plugins that wish to add their own custom search strategies should extend this type via: + +const MY\_STRATEGY = 'MY\_STRATEGY'; + +declare module 'src/plugins/search/server' { export interface IRequestTypesMap { \[MY\_STRATEGY\]: IMySearchRequest; } + +export interface IResponseTypesMap { \[MY\_STRATEGY\]: IMySearchResponse } } + +Signature: + +```typescript +export declare type TStrategyTypes = typeof ES_SEARCH_STRATEGY | string; +``` diff --git a/examples/demo_search/server/async_demo_search_strategy.ts b/examples/demo_search/server/async_demo_search_strategy.ts index 7ed5062acba48..2eda0f4d09e11 100644 --- a/examples/demo_search/server/async_demo_search_strategy.ts +++ b/examples/demo_search/server/async_demo_search_strategy.ts @@ -17,30 +17,32 @@ * under the License. */ -import { TSearchStrategyProvider } from '../../../src/plugins/data/server'; -import { ASYNC_DEMO_SEARCH_STRATEGY } from '../common'; - -function getFibonacciSequence(n = 0) { - const beginning = [0, 1].slice(0, n); - return Array(Math.max(0, n)) - .fill(null) - .reduce((sequence, value, i) => { - if (i < 2) return sequence; - return [...sequence, sequence[i - 1] + sequence[i - 2]]; - }, beginning); -} - -const generateId = (() => { - let id = 0; - return () => `${id++}`; -})(); - -const loadedMap = new Map(); -const totalMap = new Map(); - -export const asyncDemoSearchStrategyProvider: TSearchStrategyProvider = () => { +import { ISearchStrategy } from '../../../src/plugins/data/server'; +import { ASYNC_DEMO_SEARCH_STRATEGY, IAsyncDemoRequest } from '../common'; + +export const asyncDemoSearchStrategyProvider = (): ISearchStrategy< + typeof ASYNC_DEMO_SEARCH_STRATEGY +> => { + function getFibonacciSequence(n = 0) { + const beginning = [0, 1].slice(0, n); + return Array(Math.max(0, n)) + .fill(null) + .reduce((sequence, value, i) => { + if (i < 2) return sequence; + return [...sequence, sequence[i - 1] + sequence[i - 2]]; + }, beginning); + } + + const generateId = (() => { + let id = 0; + return () => `${id++}`; + })(); + + const loadedMap = new Map(); + const totalMap = new Map(); + return { - search: async (request) => { + search: async (context, request: IAsyncDemoRequest) => { const id = request.id ?? generateId(); const loaded = (loadedMap.get(id) ?? 0) + 1; @@ -52,7 +54,7 @@ export const asyncDemoSearchStrategyProvider: TSearchStrategyProvider { + cancel: async (context, id) => { loadedMap.delete(id); totalMap.delete(id); }, diff --git a/examples/demo_search/server/demo_search_strategy.ts b/examples/demo_search/server/demo_search_strategy.ts index a1fd0e45dbc8e..36280ad22e83c 100644 --- a/examples/demo_search/server/demo_search_strategy.ts +++ b/examples/demo_search/server/demo_search_strategy.ts @@ -17,12 +17,12 @@ * under the License. */ -import { TSearchStrategyProvider } from '../../../src/plugins/data/server'; -import { DEMO_SEARCH_STRATEGY } from '../common'; +import { ISearchStrategy } from '../../../src/plugins/data/server'; +import { DEMO_SEARCH_STRATEGY, IDemoRequest } from '../common'; -export const demoSearchStrategyProvider: TSearchStrategyProvider = () => { +export const demoSearchStrategyProvider = (): ISearchStrategy => { return { - search: (request) => { + search: (context, request: IDemoRequest) => { return Promise.resolve({ greeting: request.mood === 'happy' diff --git a/examples/demo_search/server/index.ts b/examples/demo_search/server/index.ts index 6289b684b2b1e..368575b705c90 100644 --- a/examples/demo_search/server/index.ts +++ b/examples/demo_search/server/index.ts @@ -17,9 +17,6 @@ * under the License. */ -import { PluginInitializerContext, PluginInitializer } from 'kibana/server'; import { DemoDataPlugin } from './plugin'; -export const plugin: PluginInitializer = ( - initializerContext: PluginInitializerContext -) => new DemoDataPlugin(initializerContext); +export const plugin = () => new DemoDataPlugin(); diff --git a/examples/demo_search/server/plugin.ts b/examples/demo_search/server/plugin.ts index 49fbae43e3aa2..8a72b5007f988 100644 --- a/examples/demo_search/server/plugin.ts +++ b/examples/demo_search/server/plugin.ts @@ -17,7 +17,7 @@ * under the License. */ -import { Plugin, CoreSetup, PluginInitializerContext } from 'kibana/server'; +import { Plugin, CoreSetup } from 'kibana/server'; import { PluginSetup as DataPluginSetup } from 'src/plugins/data/server'; import { demoSearchStrategyProvider } from './demo_search_strategy'; import { @@ -56,18 +56,13 @@ declare module '../../../src/plugins/data/server' { } export class DemoDataPlugin implements Plugin { - constructor(private initializerContext: PluginInitializerContext) {} + constructor() {} public setup(core: CoreSetup, deps: IDemoSearchExplorerDeps) { - deps.data.search.registerSearchStrategyProvider( - this.initializerContext.opaqueId, - DEMO_SEARCH_STRATEGY, - demoSearchStrategyProvider - ); - deps.data.search.registerSearchStrategyProvider( - this.initializerContext.opaqueId, + deps.data.search.registerSearchStrategy(DEMO_SEARCH_STRATEGY, demoSearchStrategyProvider()); + deps.data.search.registerSearchStrategy( ASYNC_DEMO_SEARCH_STRATEGY, - asyncDemoSearchStrategyProvider + asyncDemoSearchStrategyProvider() ); } diff --git a/examples/search_explorer/public/search_api.tsx b/examples/search_explorer/public/search_api.tsx index c77ec725c6890..4a0e9afd20c85 100644 --- a/examples/search_explorer/public/search_api.tsx +++ b/examples/search_explorer/public/search_api.tsx @@ -23,11 +23,6 @@ import { GuideSection } from './guide_section'; import publicSearch from '!!raw-loader!./../../../src/plugins/data/public/search/i_search'; // @ts-ignore import publicPlugin from '!!raw-loader!./../../../src/plugins/data/public/search/search_service'; - -// @ts-ignore -import serverSetupContract from '!!raw-loader!./../../../src/plugins/data/server/search/i_search_setup'; -// @ts-ignore -import serverSearch from '!!raw-loader!./../../../src/plugins/data/server/search/i_search'; // @ts-ignore import serverPlugin from '!!raw-loader!./../../../src/plugins/data/server/search/search_service'; @@ -54,14 +49,6 @@ export const SearchApiPage = () => ( description: 'search_service.ts', snippet: serverPlugin, }, - { - description: `i_search_setup.ts`, - snippet: serverSetupContract, - }, - { - description: 'i_search', - snippet: serverSearch, - }, ], }, ]} diff --git a/src/plugins/data/server/search/i_route_handler_search_context.ts b/src/plugins/data/server/field_formats/mocks.ts similarity index 80% rename from src/plugins/data/server/search/i_route_handler_search_context.ts rename to src/plugins/data/server/field_formats/mocks.ts index 9888c774ea104..ecfa33c86cf16 100644 --- a/src/plugins/data/server/search/i_route_handler_search_context.ts +++ b/src/plugins/data/server/field_formats/mocks.ts @@ -17,9 +17,14 @@ * under the License. */ -import { ISearchGeneric, ISearchCancelGeneric } from './i_search'; +export function createFieldFormatsSetupMock() { + return { + register: jest.fn(), + }; +} -export interface IRouteHandlerSearchContext { - search: ISearchGeneric; - cancel: ISearchCancelGeneric; +export function createFieldFormatsStartMock() { + return { + fieldFormatServiceFactory: jest.fn(), + }; } diff --git a/src/plugins/data/server/index.ts b/src/plugins/data/server/index.ts index 831d23864d228..16ac59e300237 100644 --- a/src/plugins/data/server/index.ts +++ b/src/plugins/data/server/index.ts @@ -172,8 +172,10 @@ export { ISearchOptions, IRequestTypesMap, IResponseTypesMap, - ISearchContext, - TSearchStrategyProvider, + ISearchSetup, + ISearchStart, + TStrategyTypes, + ISearchStrategy, getDefaultSearchParams, getTotalLoaded, } from './search'; diff --git a/src/plugins/data/server/search/i_search_context.ts b/src/plugins/data/server/mocks.ts similarity index 60% rename from src/plugins/data/server/search/i_search_context.ts rename to src/plugins/data/server/mocks.ts index 9d9de055d994f..e2f2298234054 100644 --- a/src/plugins/data/server/search/i_search_context.ts +++ b/src/plugins/data/server/mocks.ts @@ -17,10 +17,24 @@ * under the License. */ -import { Observable } from 'rxjs'; -import { CoreSetup, SharedGlobalConfig } from '../../../../core/server'; +import { createSearchSetupMock, createSearchStartMock } from './search/mocks'; +import { createFieldFormatsSetupMock, createFieldFormatsStartMock } from './field_formats/mocks'; -export interface ISearchContext { - core: CoreSetup; - config$: Observable; +function createSetupContract() { + return { + search: createSearchSetupMock(), + fieldFormats: createFieldFormatsSetupMock(), + }; } + +function createStartContract() { + return { + search: createSearchStartMock(), + fieldFormats: createFieldFormatsStartMock(), + }; +} + +export const dataPluginMock = { + createSetupContract, + createStartContract, +}; diff --git a/src/plugins/data/server/plugin.ts b/src/plugins/data/server/plugin.ts index 8c9d0df2ed894..0edce458f1c6b 100644 --- a/src/plugins/data/server/plugin.ts +++ b/src/plugins/data/server/plugin.ts @@ -20,7 +20,7 @@ import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from '../../../core/server'; import { ConfigSchema } from '../config'; import { IndexPatternsService } from './index_patterns'; -import { ISearchSetup } from './search'; +import { ISearchSetup, ISearchStart } from './search'; import { SearchService } from './search/search_service'; import { QueryService } from './query/query_service'; import { ScriptsService } from './scripts'; @@ -36,6 +36,7 @@ export interface DataPluginSetup { } export interface DataPluginStart { + search: ISearchStart; fieldFormats: FieldFormatsStart; } @@ -59,7 +60,10 @@ export class DataServerPlugin implements Plugin, + { usageCollection }: DataPluginSetupDependencies + ) { this.indexPatterns.setup(core); this.scriptsService.setup(core); this.queryService.setup(core); @@ -69,13 +73,14 @@ export class DataServerPlugin implements Plugin Promise.resolve({ total: 100, loaded: 0 })); -const mockDefaultSearchStrategyProvider = jest.fn(() => - Promise.resolve({ - search: mockDefaultSearch, - }) -); -const mockStrategies: TSearchStrategiesMap = { - [DEFAULT_SEARCH_STRATEGY]: mockDefaultSearchStrategyProvider, -}; - -describe('createApi', () => { - let api: IRouteHandlerSearchContext; - - beforeEach(() => { - api = createApi({ - caller: jest.fn(), - searchStrategies: mockStrategies, - }); - mockDefaultSearchStrategyProvider.mockClear(); - }); - - it('should default to DEFAULT_SEARCH_STRATEGY if none is provided', async () => { - await api.search({ - params: {}, - }); - expect(mockDefaultSearchStrategyProvider).toBeCalled(); - expect(mockDefaultSearch).toBeCalled(); - }); - - it('should throw if no provider is found for the given name', () => { - expect(api.search({}, {}, 'noneByThisName')).rejects.toThrowErrorMatchingInlineSnapshot( - `"No strategy found for noneByThisName"` - ); - }); - - it('logs the response if `debug` is set to `true`', async () => { - const spy = jest.spyOn(console, 'log'); - await api.search({ params: {} }); - - expect(spy).not.toBeCalled(); - - await api.search({ debug: true, params: {} }); - - expect(spy).toBeCalled(); - }); -}); diff --git a/src/plugins/data/server/search/create_api.ts b/src/plugins/data/server/search/create_api.ts deleted file mode 100644 index 00665b21f2ba7..0000000000000 --- a/src/plugins/data/server/search/create_api.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { APICaller } from 'kibana/server'; -import { IRouteHandlerSearchContext } from './i_route_handler_search_context'; -import { DEFAULT_SEARCH_STRATEGY } from '../../common/search'; -import { TSearchStrategiesMap } from './i_search_strategy'; - -export function createApi({ - caller, - searchStrategies, -}: { - searchStrategies: TSearchStrategiesMap; - caller: APICaller; -}) { - const api: IRouteHandlerSearchContext = { - search: async (request, options, strategyName) => { - if (request.debug) { - // eslint-disable-next-line - console.log(JSON.stringify(request, null, 2)); - } - const name = strategyName ?? DEFAULT_SEARCH_STRATEGY; - const strategyProvider = searchStrategies[name]; - if (!strategyProvider) { - throw new Error(`No strategy found for ${strategyName}`); - } - // Give providers access to other search strategies by injecting this function - const strategy = await strategyProvider(caller, api.search); - return strategy.search(request, options); - }, - cancel: async (id, strategyName) => { - const name = strategyName ?? DEFAULT_SEARCH_STRATEGY; - const strategyProvider = searchStrategies[name]; - if (!strategyProvider) { - throw new Error(`No strategy found for ${strategyName}`); - } - const strategy = await strategyProvider(caller, api.search); - return strategy.cancel && strategy.cancel(id); - }, - }; - return api; -} diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.test.ts b/src/plugins/data/server/search/es_search/es_search_strategy.test.ts index c4b8119f9e095..1155a5491e8f3 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.test.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.test.ts @@ -17,11 +17,11 @@ * under the License. */ -import { coreMock, pluginInitializerContextConfigMock } from '../../../../../core/server/mocks'; +import { RequestHandlerContext } from '../../../../../core/server'; +import { pluginInitializerContextConfigMock } from '../../../../../core/server/mocks'; import { esSearchStrategyProvider } from './es_search_strategy'; describe('ES search strategy', () => { - const mockCoreSetup = coreMock.createSetup(); const mockApiCaller = jest.fn().mockResolvedValue({ _shards: { total: 10, @@ -30,39 +30,26 @@ describe('ES search strategy', () => { successful: 7, }, }); - const mockSearch = jest.fn(); + const mockContext = { + core: { elasticsearch: { legacy: { client: { callAsCurrentUser: mockApiCaller } } } }, + }; const mockConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; beforeEach(() => { mockApiCaller.mockClear(); - mockSearch.mockClear(); }); - it('returns a strategy with `search`', () => { - const esSearch = esSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + it('returns a strategy with `search`', async () => { + const esSearch = await esSearchStrategyProvider(mockConfig$); expect(typeof esSearch.search).toBe('function'); }); it('calls the API caller with the params with defaults', async () => { const params = { index: 'logstash-*' }; - const esSearch = esSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await esSearchStrategyProvider(mockConfig$); - await esSearch.search({ params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('search'); @@ -76,16 +63,9 @@ describe('ES search strategy', () => { it('calls the API caller with overridden defaults', async () => { const params = { index: 'logstash-*', ignoreUnavailable: false, timeout: '1000ms' }; - const esSearch = esSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await esSearchStrategyProvider(mockConfig$); - await esSearch.search({ params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('search'); @@ -97,16 +77,11 @@ describe('ES search strategy', () => { it('returns total, loaded, and raw response', async () => { const params = { index: 'logstash-*' }; - const esSearch = esSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await esSearchStrategyProvider(mockConfig$); - const response = await esSearch.search({ params }); + const response = await esSearch.search((mockContext as unknown) as RequestHandlerContext, { + params, + }); expect(response).toHaveProperty('total'); expect(response).toHaveProperty('loaded'); diff --git a/src/plugins/data/server/search/es_search/es_search_strategy.ts b/src/plugins/data/server/search/es_search/es_search_strategy.ts index 47cad7aa6b4d7..db08ddf920818 100644 --- a/src/plugins/data/server/search/es_search/es_search_strategy.ts +++ b/src/plugins/data/server/search/es_search/es_search_strategy.ts @@ -17,19 +17,18 @@ * under the License. */ import { first } from 'rxjs/operators'; -import { APICaller } from 'kibana/server'; +import { RequestHandlerContext, SharedGlobalConfig } from 'kibana/server'; import { SearchResponse } from 'elasticsearch'; +import { Observable } from 'rxjs'; import { ES_SEARCH_STRATEGY } from '../../../common/search'; -import { ISearchStrategy, TSearchStrategyProvider } from '../i_search_strategy'; -import { getDefaultSearchParams, getTotalLoaded, ISearchContext } from '..'; +import { ISearchStrategy, getDefaultSearchParams, getTotalLoaded } from '..'; -export const esSearchStrategyProvider: TSearchStrategyProvider = ( - context: ISearchContext, - caller: APICaller +export const esSearchStrategyProvider = ( + config$: Observable ): ISearchStrategy => { return { - search: async (request, options) => { - const config = await context.config$.pipe(first()).toPromise(); + search: async (context: RequestHandlerContext, request, options) => { + const config = await config$.pipe(first()).toPromise(); const defaultParams = getDefaultSearchParams(config); // Only default index pattern type is supported here. @@ -42,7 +41,12 @@ export const esSearchStrategyProvider: TSearchStrategyProvider; + + const rawResponse = (await context.core.elasticsearch.legacy.client.callAsCurrentUser( + 'search', + params, + options + )) as SearchResponse; // The above query will either complete or timeout and throw an error. // There is no progress indication on this api. diff --git a/src/plugins/data/server/search/i_search.ts b/src/plugins/data/server/search/i_search.ts deleted file mode 100644 index fa4aa72ac7287..0000000000000 --- a/src/plugins/data/server/search/i_search.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; -import { TStrategyTypes } from './strategy_types'; -import { ES_SEARCH_STRATEGY, IEsSearchResponse } from '../../common/search/es_search'; -import { IEsSearchRequest } from './es_search'; - -export interface ISearchOptions { - signal?: AbortSignal; -} - -export interface IRequestTypesMap { - [ES_SEARCH_STRATEGY]: IEsSearchRequest; - [key: string]: IKibanaSearchRequest; -} - -export interface IResponseTypesMap { - [ES_SEARCH_STRATEGY]: IEsSearchResponse; - [key: string]: IKibanaSearchResponse; -} - -export type ISearchGeneric = ( - request: IRequestTypesMap[T], - options?: ISearchOptions, - strategy?: T -) => Promise; - -export type ISearchCancelGeneric = ( - id: string, - strategy?: T -) => Promise; - -export type ISearch = ( - request: IRequestTypesMap[T], - options?: ISearchOptions -) => Promise; - -export type ISearchCancel = (id: string) => Promise; diff --git a/src/plugins/data/server/search/i_search_setup.ts b/src/plugins/data/server/search/i_search_setup.ts deleted file mode 100644 index e4a4d50141201..0000000000000 --- a/src/plugins/data/server/search/i_search_setup.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { IContextProvider } from 'kibana/server'; -import { ISearchContext } from './i_search_context'; -import { TRegisterSearchStrategyProvider, TSearchStrategyProvider } from './i_search_strategy'; - -/** - * The setup contract exposed by the Search plugin exposes the search strategy extension - * point. - */ -export interface ISearchSetup { - registerSearchStrategyContext: ( - pluginId: symbol, - strategyName: TContextName, - provider: IContextProvider, TContextName> - ) => void; - - /** - * Extension point exposed for other plugins to register their own search - * strategies. - */ - registerSearchStrategyProvider: TRegisterSearchStrategyProvider; -} diff --git a/src/plugins/data/server/search/i_search_strategy.ts b/src/plugins/data/server/search/i_search_strategy.ts deleted file mode 100644 index 9b405034f883f..0000000000000 --- a/src/plugins/data/server/search/i_search_strategy.ts +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { APICaller } from 'kibana/server'; -import { ISearch, ISearchCancel, ISearchGeneric } from './i_search'; -import { TStrategyTypes } from './strategy_types'; -import { ISearchContext } from './i_search_context'; - -/** - * Search strategy interface contains a search method that takes in - * a request and returns a promise that resolves to a response. - */ -export interface ISearchStrategy { - search: ISearch; - cancel?: ISearchCancel; -} - -/** - * Search strategy provider creates an instance of a search strategy with the request - * handler context bound to it. This way every search strategy can use - * whatever information they require from the request context. - */ -export type TSearchStrategyProviderEnhanced = ( - caller: APICaller, - search: ISearchGeneric -) => Promise>; - -/** - * Search strategy provider creates an instance of a search strategy with the request - * handler context bound to it. This way every search strategy can use - * whatever information they require from the request context. - */ -export type TSearchStrategyProvider = ( - context: ISearchContext, - caller: APICaller, - search: ISearchGeneric -) => ISearchStrategy; - -/** - * Extension point exposed for other plugins to register their own search - * strategies. - */ -export type TRegisterSearchStrategyProvider = ( - opaqueId: symbol, - name: T, - searchStrategyProvider: TSearchStrategyProvider -) => void; - -export type TSearchStrategiesMap = { - [K in TStrategyTypes]?: TSearchStrategyProviderEnhanced; -}; diff --git a/src/plugins/data/server/search/index.ts b/src/plugins/data/server/search/index.ts index e08eba1cad831..882f56e83d4ca 100644 --- a/src/plugins/data/server/search/index.ts +++ b/src/plugins/data/server/search/index.ts @@ -17,20 +17,16 @@ * under the License. */ -export { ISearchSetup } from './i_search_setup'; - -export { ISearchContext } from './i_search_context'; - export { ISearch, ISearchCancel, ISearchOptions, IRequestTypesMap, IResponseTypesMap, -} from './i_search'; - -export { TStrategyTypes } from './strategy_types'; - -export { TSearchStrategyProvider } from './i_search_strategy'; + ISearchSetup, + ISearchStart, + TStrategyTypes, + ISearchStrategy, +} from './types'; export { getDefaultSearchParams, getTotalLoaded } from './es_search'; diff --git a/src/plugins/data/server/search/mocks.ts b/src/plugins/data/server/search/mocks.ts index 136e7a1d580c9..0aab466a9a0d9 100644 --- a/src/plugins/data/server/search/mocks.ts +++ b/src/plugins/data/server/search/mocks.ts @@ -17,10 +17,14 @@ * under the License. */ -export const searchSetupMock = { - registerSearchStrategyContext: jest.fn(), - registerSearchStrategyProvider: jest.fn(), - __LEGACY: { - search: jest.fn(), - }, -}; +export function createSearchSetupMock() { + return { + registerSearchStrategy: jest.fn(), + }; +} + +export function createSearchStartMock() { + return { + getSearchStrategy: jest.fn(), + }; +} diff --git a/src/plugins/data/server/search/routes.test.ts b/src/plugins/data/server/search/routes.test.ts index f5e6507d977cd..4ef67de93e454 100644 --- a/src/plugins/data/server/search/routes.test.ts +++ b/src/plugins/data/server/search/routes.test.ts @@ -17,36 +17,26 @@ * under the License. */ -import { httpServiceMock, httpServerMock } from '../../../../../src/core/server/mocks'; +import { CoreSetup, RequestHandlerContext } from '../../../../../src/core/server'; +import { coreMock, httpServerMock } from '../../../../../src/core/server/mocks'; import { registerSearchRoute } from './routes'; -import { IRouter, ScopedClusterClient, RequestHandlerContext } from 'kibana/server'; +import { DataPluginStart } from '../plugin'; +import { dataPluginMock } from '../mocks'; describe('Search service', () => { - let routerMock: jest.Mocked; + let mockDataStart: MockedKeys; + let mockCoreSetup: MockedKeys>; beforeEach(() => { - routerMock = httpServiceMock.createRouter(); - }); - - it('registers a post route', async () => { - registerSearchRoute(routerMock); - expect(routerMock.post).toBeCalled(); + mockDataStart = dataPluginMock.createStartContract(); + mockCoreSetup = coreMock.createSetup({ pluginStartContract: mockDataStart }); }); it('handler calls context.search.search with the given request and strategy', async () => { const mockSearch = jest.fn().mockResolvedValue('yay'); - const mockContext = { - core: { - elasticsearch: { - legacy: { - client: {} as ScopedClusterClient, - }, - }, - }, - search: { - search: mockSearch, - }, - }; + mockDataStart.search.getSearchStrategy.mockReturnValueOnce({ search: mockSearch }); + + const mockContext = {}; const mockBody = { params: {} }; const mockParams = { strategy: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ @@ -55,13 +45,15 @@ describe('Search service', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerSearchRoute(routerMock); - const handler = routerMock.post.mock.calls[0][1]; + registerSearchRoute(mockCoreSetup); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.post.mock.calls[0][1]; await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + expect(mockDataStart.search.getSearchStrategy.mock.calls[0][0]).toBe(mockParams.strategy); expect(mockSearch).toBeCalled(); - expect(mockSearch.mock.calls[0][0]).toStrictEqual(mockBody); - expect(mockSearch.mock.calls[0][2]).toBe(mockParams.strategy); + expect(mockSearch.mock.calls[0][1]).toStrictEqual(mockBody); expect(mockResponse.ok).toBeCalled(); expect(mockResponse.ok.mock.calls[0][0]).toEqual({ body: 'yay' }); }); @@ -73,18 +65,9 @@ describe('Search service', () => { error: 'oops', }, }); - const mockContext = { - core: { - elasticsearch: { - legacy: { - client: {} as ScopedClusterClient, - }, - }, - }, - search: { - search: mockSearch, - }, - }; + mockDataStart.search.getSearchStrategy.mockReturnValueOnce({ search: mockSearch }); + + const mockContext = {}; const mockBody = { params: {} }; const mockParams = { strategy: 'foo' }; const mockRequest = httpServerMock.createKibanaRequest({ @@ -93,13 +76,15 @@ describe('Search service', () => { }); const mockResponse = httpServerMock.createResponseFactory(); - registerSearchRoute(routerMock); - const handler = routerMock.post.mock.calls[0][1]; + registerSearchRoute(mockCoreSetup); + + const mockRouter = mockCoreSetup.http.createRouter.mock.results[0].value; + const handler = mockRouter.post.mock.calls[0][1]; await handler((mockContext as unknown) as RequestHandlerContext, mockRequest, mockResponse); + expect(mockDataStart.search.getSearchStrategy.mock.calls[0][0]).toBe(mockParams.strategy); expect(mockSearch).toBeCalled(); - expect(mockSearch.mock.calls[0][0]).toStrictEqual(mockBody); - expect(mockSearch.mock.calls[0][2]).toBe(mockParams.strategy); + expect(mockSearch.mock.calls[0][1]).toStrictEqual(mockBody); expect(mockResponse.customError).toBeCalled(); const error: any = mockResponse.customError.mock.calls[0][0]; expect(error.body.message).toBe('oh no'); diff --git a/src/plugins/data/server/search/routes.ts b/src/plugins/data/server/search/routes.ts index b90d7d4ff80ce..7b6c045b0908c 100644 --- a/src/plugins/data/server/search/routes.ts +++ b/src/plugins/data/server/search/routes.ts @@ -18,10 +18,13 @@ */ import { schema } from '@kbn/config-schema'; -import { IRouter } from '../../../../core/server'; +import { CoreSetup } from '../../../../core/server'; import { getRequestAbortedSignal } from '../lib'; +import { DataPluginStart } from '../plugin'; + +export function registerSearchRoute(core: CoreSetup): void { + const router = core.http.createRouter(); -export function registerSearchRoute(router: IRouter): void { router.post( { path: '/internal/search/{strategy}', @@ -38,8 +41,11 @@ export function registerSearchRoute(router: IRouter): void { const { strategy } = request.params; const signal = getRequestAbortedSignal(request.events.aborted$); + const [, , selfStart] = await core.getStartServices(); + const searchStrategy = selfStart.search.getSearchStrategy(strategy); + try { - const response = await context.search!.search(searchRequest, { signal }, strategy); + const response = await searchStrategy.search(context, searchRequest, { signal }); return res.ok({ body: response }); } catch (err) { return res.customError({ @@ -69,8 +75,13 @@ export function registerSearchRoute(router: IRouter): void { }, async (context, request, res) => { const { strategy, id } = request.params; + + const [, , selfStart] = await core.getStartServices(); + const searchStrategy = selfStart.search.getSearchStrategy(strategy); + if (!searchStrategy.cancel) return res.ok(); + try { - await context.search!.cancel(id, strategy); + await searchStrategy.cancel(context, id); return res.ok(); } catch (err) { return res.customError({ diff --git a/src/plugins/data/server/search/search_service.test.ts b/src/plugins/data/server/search/search_service.test.ts index fa659756c1273..25143fa09e6bf 100644 --- a/src/plugins/data/server/search/search_service.test.ts +++ b/src/plugins/data/server/search/search_service.test.ts @@ -21,27 +21,28 @@ import { coreMock } from '../../../../core/server/mocks'; import { SearchService } from './search_service'; import { CoreSetup } from '../../../../core/server'; - -const mockSearchApi = { search: jest.fn() }; -jest.mock('./create_api', () => ({ - createApi: () => mockSearchApi, -})); +import { DataPluginStart } from '../plugin'; describe('Search service', () => { let plugin: SearchService; - let mockCoreSetup: MockedKeys; + let mockCoreSetup: MockedKeys>; beforeEach(() => { plugin = new SearchService(coreMock.createPluginInitializerContext({})); mockCoreSetup = coreMock.createSetup(); - mockSearchApi.search.mockClear(); }); describe('setup()', () => { it('exposes proper contract', async () => { const setup = plugin.setup(mockCoreSetup); - expect(setup).toHaveProperty('registerSearchStrategyContext'); - expect(setup).toHaveProperty('registerSearchStrategyProvider'); + expect(setup).toHaveProperty('registerSearchStrategy'); + }); + }); + + describe('start()', () => { + it('exposes proper contract', async () => { + const setup = plugin.start(); + expect(setup).toHaveProperty('getSearchStrategy'); }); }); }); diff --git a/src/plugins/data/server/search/search_service.ts b/src/plugins/data/server/search/search_service.ts index 1c267c32ebc37..df809b425eb9e 100644 --- a/src/plugins/data/server/search/search_service.ts +++ b/src/plugins/data/server/search/search_service.ts @@ -17,82 +17,52 @@ * under the License. */ +import { Plugin, PluginInitializerContext, CoreSetup } from '../../../../core/server'; import { - PluginInitializerContext, - Plugin, - CoreSetup, - IContextContainer, -} from '../../../../core/server'; -import { registerSearchRoute } from './routes'; -import { ISearchSetup } from './i_search_setup'; -import { createApi } from './create_api'; -import { + ISearchSetup, + ISearchStart, TSearchStrategiesMap, - TSearchStrategyProvider, - TRegisterSearchStrategyProvider, -} from './i_search_strategy'; -import { IRouteHandlerSearchContext } from './i_route_handler_search_context'; + TRegisterSearchStrategy, + TGetSearchStrategy, +} from './types'; +import { registerSearchRoute } from './routes'; import { ES_SEARCH_STRATEGY, esSearchStrategyProvider } from './es_search'; - import { searchSavedObjectType } from '../saved_objects'; +import { DataPluginStart } from '../plugin'; -declare module 'kibana/server' { - interface RequestHandlerContext { - search?: IRouteHandlerSearchContext; - } -} - -export class SearchService implements Plugin { +export class SearchService implements Plugin { private searchStrategies: TSearchStrategiesMap = {}; - private contextContainer?: IContextContainer>; - constructor(private initializerContext: PluginInitializerContext) {} - public setup(core: CoreSetup): ISearchSetup { - const router = core.http.createRouter(); - registerSearchRoute(router); - - this.contextContainer = core.context.createContextContainer(); - + public setup(core: CoreSetup): ISearchSetup { core.savedObjects.registerType(searchSavedObjectType); - core.http.registerRouteHandlerContext<'search'>('search', (context) => { - return createApi({ - caller: context.core.elasticsearch.legacy.client.callAsCurrentUser, - searchStrategies: this.searchStrategies, - }); - }); - - const registerSearchStrategyProvider: TRegisterSearchStrategyProvider = ( - plugin, - name, - strategyProvider - ) => { - this.searchStrategies[name] = this.contextContainer!.createHandler(plugin, strategyProvider); - }; - - const api: ISearchSetup = { - registerSearchStrategyContext: this.contextContainer!.registerContext, - registerSearchStrategyProvider, - }; - - api.registerSearchStrategyContext(this.initializerContext.opaqueId, 'core', () => core); - api.registerSearchStrategyContext( - this.initializerContext.opaqueId, - 'config$', - () => this.initializerContext.config.legacy.globalConfig$ - ); - - api.registerSearchStrategyProvider( - this.initializerContext.opaqueId, + this.registerSearchStrategy( ES_SEARCH_STRATEGY, - esSearchStrategyProvider + esSearchStrategyProvider(this.initializerContext.config.legacy.globalConfig$) ); - return api; + registerSearchRoute(core); + + return { registerSearchStrategy: this.registerSearchStrategy }; + } + + public start(): ISearchStart { + return { getSearchStrategy: this.getSearchStrategy }; } - public start() {} public stop() {} + + private registerSearchStrategy: TRegisterSearchStrategy = (name, strategy) => { + this.searchStrategies[name] = strategy; + }; + + private getSearchStrategy: TGetSearchStrategy = (name) => { + const strategy = this.searchStrategies[name]; + if (!strategy) { + throw new Error(`Search strategy ${name} not found`); + } + return strategy; + }; } diff --git a/src/plugins/data/server/search/strategy_types.ts b/src/plugins/data/server/search/strategy_types.ts deleted file mode 100644 index 252e0c8f9e6c9..0000000000000 --- a/src/plugins/data/server/search/strategy_types.ts +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { ES_SEARCH_STRATEGY } from '../../common/search/es_search'; - -/** - * Contains all known strategy type identifiers that will be used to map to - * request and response shapes. Plugins that wish to add their own custom search - * strategies should extend this type via: - * - * const MY_STRATEGY = 'MY_STRATEGY'; - * - * declare module 'src/plugins/search/server' { - * export interface IRequestTypesMap { - * [MY_STRATEGY]: IMySearchRequest; - * } - * - * export interface IResponseTypesMap { - * [MY_STRATEGY]: IMySearchResponse - * } - * } - */ -export type TStrategyTypes = typeof ES_SEARCH_STRATEGY | string; diff --git a/src/plugins/data/server/search/types.ts b/src/plugins/data/server/search/types.ts new file mode 100644 index 0000000000000..dea325cc063bb --- /dev/null +++ b/src/plugins/data/server/search/types.ts @@ -0,0 +1,111 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { RequestHandlerContext } from '../../../../core/server'; +import { IKibanaSearchResponse, IKibanaSearchRequest } from '../../common/search'; +import { ES_SEARCH_STRATEGY, IEsSearchRequest, IEsSearchResponse } from './es_search'; + +export interface ISearchSetup { + /** + * Extension point exposed for other plugins to register their own search + * strategies. + */ + registerSearchStrategy: TRegisterSearchStrategy; +} + +export interface ISearchStart { + /** + * Get other registered search strategies. For example, if a new strategy needs to use the + * already-registered ES search strategy, it can use this function to accomplish that. + */ + getSearchStrategy: TGetSearchStrategy; +} + +export interface ISearchOptions { + /** + * An `AbortSignal` that allows the caller of `search` to abort a search request. + */ + signal?: AbortSignal; +} + +/** + * Contains all known strategy type identifiers that will be used to map to + * request and response shapes. Plugins that wish to add their own custom search + * strategies should extend this type via: + * + * const MY_STRATEGY = 'MY_STRATEGY'; + * + * declare module 'src/plugins/search/server' { + * export interface IRequestTypesMap { + * [MY_STRATEGY]: IMySearchRequest; + * } + * + * export interface IResponseTypesMap { + * [MY_STRATEGY]: IMySearchResponse + * } + * } + */ +export type TStrategyTypes = typeof ES_SEARCH_STRATEGY | string; + +/** + * The map of search strategy IDs to the corresponding request type definitions. + */ +export interface IRequestTypesMap { + [ES_SEARCH_STRATEGY]: IEsSearchRequest; + [key: string]: IKibanaSearchRequest; +} + +/** + * The map of search strategy IDs to the corresponding response type definitions. + */ +export interface IResponseTypesMap { + [ES_SEARCH_STRATEGY]: IEsSearchResponse; + [key: string]: IKibanaSearchResponse; +} + +export type ISearch = ( + context: RequestHandlerContext, + request: IRequestTypesMap[T], + options?: ISearchOptions +) => Promise; + +export type ISearchCancel = ( + context: RequestHandlerContext, + id: string +) => Promise; + +/** + * Search strategy interface contains a search method that takes in a request and returns a promise + * that resolves to a response. + */ +export interface ISearchStrategy { + search: ISearch; + cancel?: ISearchCancel; +} + +export type TRegisterSearchStrategy = ( + name: T, + searchStrategy: ISearchStrategy +) => void; + +export type TGetSearchStrategy = (name: T) => ISearchStrategy; + +export type TSearchStrategiesMap = { + [K in TStrategyTypes]?: ISearchStrategy; +}; diff --git a/src/plugins/data/server/server.api.md b/src/plugins/data/server/server.api.md index 2d4185415b9d5..d825153a7aa12 100644 --- a/src/plugins/data/server/server.api.md +++ b/src/plugins/data/server/server.api.md @@ -48,7 +48,6 @@ import { GetResponse } from 'elasticsearch'; import { GetScriptParams } from 'elasticsearch'; import { GetSourceParams } from 'elasticsearch'; import { GetTemplateParams } from 'elasticsearch'; -import { IContextProvider as IContextProvider_2 } from 'kibana/server'; import { IncomingHttpHeaders } from 'http'; import { IndexDocumentParams } from 'elasticsearch'; import { IndicesAnalyzeParams } from 'elasticsearch'; @@ -490,7 +489,7 @@ export class IndexPatternsFetcher { // Warning: (ae-missing-release-tag) "IRequestTypesMap" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public export interface IRequestTypesMap { // Warning: (ae-forgotten-export) The symbol "IKibanaSearchRequest" needs to be exported by the entry point index.d.ts // @@ -505,7 +504,7 @@ export interface IRequestTypesMap { // Warning: (ae-missing-release-tag) "IResponseTypesMap" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // -// @public (undocumented) +// @public export interface IResponseTypesMap { // Warning: (ae-forgotten-export) The symbol "IKibanaSearchResponse" needs to be exported by the entry point index.d.ts // @@ -517,35 +516,48 @@ export interface IResponseTypesMap { [ES_SEARCH_STRATEGY]: IEsSearchResponse; } -// Warning: (ae-forgotten-export) The symbol "TStrategyTypes" needs to be exported by the entry point index.d.ts +// Warning: (ae-forgotten-export) The symbol "RequestHandlerContext" needs to be exported by the entry point index.d.ts // Warning: (ae-missing-release-tag) "ISearch" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type ISearch = (request: IRequestTypesMap[T], options?: ISearchOptions) => Promise; +export type ISearch = (context: RequestHandlerContext, request: IRequestTypesMap[T], options?: ISearchOptions) => Promise; // Warning: (ae-missing-release-tag) "ISearchCancel" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export type ISearchCancel = (id: string) => Promise; +export type ISearchCancel = (context: RequestHandlerContext, id: string) => Promise; -// Warning: (ae-missing-release-tag) "ISearchContext" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface ISearchContext { - // (undocumented) - config$: Observable; - // Warning: (ae-forgotten-export) The symbol "CoreSetup" needs to be exported by the entry point index.d.ts - // - // (undocumented) - core: CoreSetup; +export interface ISearchOptions { + signal?: AbortSignal; } -// Warning: (ae-missing-release-tag) "ISearchOptions" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "ISearchSetup" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public (undocumented) -export interface ISearchOptions { +export interface ISearchSetup { + // Warning: (ae-forgotten-export) The symbol "TRegisterSearchStrategy" needs to be exported by the entry point index.d.ts + registerSearchStrategy: TRegisterSearchStrategy; +} + +// Warning: (ae-missing-release-tag) "ISearchStart" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public (undocumented) +export interface ISearchStart { + // Warning: (ae-forgotten-export) The symbol "TGetSearchStrategy" needs to be exported by the entry point index.d.ts + getSearchStrategy: TGetSearchStrategy; +} + +// Warning: (ae-missing-release-tag) "ISearchStrategy" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// +// @public +export interface ISearchStrategy { // (undocumented) - signal?: AbortSignal; + cancel?: ISearchCancel; + // (undocumented) + search: ISearch; } // @public (undocumented) @@ -612,21 +624,23 @@ export function parseInterval(interval: string): moment.Duration | null; export class Plugin implements Plugin_2 { // Warning: (ae-forgotten-export) The symbol "PluginInitializerContext" needs to be exported by the entry point index.d.ts constructor(initializerContext: PluginInitializerContext); + // Warning: (ae-forgotten-export) The symbol "CoreSetup" needs to be exported by the entry point index.d.ts // Warning: (ae-forgotten-export) The symbol "DataPluginSetupDependencies" needs to be exported by the entry point index.d.ts // // (undocumented) - setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { + setup(core: CoreSetup, { usageCollection }: DataPluginSetupDependencies): { + search: ISearchSetup; fieldFormats: { register: (customFieldFormat: import("../public").FieldFormatInstanceType) => number; }; - search: ISearchSetup; }; // Warning: (ae-forgotten-export) The symbol "CoreStart" needs to be exported by the entry point index.d.ts // // (undocumented) start(core: CoreStart): { + search: ISearchStart; fieldFormats: { - fieldFormatServiceFactory: (uiSettings: import("kibana/server").IUiSettingsClient) => Promise; + fieldFormatServiceFactory: (uiSettings: import("../../../core/server").IUiSettingsClient) => Promise; }; }; // (undocumented) @@ -656,6 +670,8 @@ export interface PluginStart { // // (undocumented) fieldFormats: FieldFormatsStart; + // (undocumented) + search: ISearchStart; } // Warning: (ae-missing-release-tag) "Query" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) @@ -713,12 +729,10 @@ export interface TimeRange { to: string; } -// Warning: (ae-forgotten-export) The symbol "ISearchGeneric" needs to be exported by the entry point index.d.ts -// Warning: (ae-forgotten-export) The symbol "ISearchStrategy" needs to be exported by the entry point index.d.ts -// Warning: (ae-missing-release-tag) "TSearchStrategyProvider" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) +// Warning: (ae-missing-release-tag) "TStrategyTypes" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // // @public -export type TSearchStrategyProvider = (context: ISearchContext, caller: APICaller_2, search: ISearchGeneric) => ISearchStrategy; +export type TStrategyTypes = typeof ES_SEARCH_STRATEGY | string; // Warning: (ae-missing-release-tag) "UI_SETTINGS" is exported by the package, but it is missing a release tag (@alpha, @beta, @public, or @internal) // @@ -778,13 +792,12 @@ export const UI_SETTINGS: { // src/plugins/data/server/index.ts:103:26 - (ae-forgotten-export) The symbol "TruncateFormat" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:131:27 - (ae-forgotten-export) The symbol "isFilterable" needs to be exported by the entry point index.d.ts // src/plugins/data/server/index.ts:131:27 - (ae-forgotten-export) The symbol "isNestedField" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:184:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:185:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:186:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:187:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/index.ts:191:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts -// src/plugins/data/server/plugin.ts:66:14 - (ae-forgotten-export) The symbol "ISearchSetup" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:186:1 - (ae-forgotten-export) The symbol "dateHistogramInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:187:1 - (ae-forgotten-export) The symbol "InvalidEsCalendarIntervalError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:188:1 - (ae-forgotten-export) The symbol "InvalidEsIntervalFormatError" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:189:1 - (ae-forgotten-export) The symbol "isValidEsInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:190:1 - (ae-forgotten-export) The symbol "isValidInterval" needs to be exported by the entry point index.d.ts +// src/plugins/data/server/index.ts:193:1 - (ae-forgotten-export) The symbol "toAbsoluteDates" needs to be exported by the entry point index.d.ts // (No @packageDocumentation comment for this package) diff --git a/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts b/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts index cb3a24375607e..c9274c867df83 100644 --- a/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts +++ b/test/plugin_functional/test_suites/core_plugins/legacy_plugins.ts @@ -39,7 +39,7 @@ export default function ({ getService, getPageObjects }: PluginFunctionalProvide await supertest .get('/api/np-context-in-legacy') .expect(200) - .expect(JSON.stringify({ contexts: ['core', 'search', 'pluginA'] })); + .expect(JSON.stringify({ contexts: ['core', 'pluginA'] })); }); }); diff --git a/x-pack/plugins/data_enhanced/server/plugin.ts b/x-pack/plugins/data_enhanced/server/plugin.ts index a27a73431574b..4f6756231912c 100644 --- a/x-pack/plugins/data_enhanced/server/plugin.ts +++ b/x-pack/plugins/data_enhanced/server/plugin.ts @@ -22,10 +22,9 @@ export class EnhancedDataServerPlugin implements Plugin { - const mockCoreSetup = coreMock.createSetup(); const mockApiCaller = jest.fn(); - const mockSearch = jest.fn(); + const mockContext = { + core: { elasticsearch: { legacy: { client: { callAsCurrentUser: mockApiCaller } } } }, + }; const mockConfig$ = pluginInitializerContextConfigMock({}).legacy.globalConfig$; beforeEach(() => { mockApiCaller.mockClear(); - mockSearch.mockClear(); }); - it('returns a strategy with `search`', () => { - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + it('returns a strategy with `search`', async () => { + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); expect(typeof esSearch.search).toBe('function'); }); @@ -56,16 +50,9 @@ describe('ES search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { index: 'logstash-*', body: { query: {} } }; - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); - await esSearch.search({ params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('transport.request'); @@ -79,16 +66,9 @@ describe('ES search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { index: 'logstash-*', body: { query: {} } }; - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); - await esSearch.search({ id: 'foo', params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { id: 'foo', params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('transport.request'); @@ -102,16 +82,9 @@ describe('ES search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockAsyncResponse); const params = { index: 'foo-程', body: {} }; - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); - await esSearch.search({ params }); + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { params }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('transport.request'); @@ -124,16 +97,12 @@ describe('ES search strategy', () => { mockApiCaller.mockResolvedValueOnce(mockRollupResponse); const params = { index: 'foo-程', body: {} }; - const esSearch = enhancedEsSearchStrategyProvider( - { - core: mockCoreSetup, - config$: mockConfig$, - }, - mockApiCaller, - mockSearch - ); - - await esSearch.search({ indexType: 'rollup', params }); + const esSearch = await enhancedEsSearchStrategyProvider(mockConfig$); + + await esSearch.search((mockContext as unknown) as RequestHandlerContext, { + indexType: 'rollup', + params, + }); expect(mockApiCaller).toBeCalled(); expect(mockApiCaller.mock.calls[0][0]).toBe('transport.request'); diff --git a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts index 15f2ca10af7f7..9083ab24a4521 100644 --- a/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts +++ b/x-pack/plugins/data_enhanced/server/search/es_search_strategy.ts @@ -7,16 +7,16 @@ import { first } from 'rxjs/operators'; import { mapKeys, snakeCase } from 'lodash'; import { SearchResponse } from 'elasticsearch'; -import { APICaller } from '../../../../../src/core/server'; +import { Observable } from 'rxjs'; +import { APICaller, SharedGlobalConfig } from '../../../../../src/core/server'; import { ES_SEARCH_STRATEGY } from '../../../../../src/plugins/data/common'; import { - ISearchContext, - TSearchStrategyProvider, ISearch, ISearchOptions, ISearchCancel, getDefaultSearchParams, getTotalLoaded, + ISearchStrategy, } from '../../../../../src/plugins/data/server'; import { IEnhancedEsSearchRequest } from '../../common'; import { shimHitsTotal } from './shim_hits_total'; @@ -28,15 +28,16 @@ export interface AsyncSearchResponse { response: SearchResponse; } -export const enhancedEsSearchStrategyProvider: TSearchStrategyProvider = ( - context: ISearchContext, - caller: APICaller -) => { +export const enhancedEsSearchStrategyProvider = ( + config$: Observable +): ISearchStrategy => { const search: ISearch = async ( + context, request: IEnhancedEsSearchRequest, options ) => { - const config = await context.config$.pipe(first()).toPromise(); + const config = await config$.pipe(first()).toPromise(); + const caller = context.core.elasticsearch.legacy.client.callAsCurrentUser; const defaultParams = getDefaultSearchParams(config); const params = { ...defaultParams, ...request.params }; @@ -45,10 +46,13 @@ export const enhancedEsSearchStrategyProvider: TSearchStrategyProvider = async (id) => { + const cancel: ISearchCancel = async (context, id) => { const method = 'DELETE'; const path = encodeURI(`/_async_search/${id}`); - await caller('transport.request', { method, path }); + await context.core.elasticsearch.legacy.client.callAsCurrentUser('transport.request', { + method, + path, + }); }; return { search, cancel }; From 5c327a12ddce4d902a583e21fc1d40f411e64641 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 16 Jun 2020 13:45:20 -0700 Subject: [PATCH 13/41] [ci/getCheckoutInfo] retry fetching upstream changes to calculate mergeBase (#69320) Co-authored-by: spalger --- vars/getCheckoutInfo.groovy | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/vars/getCheckoutInfo.groovy b/vars/getCheckoutInfo.groovy index 7a3a7a9d2eccc..32a7b054bfd15 100644 --- a/vars/getCheckoutInfo.groovy +++ b/vars/getCheckoutInfo.groovy @@ -22,10 +22,14 @@ def call(branchOverride) { ).trim() if (repoInfo.targetBranch) { - sh( - script: "git fetch origin ${repoInfo.targetBranch}", - label: "fetch latest from '${repoInfo.targetBranch}' at origin" - ) + // Try to clone fetch from Github up to 8 times, waiting 15 secs between attempts + retryWithDelay(8, 15) { + sh( + script: "git fetch origin ${repoInfo.targetBranch}", + label: "fetch latest from '${repoInfo.targetBranch}' at origin" + ) + } + repoInfo.mergeBase = sh( script: "git merge-base HEAD FETCH_HEAD", label: "determining merge point with '${repoInfo.targetBranch}' at origin", From 885a42ca15f0ac954d2d5fef749892939c5894e6 Mon Sep 17 00:00:00 2001 From: Tre Date: Tue, 16 Jun 2020 14:59:26 -0600 Subject: [PATCH 14/41] [QA] [Code Coverage] Doc update (#69204) Co-authored-by: Elastic Machine --- .../kibana_code_coverage_index_mapping.md} | 10 +- .../ingest_code_coverage_readme.md | 15 +- ...qa_research_code_coverage_with_mapping.png | Bin 0 -> 829938 bytes .../qa_research_index_mapping.md | 193 ++++++++++++++++++ .../teams_scripted_field.painless | 0 5 files changed, 213 insertions(+), 5 deletions(-) rename src/dev/code_coverage/{ingest_coverage/index_mapping.md => docs/code_coverage_job/kibana_code_coverage_index_mapping.md} (97%) rename src/dev/code_coverage/{ingest_coverage => docs}/ingest_code_coverage_readme.md (52%) create mode 100644 src/dev/code_coverage/docs/qa_research_job/put_qa_research_code_coverage_with_mapping.png create mode 100644 src/dev/code_coverage/docs/qa_research_job/qa_research_index_mapping.md rename src/dev/code_coverage/{ingest_coverage => docs}/teams_scripted_field.painless (100%) diff --git a/src/dev/code_coverage/ingest_coverage/index_mapping.md b/src/dev/code_coverage/docs/code_coverage_job/kibana_code_coverage_index_mapping.md similarity index 97% rename from src/dev/code_coverage/ingest_coverage/index_mapping.md rename to src/dev/code_coverage/docs/code_coverage_job/kibana_code_coverage_index_mapping.md index c3b934eb35c5e..66654dd730518 100644 --- a/src/dev/code_coverage/ingest_coverage/index_mapping.md +++ b/src/dev/code_coverage/docs/code_coverage_job/kibana_code_coverage_index_mapping.md @@ -1,9 +1,12 @@ -# Create index mapping +# Index Mapping + +Execute the following in Kibana Dev Tools. -This is usually done in Kibana's dev tools ui. ``` - "mappings" : { +PUT /kibana_code_coverage +{ + "mappings" : { "properties" : { "@timestamp" : { "type" : "date" @@ -189,6 +192,7 @@ This is usually done in Kibana's dev tools ui. } } } +} ``` _The main portion of the above mapping, is the timestamp-date mapping._ \ No newline at end of file diff --git a/src/dev/code_coverage/ingest_coverage/ingest_code_coverage_readme.md b/src/dev/code_coverage/docs/ingest_code_coverage_readme.md similarity index 52% rename from src/dev/code_coverage/ingest_coverage/ingest_code_coverage_readme.md rename to src/dev/code_coverage/docs/ingest_code_coverage_readme.md index 0670780a7c03a..174f729180b77 100644 --- a/src/dev/code_coverage/ingest_coverage/ingest_code_coverage_readme.md +++ b/src/dev/code_coverage/docs/ingest_code_coverage_readme.md @@ -1,7 +1,18 @@ -# Convert Code Coverage Json Summary and Send to ES +# Massage and Ingest Code Coverage Json Summary and Send to ES +## Currently, we have 4 indexes +### 2 for the Code Coverage Job +https://kibana-ci.elastic.co/job/elastic+kibana+code-coverage/ +1. kibana_code_coverage +2. kibana_total_code_coverage + +### 2 for the R & D Job +https://kibana-ci.elastic.co/job/elastic+kibana+qa-research/ +1. qa_research_code_coverage +2. qa_research_total_code_coverage + ## How it works It starts with this jenkins pipeline file: @@ -19,6 +30,6 @@ From there, an event stream is created, that massages the data to an output form ## Configuration There is really only one config step. -The index [mapping](src/dev/code_coverage/ingest_coverage/index_mapping.md) for one of +The index [mapping](./code_coverage_job/kibana_code_coverage_index_mapping.md) for one of of the indexes has to be manually created. Currently, we just add it using Kibana's Dev Tools. \ No newline at end of file diff --git a/src/dev/code_coverage/docs/qa_research_job/put_qa_research_code_coverage_with_mapping.png b/src/dev/code_coverage/docs/qa_research_job/put_qa_research_code_coverage_with_mapping.png new file mode 100644 index 0000000000000000000000000000000000000000..c2e4ee4546dfcf08159c5a4a4ae3576e942d3ed1 GIT binary patch literal 829938 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 z

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%0DJ-z`D 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 literal 0 HcmV?d00001 diff --git a/src/dev/code_coverage/docs/qa_research_job/qa_research_index_mapping.md b/src/dev/code_coverage/docs/qa_research_job/qa_research_index_mapping.md new file mode 100644 index 0000000000000..746f81c761fcc --- /dev/null +++ b/src/dev/code_coverage/docs/qa_research_job/qa_research_index_mapping.md @@ -0,0 +1,193 @@ +``` +PUT /qa_research_code_coverage +{ + "mappings" : { + "properties" : { + "@timestamp" : { + "type" : "date" + }, + "BUILD_ID" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "branches" : { + "properties" : { + "covered" : { + "type" : "long" + }, + "pct" : { + "type" : "long" + }, + "skipped" : { + "type" : "long" + }, + "total" : { + "type" : "long" + } + } + }, + "ciRunUrl" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "coveredFilePath" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "functions" : { + "properties" : { + "covered" : { + "type" : "long" + }, + "pct" : { + "type" : "long" + }, + "skipped" : { + "type" : "long" + }, + "total" : { + "type" : "long" + } + } + }, + "isTotal" : { + "type" : "boolean" + }, + "jsonSummaryPath" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "lines" : { + "properties" : { + "covered" : { + "type" : "long" + }, + "pct" : { + "type" : "long" + }, + "skipped" : { + "type" : "long" + }, + "total" : { + "type" : "long" + } + } + }, + "path" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "statements" : { + "properties" : { + "covered" : { + "type" : "long" + }, + "pct" : { + "type" : "long" + }, + "skipped" : { + "type" : "long" + }, + "total" : { + "type" : "long" + } + } + }, + "staticSiteUrl" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "testRunnerType" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "vcs" : { + "properties" : { + "author" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "branch" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "commitMsg" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "sha" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + }, + "vcsUrl" : { + "type" : "text", + "fields" : { + "keyword" : { + "type" : "keyword", + "ignore_above" : 256 + } + } + } + } + } + } + } +} +``` + +Execute the above in Kibana Dev Tools, eg: ![Index Mapping Screenshot](./put_qa_research_code_coverage_with_mapping.png "QA Research Code Coverage Index Mapping") \ No newline at end of file diff --git a/src/dev/code_coverage/ingest_coverage/teams_scripted_field.painless b/src/dev/code_coverage/docs/teams_scripted_field.painless similarity index 100% rename from src/dev/code_coverage/ingest_coverage/teams_scripted_field.painless rename to src/dev/code_coverage/docs/teams_scripted_field.painless From beb0da1d58c609c86565ff23e8e541a056c39eb9 Mon Sep 17 00:00:00 2001 From: Brian Seeders Date: Tue, 16 Jun 2020 17:03:59 -0400 Subject: [PATCH 15/41] [CI] Fix packer cache git branch reference value (#69207) --- .ci/packer_cache.sh | 58 ++----------------------------- .ci/packer_cache_for_branch.sh | 62 ++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 56 deletions(-) create mode 100755 .ci/packer_cache_for_branch.sh diff --git a/.ci/packer_cache.sh b/.ci/packer_cache.sh index 11f9ccaeddb1e..e4b5e35e1e4a9 100755 --- a/.ci/packer_cache.sh +++ b/.ci/packer_cache.sh @@ -2,59 +2,5 @@ set -e -branch="$(git rev-parse --abbrev-ref HEAD 2> /dev/null)" - -# run setup script that gives us node, yarn, and bootstraps the project -source src/dev/ci_setup/setup.sh; - -# download es snapshots -node scripts/es snapshot --download-only; -node scripts/es snapshot --license=oss --download-only; - -# download reporting browsers -(cd "x-pack" && yarn gulp prepare); - -# cache the chromedriver archive -chromedriverDistVersion="$(node -e "console.log(require('chromedriver').version)")" -chromedriverPkgVersion="$(node -e "console.log(require('./package.json').devDependencies.chromedriver)")" -if [ -z "$chromedriverDistVersion" ] || [ -z "$chromedriverPkgVersion" ]; then - echo "UNABLE TO DETERMINE CHROMEDRIVER VERSIONS" - exit 1 -fi -mkdir -p .chromedriver -curl "https://chromedriver.storage.googleapis.com/$chromedriverDistVersion/chromedriver_linux64.zip" > .chromedriver/chromedriver.zip -echo "$chromedriverPkgVersion" > .chromedriver/pkgVersion - -# cache the geckodriver archive -geckodriverPkgVersion="$(node -e "console.log(require('./package.json').devDependencies.geckodriver)")" -if [ -z "$geckodriverPkgVersion" ]; then - echo "UNABLE TO DETERMINE geckodriver VERSIONS" - exit 1 -fi -mkdir -p ".geckodriver" -cp "node_modules/geckodriver/geckodriver.tar.gz" .geckodriver/geckodriver.tar.gz -echo "$geckodriverPkgVersion" > .geckodriver/pkgVersion - -echo "Creating bootstrap_cache archive" - -# archive cacheable directories -mkdir -p "$HOME/.kibana/bootstrap_cache" -tar -cf "$HOME/.kibana/bootstrap_cache/$branch.tar" \ - x-pack/plugins/reporting/.chromium \ - .es \ - .chromedriver \ - .geckodriver; - -echo "Adding node_modules" -# Find all of the node_modules directories that aren't test fixtures, and aren't inside other node_modules directories, and append them to the tar -find . -type d -name node_modules -not -path '*__fixtures__*' -prune -print0 | xargs -0I % tar -rf "$HOME/.kibana/bootstrap_cache/$branch.tar" "%" - -echo "created $HOME/.kibana/bootstrap_cache/$branch.tar" - -if [ "$branch" == "master" ]; then - echo "Creating bootstrap cache for 7.x"; - - git clone https://github.com/elastic/kibana.git --branch 7.x --depth 1 /tmp/kibana-7.x - (cd /tmp/kibana-7.x && ./.ci/packer_cache.sh); - rm -rf /tmp/kibana-7.x; -fi +./.ci/packer_cache_for_branch.sh master +./.ci/packer_cache_for_branch.sh 7.x diff --git a/.ci/packer_cache_for_branch.sh b/.ci/packer_cache_for_branch.sh new file mode 100755 index 0000000000000..a9fbe781915b6 --- /dev/null +++ b/.ci/packer_cache_for_branch.sh @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +set -e + +branch="$1" +checkoutDir="$(pwd)" + +if [[ "$branch" != "master" ]]; then + checkoutDir="/tmp/kibana-$branch" + git clone https://github.com/elastic/kibana.git --branch "$branch" --depth 1 "$checkoutDir" + cd "$checkoutDir" +fi + +source src/dev/ci_setup/setup.sh; + +# download es snapshots +node scripts/es snapshot --download-only; +node scripts/es snapshot --license=oss --download-only; + +# download reporting browsers +(cd "x-pack" && yarn gulp prepare); + +# cache the chromedriver archive +chromedriverDistVersion="$(node -e "console.log(require('chromedriver').version)")" +chromedriverPkgVersion="$(node -e "console.log(require('./package.json').devDependencies.chromedriver)")" +if [ -z "$chromedriverDistVersion" ] || [ -z "$chromedriverPkgVersion" ]; then + echo "UNABLE TO DETERMINE CHROMEDRIVER VERSIONS" + exit 1 +fi +mkdir -p .chromedriver +curl "https://chromedriver.storage.googleapis.com/$chromedriverDistVersion/chromedriver_linux64.zip" > .chromedriver/chromedriver.zip +echo "$chromedriverPkgVersion" > .chromedriver/pkgVersion + +# cache the geckodriver archive +geckodriverPkgVersion="$(node -e "console.log(require('./package.json').devDependencies.geckodriver)")" +if [ -z "$geckodriverPkgVersion" ]; then + echo "UNABLE TO DETERMINE geckodriver VERSIONS" + exit 1 +fi +mkdir -p ".geckodriver" +cp "node_modules/geckodriver/geckodriver.tar.gz" .geckodriver/geckodriver.tar.gz +echo "$geckodriverPkgVersion" > .geckodriver/pkgVersion + +echo "Creating bootstrap_cache archive" + +# archive cacheable directories +mkdir -p "$HOME/.kibana/bootstrap_cache" +tar -cf "$HOME/.kibana/bootstrap_cache/$branch.tar" \ + x-pack/plugins/reporting/.chromium \ + .es \ + .chromedriver \ + .geckodriver; + +echo "Adding node_modules" +# Find all of the node_modules directories that aren't test fixtures, and aren't inside other node_modules directories, and append them to the tar +find . -type d -name node_modules -not -path '*__fixtures__*' -prune -print0 | xargs -0I % tar -rf "$HOME/.kibana/bootstrap_cache/$branch.tar" "%" + +echo "created $HOME/.kibana/bootstrap_cache/$branch.tar" + +if [[ "$branch" != "master" ]]; then + rm --preserve-root -rf "$checkoutDir" +fi From 8b0efca3b20810085e02059d8b7a1c03df0386c5 Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 16 Jun 2020 14:14:09 -0700 Subject: [PATCH 16/41] [kbn/pm] only count cached project (#69113) Co-authored-by: spalger Co-authored-by: Elastic Machine --- packages/kbn-pm/dist/index.js | 2 +- packages/kbn-pm/src/commands/bootstrap.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/kbn-pm/dist/index.js b/packages/kbn-pm/dist/index.js index 1600d66ec7558..f6d008c9bf9be 100644 --- a/packages/kbn-pm/dist/index.js +++ b/packages/kbn-pm/dist/index.js @@ -8846,13 +8846,13 @@ const BootstrapCommand = { if (valid) { _utils_log__WEBPACK_IMPORTED_MODULE_1__["log"].debug(`[${project.name}] cache up to date`); + cachedProjectCount += 1; } caches.set(project, { file, valid }); - cachedProjectCount += 1; } } diff --git a/packages/kbn-pm/src/commands/bootstrap.ts b/packages/kbn-pm/src/commands/bootstrap.ts index 80ccc5daecc56..f8e50a8247856 100644 --- a/packages/kbn-pm/src/commands/bootstrap.ts +++ b/packages/kbn-pm/src/commands/bootstrap.ts @@ -74,10 +74,10 @@ export const BootstrapCommand: ICommand = { if (valid) { log.debug(`[${project.name}] cache up to date`); + cachedProjectCount += 1; } caches.set(project, { file, valid }); - cachedProjectCount += 1; } } From 8bc8837e347c7db923b0d442dda220ae412c670a Mon Sep 17 00:00:00 2001 From: Tim Sullivan Date: Tue, 16 Jun 2020 14:24:35 -0700 Subject: [PATCH 17/41] [Reporting] Prepare export type definitions for Task Manager (#65213) --- x-pack/plugins/reporting/public/plugin.tsx | 2 - .../common/execute_job/decrypt_job_headers.ts | 4 +- .../get_conditional_headers.test.ts | 16 +- .../execute_job/get_conditional_headers.ts | 4 +- .../execute_job/get_custom_logo.test.ts | 6 +- .../common/execute_job/get_custom_logo.ts | 4 +- .../common/execute_job/get_full_urls.test.ts | 8 +- .../common/execute_job/get_full_urls.ts | 20 +- .../execute_job/omit_blacklisted_headers.ts | 4 +- .../server/export_types/csv/index.ts | 14 +- .../export_types/csv/server/create_job.ts | 14 +- .../csv/server/execute_job.test.ts | 266 +++++++++--------- .../export_types/csv/server/execute_job.ts | 21 +- .../server/export_types/csv/types.d.ts | 4 +- .../csv_from_savedobject/index.ts | 12 +- .../server/create_job/create_job.ts | 106 ------- .../server/create_job/index.ts | 94 ++++++- .../server/execute_job.ts | 24 +- .../csv_from_savedobject/types.d.ts | 4 +- .../server/export_types/png/index.ts | 14 +- .../png/server/create_job/index.ts | 6 +- .../png/server/execute_job/index.test.ts | 24 +- .../png/server/execute_job/index.ts | 18 +- .../server/export_types/png/types.d.ts | 4 +- .../export_types/printable_pdf/index.ts | 14 +- .../printable_pdf/server/create_job/index.ts | 8 +- .../server/execute_job/index.test.ts | 24 +- .../printable_pdf/server/execute_job/index.ts | 18 +- .../export_types/printable_pdf/types.d.ts | 4 +- .../reporting/server/lib/create_queue.ts | 6 +- .../server/lib/create_worker.test.ts | 12 +- .../reporting/server/lib/create_worker.ts | 2 +- .../reporting/server/lib/enqueue_job.ts | 6 +- .../server/lib/export_types_registry.ts | 34 +-- .../generate_from_savedobject_immediate.ts | 22 +- .../server/routes/lib/get_document_payload.ts | 10 +- .../reporting/server/routes/types.d.ts | 4 +- x-pack/plugins/reporting/server/types.ts | 36 +-- 38 files changed, 423 insertions(+), 470 deletions(-) delete mode 100644 x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/create_job.ts diff --git a/x-pack/plugins/reporting/public/plugin.tsx b/x-pack/plugins/reporting/public/plugin.tsx index fcaa295a45ecc..aad3d9b026c6e 100644 --- a/x-pack/plugins/reporting/public/plugin.tsx +++ b/x-pack/plugins/reporting/public/plugin.tsx @@ -155,8 +155,6 @@ export class ReportingPublicPlugin implements Plugin { ); } - // FIXME: only perform these actions for authenticated routes - // Depends on https://github.com/elastic/kibana/pull/39477 public start(core: CoreStart) { const { http, notifications } = core; const apiClient = new ReportingAPIClient(http); diff --git a/x-pack/plugins/reporting/server/export_types/common/execute_job/decrypt_job_headers.ts b/x-pack/plugins/reporting/server/export_types/common/execute_job/decrypt_job_headers.ts index e5124c80601d7..579b5196ad4d9 100644 --- a/x-pack/plugins/reporting/server/export_types/common/execute_job/decrypt_job_headers.ts +++ b/x-pack/plugins/reporting/server/export_types/common/execute_job/decrypt_job_headers.ts @@ -14,14 +14,14 @@ interface HasEncryptedHeaders { // TODO merge functionality with CSV execute job export const decryptJobHeaders = async < JobParamsType, - JobDocPayloadType extends HasEncryptedHeaders + ScheduledTaskParamsType extends HasEncryptedHeaders >({ encryptionKey, job, logger, }: { encryptionKey?: string; - job: JobDocPayloadType; + job: ScheduledTaskParamsType; logger: LevelLogger; }): Promise> => { try { diff --git a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_conditional_headers.test.ts b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_conditional_headers.test.ts index 5d651ad5f8aea..030ced5dc4b80 100644 --- a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_conditional_headers.test.ts +++ b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_conditional_headers.test.ts @@ -8,8 +8,8 @@ import sinon from 'sinon'; import { ReportingConfig } from '../../../'; import { ReportingCore } from '../../../core'; import { createMockReportingCore } from '../../../test_helpers'; -import { JobDocPayload } from '../../../types'; -import { JobDocPayloadPDF } from '../../printable_pdf/types'; +import { ScheduledTaskParams } from '../../../types'; +import { ScheduledTaskParamsPDF } from '../../printable_pdf/types'; import { getConditionalHeaders, getCustomLogo } from './index'; let mockConfig: ReportingConfig; @@ -37,7 +37,7 @@ describe('conditions', () => { }; const conditionalHeaders = await getConditionalHeaders({ - job: {} as JobDocPayload, + job: {} as ScheduledTaskParams, filteredHeaders: permittedHeaders, config: mockConfig, }); @@ -64,14 +64,14 @@ test('uses basePath from job when creating saved object service', async () => { baz: 'quix', }; const conditionalHeaders = await getConditionalHeaders({ - job: {} as JobDocPayload, + job: {} as ScheduledTaskParams, filteredHeaders: permittedHeaders, config: mockConfig, }); const jobBasePath = '/sbp/s/marketing'; await getCustomLogo({ reporting: mockReportingPlugin, - job: { basePath: jobBasePath } as JobDocPayloadPDF, + job: { basePath: jobBasePath } as ScheduledTaskParamsPDF, conditionalHeaders, config: mockConfig, }); @@ -94,14 +94,14 @@ test(`uses basePath from server if job doesn't have a basePath when creating sav baz: 'quix', }; const conditionalHeaders = await getConditionalHeaders({ - job: {} as JobDocPayload, + job: {} as ScheduledTaskParams, filteredHeaders: permittedHeaders, config: mockConfig, }); await getCustomLogo({ reporting: mockReportingPlugin, - job: {} as JobDocPayloadPDF, + job: {} as ScheduledTaskParamsPDF, conditionalHeaders, config: mockConfig, }); @@ -139,7 +139,7 @@ describe('config formatting', () => { mockConfig = getMockConfig(mockConfigGet); const conditionalHeaders = await getConditionalHeaders({ - job: {} as JobDocPayload, + job: {} as ScheduledTaskParams, filteredHeaders: {}, config: mockConfig, }); diff --git a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_conditional_headers.ts b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_conditional_headers.ts index 6854f678aa975..7a50eaac80d85 100644 --- a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_conditional_headers.ts +++ b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_conditional_headers.ts @@ -7,13 +7,13 @@ import { ReportingConfig } from '../../../'; import { ConditionalHeaders } from '../../../types'; -export const getConditionalHeaders = ({ +export const getConditionalHeaders = ({ config, job, filteredHeaders, }: { config: ReportingConfig; - job: JobDocPayloadType; + job: ScheduledTaskParamsType; filteredHeaders: Record; }) => { const { kbnConfig } = config; diff --git a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_custom_logo.test.ts b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_custom_logo.test.ts index bd6eb4644d87f..c364752c8dd0f 100644 --- a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_custom_logo.test.ts +++ b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_custom_logo.test.ts @@ -6,7 +6,7 @@ import { ReportingCore } from '../../../core'; import { createMockReportingCore } from '../../../test_helpers'; -import { JobDocPayloadPDF } from '../../printable_pdf/types'; +import { ScheduledTaskParamsPDF } from '../../printable_pdf/types'; import { getConditionalHeaders, getCustomLogo } from './index'; const mockConfigGet = jest.fn().mockImplementation((key: string) => { @@ -37,7 +37,7 @@ test(`gets logo from uiSettings`, async () => { }); const conditionalHeaders = await getConditionalHeaders({ - job: {} as JobDocPayloadPDF, + job: {} as ScheduledTaskParamsPDF, filteredHeaders: permittedHeaders, config: mockConfig, }); @@ -45,7 +45,7 @@ test(`gets logo from uiSettings`, async () => { const { logo } = await getCustomLogo({ reporting: mockReportingPlugin, config: mockConfig, - job: {} as JobDocPayloadPDF, + job: {} as ScheduledTaskParamsPDF, conditionalHeaders, }); diff --git a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_custom_logo.ts b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_custom_logo.ts index 85d1272fc22ce..36c02eb47565c 100644 --- a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_custom_logo.ts +++ b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_custom_logo.ts @@ -7,7 +7,7 @@ import { ReportingConfig, ReportingCore } from '../../../'; import { UI_SETTINGS_CUSTOM_PDF_LOGO } from '../../../../common/constants'; import { ConditionalHeaders } from '../../../types'; -import { JobDocPayloadPDF } from '../../printable_pdf/types'; // Logo is PDF only +import { ScheduledTaskParamsPDF } from '../../printable_pdf/types'; // Logo is PDF only export const getCustomLogo = async ({ reporting, @@ -17,7 +17,7 @@ export const getCustomLogo = async ({ }: { reporting: ReportingCore; config: ReportingConfig; - job: JobDocPayloadPDF; + job: ScheduledTaskParamsPDF; conditionalHeaders: ConditionalHeaders; }) => { const serverBasePath: string = config.kbnConfig.get('server', 'basePath'); diff --git a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_full_urls.test.ts b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_full_urls.test.ts index cacea41477ea4..ad952c084d4f3 100644 --- a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_full_urls.test.ts +++ b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_full_urls.test.ts @@ -5,12 +5,12 @@ */ import { ReportingConfig } from '../../../'; -import { JobDocPayloadPNG } from '../../png/types'; -import { JobDocPayloadPDF } from '../../printable_pdf/types'; +import { ScheduledTaskParamsPNG } from '../../png/types'; +import { ScheduledTaskParamsPDF } from '../../printable_pdf/types'; import { getFullUrls } from './get_full_urls'; interface FullUrlsOpts { - job: JobDocPayloadPNG & JobDocPayloadPDF; + job: ScheduledTaskParamsPNG & ScheduledTaskParamsPDF; config: ReportingConfig; } @@ -35,7 +35,7 @@ beforeEach(() => { mockConfig = getMockConfig(mockConfigGet); }); -const getMockJob = (base: object) => base as JobDocPayloadPNG & JobDocPayloadPDF; +const getMockJob = (base: object) => base as ScheduledTaskParamsPNG & ScheduledTaskParamsPDF; test(`fails if no URL is passed`, async () => { const fn = () => getFullUrls({ job: getMockJob({}), config: mockConfig } as FullUrlsOpts); diff --git a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_full_urls.ts b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_full_urls.ts index bcd7f122748cb..67bc8d16fa758 100644 --- a/x-pack/plugins/reporting/server/export_types/common/execute_job/get_full_urls.ts +++ b/x-pack/plugins/reporting/server/export_types/common/execute_job/get_full_urls.ts @@ -13,22 +13,26 @@ import { import { ReportingConfig } from '../../..'; import { getAbsoluteUrlFactory } from '../../../../common/get_absolute_url'; import { validateUrls } from '../../../../common/validate_urls'; -import { JobDocPayloadPNG } from '../../png/types'; -import { JobDocPayloadPDF } from '../../printable_pdf/types'; +import { ScheduledTaskParamsPNG } from '../../png/types'; +import { ScheduledTaskParamsPDF } from '../../printable_pdf/types'; -function isPngJob(job: JobDocPayloadPNG | JobDocPayloadPDF): job is JobDocPayloadPNG { - return (job as JobDocPayloadPNG).relativeUrl !== undefined; +function isPngJob( + job: ScheduledTaskParamsPNG | ScheduledTaskParamsPDF +): job is ScheduledTaskParamsPNG { + return (job as ScheduledTaskParamsPNG).relativeUrl !== undefined; } -function isPdfJob(job: JobDocPayloadPNG | JobDocPayloadPDF): job is JobDocPayloadPDF { - return (job as JobDocPayloadPDF).relativeUrls !== undefined; +function isPdfJob( + job: ScheduledTaskParamsPNG | ScheduledTaskParamsPDF +): job is ScheduledTaskParamsPDF { + return (job as ScheduledTaskParamsPDF).relativeUrls !== undefined; } -export function getFullUrls({ +export function getFullUrls({ config, job, }: { config: ReportingConfig; - job: JobDocPayloadPDF | JobDocPayloadPNG; + job: ScheduledTaskParamsPDF | ScheduledTaskParamsPNG; }) { const [basePath, protocol, hostname, port] = [ config.kbnConfig.get('server', 'basePath'), diff --git a/x-pack/plugins/reporting/server/export_types/common/execute_job/omit_blacklisted_headers.ts b/x-pack/plugins/reporting/server/export_types/common/execute_job/omit_blacklisted_headers.ts index 5147881a980ea..db7137c30513b 100644 --- a/x-pack/plugins/reporting/server/export_types/common/execute_job/omit_blacklisted_headers.ts +++ b/x-pack/plugins/reporting/server/export_types/common/execute_job/omit_blacklisted_headers.ts @@ -9,11 +9,11 @@ import { KBN_SCREENSHOT_HEADER_BLACKLIST_STARTS_WITH_PATTERN, } from '../../../../common/constants'; -export const omitBlacklistedHeaders = ({ +export const omitBlacklistedHeaders = ({ job, decryptedHeaders, }: { - job: JobDocPayloadType; + job: ScheduledTaskParamsType; decryptedHeaders: Record; }) => { const filteredHeaders: Record = omit( diff --git a/x-pack/plugins/reporting/server/export_types/csv/index.ts b/x-pack/plugins/reporting/server/export_types/csv/index.ts index 8642a6d5758a8..b5eacdfc62c8b 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/index.ts @@ -15,21 +15,21 @@ import { import { CSV_JOB_TYPE as jobType } from '../../../constants'; import { ESQueueCreateJobFn, ESQueueWorkerExecuteFn, ExportTypeDefinition } from '../../types'; import { metadata } from './metadata'; -import { createJobFactory } from './server/create_job'; -import { executeJobFactory } from './server/execute_job'; -import { JobDocPayloadDiscoverCsv, JobParamsDiscoverCsv } from './types'; +import { scheduleTaskFnFactory } from './server/create_job'; +import { runTaskFnFactory } from './server/execute_job'; +import { JobParamsDiscoverCsv, ScheduledTaskParamsCSV } from './types'; export const getExportType = (): ExportTypeDefinition< JobParamsDiscoverCsv, ESQueueCreateJobFn, - JobDocPayloadDiscoverCsv, - ESQueueWorkerExecuteFn + ScheduledTaskParamsCSV, + ESQueueWorkerExecuteFn > => ({ ...metadata, jobType, jobContentExtension: 'csv', - createJobFactory, - executeJobFactory, + scheduleTaskFnFactory, + runTaskFnFactory, validLicenses: [ LICENSE_TYPE_TRIAL, LICENSE_TYPE_BASIC, diff --git a/x-pack/plugins/reporting/server/export_types/csv/server/create_job.ts b/x-pack/plugins/reporting/server/export_types/csv/server/create_job.ts index acf7f0505a735..c4fa1cd8e4fa6 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/server/create_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/server/create_job.ts @@ -4,24 +4,18 @@ * you may not use this file except in compliance with the Elastic License. */ -import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; -import { ReportingCore } from '../../../'; import { cryptoFactory } from '../../../lib'; -import { CreateJobFactory, ESQueueCreateJobFn } from '../../../types'; +import { ESQueueCreateJobFn, ScheduleTaskFnFactory } from '../../../types'; import { JobParamsDiscoverCsv } from '../types'; -export const createJobFactory: CreateJobFactory> = function createJobFactoryFn(reporting: ReportingCore) { +>> = function createJobFactoryFn(reporting) { const config = reporting.getConfig(); const crypto = cryptoFactory(config.get('encryptionKey')); const setupDeps = reporting.getPluginSetupDeps(); - return async function createJob( - jobParams: JobParamsDiscoverCsv, - context: RequestHandlerContext, - request: KibanaRequest - ) { + return async function scheduleTask(jobParams, context, request) { const serializedEncryptedHeaders = await crypto.encrypt(request.headers); const savedObjectsClient = context.core.savedObjects.client; diff --git a/x-pack/plugins/reporting/server/export_types/csv/server/execute_job.test.ts b/x-pack/plugins/reporting/server/export_types/csv/server/execute_job.test.ts index 4ce448e953bd1..d1297454971c7 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/server/execute_job.test.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/server/execute_job.test.ts @@ -20,8 +20,8 @@ import { CSV_BOM_CHARS } from '../../../../common/constants'; import { LevelLogger } from '../../../lib'; import { setFieldFormats } from '../../../services'; import { createMockReportingCore } from '../../../test_helpers'; -import { JobDocPayloadDiscoverCsv } from '../types'; -import { executeJobFactory } from './execute_job'; +import { ScheduledTaskParamsCSV } from '../types'; +import { runTaskFnFactory } from './execute_job'; const delay = (ms: number) => new Promise((resolve) => setTimeout(() => resolve(), ms)); @@ -30,7 +30,7 @@ const getRandomScrollId = () => { return puid.generate(); }; -const getJobDocPayload = (baseObj: any) => baseObj as JobDocPayloadDiscoverCsv; +const getScheduledTaskParams = (baseObj: any) => baseObj as ScheduledTaskParamsCSV; describe('CSV Execute Job', function () { const encryptionKey = 'testEncryptionKey'; @@ -125,10 +125,10 @@ describe('CSV Execute Job', function () { describe('basic Elasticsearch call behavior', function () { it('should decrypt encrypted headers and pass to callAsCurrentUser', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - await executeJob( + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + await runTask( 'job456', - getJobDocPayload({ + getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, @@ -145,8 +145,8 @@ describe('CSV Execute Job', function () { testBody: true, }; - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const job = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const job = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { @@ -155,7 +155,7 @@ describe('CSV Execute Job', function () { }, }); - await executeJob('job777', job, cancellationToken); + await runTask('job777', job, cancellationToken); const searchCall = callAsCurrentUserStub.firstCall; expect(searchCall.args[0]).toBe('search'); @@ -172,10 +172,10 @@ describe('CSV Execute Job', function () { _scroll_id: scrollId, }); callAsCurrentUserStub.onSecondCall().resolves(defaultElasticsearchResponse); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - await executeJob( + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + await runTask( 'job456', - getJobDocPayload({ + getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, @@ -190,10 +190,10 @@ describe('CSV Execute Job', function () { }); it('should not execute scroll if there are no hits from the search', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - await executeJob( + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + await runTask( 'job456', - getJobDocPayload({ + getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, @@ -224,10 +224,10 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - await executeJob( + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + await runTask( 'job456', - getJobDocPayload({ + getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, @@ -263,10 +263,10 @@ describe('CSV Execute Job', function () { _scroll_id: lastScrollId, }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - await executeJob( + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + await runTask( 'job456', - getJobDocPayload({ + getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, @@ -295,16 +295,16 @@ describe('CSV Execute Job', function () { _scroll_id: lastScrollId, }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: undefined, searchRequest: { index: null, body: null }, }); - await expect( - executeJob('job123', jobParams, cancellationToken) - ).rejects.toMatchInlineSnapshot(`[TypeError: Cannot read property 'indexOf' of undefined]`); + await expect(runTask('job123', jobParams, cancellationToken)).rejects.toMatchInlineSnapshot( + `[TypeError: Cannot read property 'indexOf' of undefined]` + ); const lastCall = callAsCurrentUserStub.getCall(callAsCurrentUserStub.callCount - 1); expect(lastCall.args[0]).toBe('clearScroll'); @@ -322,14 +322,14 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { csv_contains_formulas: csvContainsFormulas } = await executeJob( + const { csv_contains_formulas: csvContainsFormulas } = await runTask( 'job123', jobParams, cancellationToken @@ -347,14 +347,14 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['=SUM(A1:A2)', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { csv_contains_formulas: csvContainsFormulas } = await executeJob( + const { csv_contains_formulas: csvContainsFormulas } = await runTask( 'job123', jobParams, cancellationToken @@ -373,14 +373,14 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { csv_contains_formulas: csvContainsFormulas } = await executeJob( + const { csv_contains_formulas: csvContainsFormulas } = await runTask( 'job123', jobParams, cancellationToken @@ -399,15 +399,15 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['=SUM(A1:A2)', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { csv_contains_formulas: csvContainsFormulas } = await executeJob( + const { csv_contains_formulas: csvContainsFormulas } = await runTask( 'job123', jobParams, cancellationToken @@ -425,14 +425,14 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { csv_contains_formulas: csvContainsFormulas } = await executeJob( + const { csv_contains_formulas: csvContainsFormulas } = await runTask( 'job123', jobParams, cancellationToken @@ -452,14 +452,14 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); expect(content).toEqual(`${CSV_BOM_CHARS}one,two\none,bar\n`); }); @@ -473,14 +473,14 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); expect(content).toEqual('one,two\none,bar\n'); }); @@ -496,14 +496,14 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); expect(content).toEqual("one,two\n\"'=cmd|' /C calc'!A0\",bar\n"); }); @@ -517,14 +517,14 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); expect(content).toEqual('one,two\n"=cmd|\' /C calc\'!A0",bar\n'); }); @@ -533,15 +533,15 @@ describe('CSV Execute Job', function () { describe('Elasticsearch call errors', function () { it('should reject Promise if search call errors out', async function () { callAsCurrentUserStub.rejects(new Error()); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, }); - await expect( - executeJob('job123', jobParams, cancellationToken) - ).rejects.toMatchInlineSnapshot(`[Error]`); + await expect(runTask('job123', jobParams, cancellationToken)).rejects.toMatchInlineSnapshot( + `[Error]` + ); }); it('should reject Promise if scroll call errors out', async function () { @@ -552,15 +552,15 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); callAsCurrentUserStub.onSecondCall().rejects(new Error()); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, }); - await expect( - executeJob('job123', jobParams, cancellationToken) - ).rejects.toMatchInlineSnapshot(`[Error]`); + await expect(runTask('job123', jobParams, cancellationToken)).rejects.toMatchInlineSnapshot( + `[Error]` + ); }); }); @@ -573,15 +573,13 @@ describe('CSV Execute Job', function () { _scroll_id: undefined, }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, }); - await expect( - executeJob('job123', jobParams, cancellationToken) - ).rejects.toMatchInlineSnapshot( + await expect(runTask('job123', jobParams, cancellationToken)).rejects.toMatchInlineSnapshot( `[Error: Expected _scroll_id in the following Elasticsearch response: {"hits":{"hits":[{}]}}]` ); }); @@ -594,15 +592,13 @@ describe('CSV Execute Job', function () { _scroll_id: undefined, }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, }); - await expect( - executeJob('job123', jobParams, cancellationToken) - ).rejects.toMatchInlineSnapshot( + await expect(runTask('job123', jobParams, cancellationToken)).rejects.toMatchInlineSnapshot( `[Error: Expected _scroll_id in the following Elasticsearch response: {"hits":{"hits":[]}}]` ); }); @@ -622,15 +618,13 @@ describe('CSV Execute Job', function () { _scroll_id: undefined, }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, }); - await expect( - executeJob('job123', jobParams, cancellationToken) - ).rejects.toMatchInlineSnapshot( + await expect(runTask('job123', jobParams, cancellationToken)).rejects.toMatchInlineSnapshot( `[Error: Expected _scroll_id in the following Elasticsearch response: {"hits":{"hits":[{}]}}]` ); }); @@ -650,15 +644,13 @@ describe('CSV Execute Job', function () { _scroll_id: undefined, }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, }); - await expect( - executeJob('job123', jobParams, cancellationToken) - ).rejects.toMatchInlineSnapshot( + await expect(runTask('job123', jobParams, cancellationToken)).rejects.toMatchInlineSnapshot( `[Error: Expected _scroll_id in the following Elasticsearch response: {"hits":{"hits":[]}}]` ); }); @@ -686,10 +678,10 @@ describe('CSV Execute Job', function () { }); it('should stop calling Elasticsearch when cancellationToken.cancel is called', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - executeJob( + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + runTask( 'job345', - getJobDocPayload({ + getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, @@ -705,10 +697,10 @@ describe('CSV Execute Job', function () { }); it(`shouldn't call clearScroll if it never got a scrollId`, async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - executeJob( + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + runTask( 'job345', - getJobDocPayload({ + getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, @@ -723,10 +715,10 @@ describe('CSV Execute Job', function () { }); it('should call clearScroll if it got a scrollId', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - executeJob( + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + runTask( 'job345', - getJobDocPayload({ + getScheduledTaskParams({ headers: encryptedHeaders, fields: [], searchRequest: { index: null, body: null }, @@ -745,54 +737,54 @@ describe('CSV Execute Job', function () { describe('csv content', function () { it('should write column headers to output, even if there are no results', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); expect(content).toBe(`one,two\n`); }); it('should use custom uiSettings csv:separator for header', async function () { mockUiSettingsClient.get.withArgs(CSV_SEPARATOR_SETTING).returns(';'); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); expect(content).toBe(`one;two\n`); }); it('should escape column headers if uiSettings csv:quoteValues is true', async function () { mockUiSettingsClient.get.withArgs(CSV_QUOTE_VALUES_SETTING).returns(true); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one and a half', 'two', 'three-and-four', 'five & six'], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); expect(content).toBe(`"one and a half",two,"three-and-four","five & six"\n`); }); it(`shouldn't escape column headers if uiSettings csv:quoteValues is false`, async function () { mockUiSettingsClient.get.withArgs(CSV_QUOTE_VALUES_SETTING).returns(false); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one and a half', 'two', 'three-and-four', 'five & six'], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); expect(content).toBe(`one and a half,two,three-and-four,five & six\n`); }); it('should write column headers to output, when there are results', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ one: '1', two: '2' }], @@ -800,19 +792,19 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const jobParams = getJobDocPayload({ + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); const lines = content.split('\n'); const headerLine = lines[0]; expect(headerLine).toBe('one,two'); }); it('should use comma separated values of non-nested fields from _source', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -820,20 +812,20 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const jobParams = getJobDocPayload({ + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); const lines = content.split('\n'); const valuesLine = lines[1]; expect(valuesLine).toBe('foo,bar'); }); it('should concatenate the hits from multiple responses', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -847,13 +839,13 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const jobParams = getJobDocPayload({ + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); const lines = content.split('\n'); expect(lines[1]).toBe('foo,bar'); @@ -861,7 +853,7 @@ describe('CSV Execute Job', function () { }); it('should use field formatters to format fields', async function () { - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); callAsCurrentUserStub.onFirstCall().resolves({ hits: { hits: [{ _source: { one: 'foo', two: 'bar' } }], @@ -869,7 +861,7 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const jobParams = getJobDocPayload({ + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], @@ -884,7 +876,7 @@ describe('CSV Execute Job', function () { }, }, }); - const { content } = await executeJob('job123', jobParams, cancellationToken); + const { content } = await runTask('job123', jobParams, cancellationToken); const lines = content.split('\n'); expect(lines[1]).toBe('FOO,bar'); @@ -903,14 +895,14 @@ describe('CSV Execute Job', function () { beforeEach(async function () { configGetStub.withArgs('csv', 'maxSizeBytes').returns(1); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], searchRequest: { index: null, body: null }, }); - ({ content, max_size_reached: maxSizeReached } = await executeJob( + ({ content, max_size_reached: maxSizeReached } = await runTask( 'job123', jobParams, cancellationToken @@ -933,14 +925,14 @@ describe('CSV Execute Job', function () { beforeEach(async function () { configGetStub.withArgs('csv', 'maxSizeBytes').returns(9); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], searchRequest: { index: null, body: null }, }); - ({ content, max_size_reached: maxSizeReached } = await executeJob( + ({ content, max_size_reached: maxSizeReached } = await runTask( 'job123', jobParams, cancellationToken @@ -970,15 +962,15 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - ({ content, max_size_reached: maxSizeReached } = await executeJob( + ({ content, max_size_reached: maxSizeReached } = await runTask( 'job123', jobParams, cancellationToken @@ -1010,15 +1002,15 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - ({ content, max_size_reached: maxSizeReached } = await executeJob( + ({ content, max_size_reached: maxSizeReached } = await runTask( 'job123', jobParams, cancellationToken @@ -1047,15 +1039,15 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - await executeJob('job123', jobParams, cancellationToken); + await runTask('job123', jobParams, cancellationToken); const searchCall = callAsCurrentUserStub.firstCall; expect(searchCall.args[0]).toBe('search'); @@ -1073,15 +1065,15 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - await executeJob('job123', jobParams, cancellationToken); + await runTask('job123', jobParams, cancellationToken); const searchCall = callAsCurrentUserStub.firstCall; expect(searchCall.args[0]).toBe('search'); @@ -1099,15 +1091,15 @@ describe('CSV Execute Job', function () { _scroll_id: 'scrollId', }); - const executeJob = await executeJobFactory(mockReportingCore, mockLogger); - const jobParams = getJobDocPayload({ + const runTask = await runTaskFnFactory(mockReportingCore, mockLogger); + const jobParams = getScheduledTaskParams({ headers: encryptedHeaders, fields: ['one', 'two'], conflictedTypesFields: [], searchRequest: { index: null, body: null }, }); - await executeJob('job123', jobParams, cancellationToken); + await runTask('job123', jobParams, cancellationToken); const scrollCall = callAsCurrentUserStub.secondCall; expect(scrollCall.args[0]).toBe('scroll'); diff --git a/x-pack/plugins/reporting/server/export_types/csv/server/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv/server/execute_job.ts index 91a4db0469fb5..89fd014502f74 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/server/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/server/execute_job.ts @@ -8,31 +8,26 @@ import { i18n } from '@kbn/i18n'; import Hapi from 'hapi'; import { IUiSettingsClient, KibanaRequest } from '../../../../../../../src/core/server'; import { - CSV_SEPARATOR_SETTING, CSV_QUOTE_VALUES_SETTING, + CSV_SEPARATOR_SETTING, } from '../../../../../../../src/plugins/share/server'; -import { ReportingCore } from '../../..'; import { CSV_BOM_CHARS, CSV_JOB_TYPE } from '../../../../common/constants'; import { getFieldFormats } from '../../../../server/services'; -import { cryptoFactory, LevelLogger } from '../../../lib'; -import { ESQueueWorkerExecuteFn, ExecuteJobFactory } from '../../../types'; -import { JobDocPayloadDiscoverCsv } from '../types'; +import { cryptoFactory } from '../../../lib'; +import { ESQueueWorkerExecuteFn, RunTaskFnFactory } from '../../../types'; +import { ScheduledTaskParamsCSV } from '../types'; import { fieldFormatMapFactory } from './lib/field_format_map'; import { createGenerateCsv } from './lib/generate_csv'; -export const executeJobFactory: ExecuteJobFactory> = async function executeJobFactoryFn(reporting: ReportingCore, parentLogger: LevelLogger) { +export const runTaskFnFactory: RunTaskFnFactory> = function executeJobFactoryFn(reporting, parentLogger) { const config = reporting.getConfig(); const crypto = cryptoFactory(config.get('encryptionKey')); const logger = parentLogger.clone([CSV_JOB_TYPE, 'execute-job']); const serverBasePath = config.kbnConfig.get('server', 'basePath'); - return async function executeJob( - jobId: string, - job: JobDocPayloadDiscoverCsv, - cancellationToken: any - ) { + return async function runTask(jobId, job, cancellationToken) { const elasticsearch = reporting.getElasticsearchService(); const jobLogger = logger.clone([jobId]); diff --git a/x-pack/plugins/reporting/server/export_types/csv/types.d.ts b/x-pack/plugins/reporting/server/export_types/csv/types.d.ts index c80cd5fd24fe5..ab3e114c7c995 100644 --- a/x-pack/plugins/reporting/server/export_types/csv/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/csv/types.d.ts @@ -5,7 +5,7 @@ */ import { CancellationToken } from '../../../common'; -import { JobParamPostPayload, JobDocPayload, ScrollConfig } from '../../types'; +import { JobParamPostPayload, ScheduledTaskParams, ScrollConfig } from '../../types'; export type RawValue = string | object | null | undefined; @@ -32,7 +32,7 @@ export interface JobParamsDiscoverCsv { post?: JobParamPostPayloadDiscoverCsv; } -export interface JobDocPayloadDiscoverCsv extends JobDocPayload { +export interface ScheduledTaskParamsCSV extends ScheduledTaskParams { basePath: string; searchRequest: any; fields: any; diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts index 65802ee5bb7fb..961a046c846e4 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/index.ts @@ -15,16 +15,16 @@ import { import { CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../constants'; import { ExportTypeDefinition } from '../../types'; import { metadata } from './metadata'; -import { createJobFactory, ImmediateCreateJobFn } from './server/create_job'; -import { executeJobFactory, ImmediateExecuteFn } from './server/execute_job'; +import { ImmediateCreateJobFn, scheduleTaskFnFactory } from './server/create_job'; +import { ImmediateExecuteFn, runTaskFnFactory } from './server/execute_job'; import { JobParamsPanelCsv } from './types'; /* * These functions are exported to share with the API route handler that * generates csv from saved object immediately on request. */ -export { createJobFactory } from './server/create_job'; -export { executeJobFactory } from './server/execute_job'; +export { scheduleTaskFnFactory } from './server/create_job'; +export { runTaskFnFactory } from './server/execute_job'; export const getExportType = (): ExportTypeDefinition< JobParamsPanelCsv, @@ -35,8 +35,8 @@ export const getExportType = (): ExportTypeDefinition< ...metadata, jobType: CSV_FROM_SAVEDOBJECT_JOB_TYPE, jobContentExtension: 'csv', - createJobFactory, - executeJobFactory, + scheduleTaskFnFactory, + runTaskFnFactory, validLicenses: [ LICENSE_TYPE_TRIAL, LICENSE_TYPE_BASIC, diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/create_job.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/create_job.ts deleted file mode 100644 index c187da5104d3f..0000000000000 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/create_job.ts +++ /dev/null @@ -1,106 +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 { notFound, notImplemented } from 'boom'; -import { get } from 'lodash'; -import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; -import { ReportingCore } from '../../../..'; -import { CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../../../common/constants'; -import { cryptoFactory, LevelLogger } from '../../../../lib'; -import { CreateJobFactory, TimeRangeParams } from '../../../../types'; -import { - JobDocPayloadPanelCsv, - JobParamsPanelCsv, - SavedObject, - SavedObjectServiceError, - SavedSearchObjectAttributesJSON, - SearchPanel, - VisObjectAttributesJSON, -} from '../../types'; -import { createJobSearch } from './create_job_search'; - -export type ImmediateCreateJobFn = ( - jobParams: JobParamsType, - headers: KibanaRequest['headers'], - context: RequestHandlerContext, - req: KibanaRequest -) => Promise<{ - type: string | null; - title: string; - jobParams: JobParamsType; -}>; - -interface VisData { - title: string; - visType: string; - panel: SearchPanel; -} - -export const createJobFactory: CreateJobFactory> = function createJobFactoryFn(reporting: ReportingCore, parentLogger: LevelLogger) { - const config = reporting.getConfig(); - const crypto = cryptoFactory(config.get('encryptionKey')); - const logger = parentLogger.clone([CSV_FROM_SAVEDOBJECT_JOB_TYPE, 'create-job']); - - return async function createJob( - jobParams: JobParamsPanelCsv, - headers: KibanaRequest['headers'], - context: RequestHandlerContext, - req: KibanaRequest - ): Promise { - const { savedObjectType, savedObjectId } = jobParams; - const serializedEncryptedHeaders = await crypto.encrypt(headers); - - const { panel, title, visType }: VisData = await Promise.resolve() - .then(() => context.core.savedObjects.client.get(savedObjectType, savedObjectId)) - .then(async (savedObject: SavedObject) => { - const { attributes, references } = savedObject; - const { - kibanaSavedObjectMeta: kibanaSavedObjectMetaJSON, - } = attributes as SavedSearchObjectAttributesJSON; - const { timerange } = req.body as { timerange: TimeRangeParams }; - - if (!kibanaSavedObjectMetaJSON) { - throw new Error('Could not parse saved object data!'); - } - - const kibanaSavedObjectMeta = { - ...kibanaSavedObjectMetaJSON, - searchSource: JSON.parse(kibanaSavedObjectMetaJSON.searchSourceJSON), - }; - - const { visState: visStateJSON } = attributes as VisObjectAttributesJSON; - if (visStateJSON) { - throw notImplemented('Visualization types are not yet implemented'); - } - - // saved search type - return await createJobSearch(timerange, attributes, references, kibanaSavedObjectMeta); - }) - .catch((err: Error) => { - const boomErr = (err as unknown) as { isBoom: boolean }; - if (boomErr.isBoom) { - throw err; - } - const errPayload: SavedObjectServiceError = get(err, 'output.payload', { statusCode: 0 }); - if (errPayload.statusCode === 404) { - throw notFound(errPayload.message); - } - if (err.stack) { - logger.error(err.stack); - } - throw new Error(`Unable to create a job from saved object data! Error: ${err}`); - }); - - return { - headers: serializedEncryptedHeaders, - jobParams: { ...jobParams, panel, visType }, - type: null, - title, - }; - }; -}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/index.ts index a3674d69ae6a5..dafac04017607 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/create_job/index.ts @@ -4,4 +4,96 @@ * you may not use this file except in compliance with the Elastic License. */ -export { createJobFactory, ImmediateCreateJobFn } from './create_job'; +import { notFound, notImplemented } from 'boom'; +import { get } from 'lodash'; +import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; +import { CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../../../common/constants'; +import { cryptoFactory } from '../../../../lib'; +import { ScheduleTaskFnFactory, TimeRangeParams } from '../../../../types'; +import { + JobParamsPanelCsv, + SavedObject, + SavedObjectServiceError, + SavedSearchObjectAttributesJSON, + SearchPanel, + VisObjectAttributesJSON, +} from '../../types'; +import { createJobSearch } from './create_job_search'; + +export type ImmediateCreateJobFn = ( + jobParams: JobParamsType, + headers: KibanaRequest['headers'], + context: RequestHandlerContext, + req: KibanaRequest +) => Promise<{ + type: string | null; + title: string; + jobParams: JobParamsType; +}>; + +interface VisData { + title: string; + visType: string; + panel: SearchPanel; +} + +export const scheduleTaskFnFactory: ScheduleTaskFnFactory> = function createJobFactoryFn(reporting, parentLogger) { + const config = reporting.getConfig(); + const crypto = cryptoFactory(config.get('encryptionKey')); + const logger = parentLogger.clone([CSV_FROM_SAVEDOBJECT_JOB_TYPE, 'create-job']); + + return async function scheduleTask(jobParams, headers, context, req) { + const { savedObjectType, savedObjectId } = jobParams; + const serializedEncryptedHeaders = await crypto.encrypt(headers); + + const { panel, title, visType }: VisData = await Promise.resolve() + .then(() => context.core.savedObjects.client.get(savedObjectType, savedObjectId)) + .then(async (savedObject: SavedObject) => { + const { attributes, references } = savedObject; + const { + kibanaSavedObjectMeta: kibanaSavedObjectMetaJSON, + } = attributes as SavedSearchObjectAttributesJSON; + const { timerange } = req.body as { timerange: TimeRangeParams }; + + if (!kibanaSavedObjectMetaJSON) { + throw new Error('Could not parse saved object data!'); + } + + const kibanaSavedObjectMeta = { + ...kibanaSavedObjectMetaJSON, + searchSource: JSON.parse(kibanaSavedObjectMetaJSON.searchSourceJSON), + }; + + const { visState: visStateJSON } = attributes as VisObjectAttributesJSON; + if (visStateJSON) { + throw notImplemented('Visualization types are not yet implemented'); + } + + // saved search type + return await createJobSearch(timerange, attributes, references, kibanaSavedObjectMeta); + }) + .catch((err: Error) => { + const boomErr = (err as unknown) as { isBoom: boolean }; + if (boomErr.isBoom) { + throw err; + } + const errPayload: SavedObjectServiceError = get(err, 'output.payload', { statusCode: 0 }); + if (errPayload.statusCode === 404) { + throw notFound(errPayload.message); + } + if (err.stack) { + logger.error(err.stack); + } + throw new Error(`Unable to create a job from saved object data! Error: ${err}`); + }); + + return { + headers: serializedEncryptedHeaders, + jobParams: { ...jobParams, panel, visType }, + type: null, + title, + }; + }; +}; diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/execute_job.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/execute_job.ts index d555100b6320d..26b7a24907f40 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/execute_job.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/server/execute_job.ts @@ -6,39 +6,33 @@ import { i18n } from '@kbn/i18n'; import { KibanaRequest, RequestHandlerContext } from 'src/core/server'; -import { ReportingCore } from '../../..'; import { CONTENT_TYPE_CSV, CSV_FROM_SAVEDOBJECT_JOB_TYPE } from '../../../../common/constants'; -import { cryptoFactory, LevelLogger } from '../../../lib'; -import { ExecuteJobFactory, JobDocOutput, JobDocPayload } from '../../../types'; +import { cryptoFactory } from '../../../lib'; +import { RunTaskFnFactory, ScheduledTaskParams, TaskRunResult } from '../../../types'; import { CsvResultFromSearch } from '../../csv/types'; -import { FakeRequest, JobDocPayloadPanelCsv, JobParamsPanelCsv, SearchPanel } from '../types'; +import { FakeRequest, JobParamsPanelCsv, SearchPanel } from '../types'; import { createGenerateCsv } from './lib'; /* * ImmediateExecuteFn receives the job doc payload because the payload was - * generated in the CreateFn + * generated in the ScheduleFn */ export type ImmediateExecuteFn = ( jobId: null, - job: JobDocPayload, + job: ScheduledTaskParams, context: RequestHandlerContext, req: KibanaRequest -) => Promise; +) => Promise; -export const executeJobFactory: ExecuteJobFactory> = async function executeJobFactoryFn(reporting: ReportingCore, parentLogger: LevelLogger) { +>> = function executeJobFactoryFn(reporting, parentLogger) { const config = reporting.getConfig(); const crypto = cryptoFactory(config.get('encryptionKey')); const logger = parentLogger.clone([CSV_FROM_SAVEDOBJECT_JOB_TYPE, 'execute-job']); const generateCsv = createGenerateCsv(reporting, parentLogger); - return async function executeJob( - jobId: string | null, - job: JobDocPayloadPanelCsv, - context, - req - ): Promise { + return async function runTask(jobId: string | null, job, context, req) { // There will not be a jobID for "immediate" generation. // jobID is only for "queued" jobs // Use the jobID as a logging tag or "immediate" diff --git a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts index 36ae5b1dac05e..835b352953dfe 100644 --- a/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/csv_from_savedobject/types.d.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { JobParamPostPayload, JobDocPayload, TimeRangeParams } from '../../types'; +import { JobParamPostPayload, ScheduledTaskParams, TimeRangeParams } from '../../types'; export interface FakeRequest { headers: Record; @@ -23,7 +23,7 @@ export interface JobParamsPanelCsv { visType?: string; } -export interface JobDocPayloadPanelCsv extends JobDocPayload { +export interface ScheduledTaskParamsPanelCsv extends ScheduledTaskParams { jobParams: JobParamsPanelCsv; } diff --git a/x-pack/plugins/reporting/server/export_types/png/index.ts b/x-pack/plugins/reporting/server/export_types/png/index.ts index a3b51e365e772..b708448b0f8b2 100644 --- a/x-pack/plugins/reporting/server/export_types/png/index.ts +++ b/x-pack/plugins/reporting/server/export_types/png/index.ts @@ -14,22 +14,22 @@ import { } from '../../../common/constants'; import { ESQueueCreateJobFn, ESQueueWorkerExecuteFn, ExportTypeDefinition } from '../..//types'; import { metadata } from './metadata'; -import { createJobFactory } from './server/create_job'; -import { executeJobFactory } from './server/execute_job'; -import { JobDocPayloadPNG, JobParamsPNG } from './types'; +import { scheduleTaskFnFactory } from './server/create_job'; +import { runTaskFnFactory } from './server/execute_job'; +import { JobParamsPNG, ScheduledTaskParamsPNG } from './types'; export const getExportType = (): ExportTypeDefinition< JobParamsPNG, ESQueueCreateJobFn, - JobDocPayloadPNG, - ESQueueWorkerExecuteFn + ScheduledTaskParamsPNG, + ESQueueWorkerExecuteFn > => ({ ...metadata, jobType, jobContentEncoding: 'base64', jobContentExtension: 'PNG', - createJobFactory, - executeJobFactory, + scheduleTaskFnFactory, + runTaskFnFactory, validLicenses: [ LICENSE_TYPE_TRIAL, LICENSE_TYPE_STANDARD, diff --git a/x-pack/plugins/reporting/server/export_types/png/server/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/png/server/create_job/index.ts index 3f1556fb29782..f459b8f249c70 100644 --- a/x-pack/plugins/reporting/server/export_types/png/server/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/png/server/create_job/index.ts @@ -6,17 +6,17 @@ import { validateUrls } from '../../../../../common/validate_urls'; import { cryptoFactory } from '../../../../lib'; -import { CreateJobFactory, ESQueueCreateJobFn } from '../../../../types'; +import { ESQueueCreateJobFn, ScheduleTaskFnFactory } from '../../../../types'; import { JobParamsPNG } from '../../types'; -export const createJobFactory: CreateJobFactory> = function createJobFactoryFn(reporting) { const config = reporting.getConfig(); const setupDeps = reporting.getPluginSetupDeps(); const crypto = cryptoFactory(config.get('encryptionKey')); - return async function createJob( + return async function scheduleTask( { objectType, title, relativeUrl, browserTimezone, layout }, context, req diff --git a/x-pack/plugins/reporting/server/export_types/png/server/execute_job/index.test.ts b/x-pack/plugins/reporting/server/export_types/png/server/execute_job/index.test.ts index b92f53ff6563f..3d3f156aeef02 100644 --- a/x-pack/plugins/reporting/server/export_types/png/server/execute_job/index.test.ts +++ b/x-pack/plugins/reporting/server/export_types/png/server/execute_job/index.test.ts @@ -9,9 +9,9 @@ import { ReportingCore } from '../../../../'; import { CancellationToken } from '../../../../../common'; import { cryptoFactory, LevelLogger } from '../../../../lib'; import { createMockReportingCore } from '../../../../test_helpers'; -import { JobDocPayloadPNG } from '../../types'; +import { ScheduledTaskParamsPNG } from '../../types'; import { generatePngObservableFactory } from '../lib/generate_png'; -import { executeJobFactory } from './'; +import { runTaskFnFactory } from './'; jest.mock('../lib/generate_png', () => ({ generatePngObservableFactory: jest.fn() })); @@ -36,7 +36,7 @@ const encryptHeaders = async (headers: Record) => { return await crypto.encrypt(headers); }; -const getJobDocPayload = (baseObj: any) => baseObj as JobDocPayloadPNG; +const getScheduledTaskParams = (baseObj: any) => baseObj as ScheduledTaskParamsPNG; beforeEach(async () => { const kbnConfig = { @@ -81,11 +81,11 @@ test(`passes browserTimezone to generatePng`, async () => { const generatePngObservable = (await generatePngObservableFactory(mockReporting)) as jest.Mock; generatePngObservable.mockReturnValue(Rx.of(Buffer.from(''))); - const executeJob = await executeJobFactory(mockReporting, getMockLogger()); + const runTask = await runTaskFnFactory(mockReporting, getMockLogger()); const browserTimezone = 'UTC'; - await executeJob( + await runTask( 'pngJobId', - getJobDocPayload({ + getScheduledTaskParams({ relativeUrl: '/app/kibana#/something', browserTimezone, headers: encryptedHeaders, @@ -125,15 +125,15 @@ test(`passes browserTimezone to generatePng`, async () => { }); test(`returns content_type of application/png`, async () => { - const executeJob = await executeJobFactory(mockReporting, getMockLogger()); + const runTask = await runTaskFnFactory(mockReporting, getMockLogger()); const encryptedHeaders = await encryptHeaders({}); const generatePngObservable = await generatePngObservableFactory(mockReporting); (generatePngObservable as jest.Mock).mockReturnValue(Rx.of('foo')); - const { content_type: contentType } = await executeJob( + const { content_type: contentType } = await runTask( 'pngJobId', - getJobDocPayload({ relativeUrl: '/app/kibana#/something', headers: encryptedHeaders }), + getScheduledTaskParams({ relativeUrl: '/app/kibana#/something', headers: encryptedHeaders }), cancellationToken ); expect(contentType).toBe('image/png'); @@ -144,11 +144,11 @@ test(`returns content of generatePng getBuffer base64 encoded`, async () => { const generatePngObservable = await generatePngObservableFactory(mockReporting); (generatePngObservable as jest.Mock).mockReturnValue(Rx.of({ base64: testContent })); - const executeJob = await executeJobFactory(mockReporting, getMockLogger()); + const runTask = await runTaskFnFactory(mockReporting, getMockLogger()); const encryptedHeaders = await encryptHeaders({}); - const { content } = await executeJob( + const { content } = await runTask( 'pngJobId', - getJobDocPayload({ relativeUrl: '/app/kibana#/something', headers: encryptedHeaders }), + getScheduledTaskParams({ relativeUrl: '/app/kibana#/something', headers: encryptedHeaders }), cancellationToken ); diff --git a/x-pack/plugins/reporting/server/export_types/png/server/execute_job/index.ts b/x-pack/plugins/reporting/server/export_types/png/server/execute_job/index.ts index ea4c4b1d106ae..c9ab890dc8a50 100644 --- a/x-pack/plugins/reporting/server/export_types/png/server/execute_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/png/server/execute_job/index.ts @@ -7,37 +7,35 @@ import apm from 'elastic-apm-node'; import * as Rx from 'rxjs'; import { catchError, map, mergeMap, takeUntil } from 'rxjs/operators'; -import { ReportingCore } from '../../../..'; import { PNG_JOB_TYPE } from '../../../../../common/constants'; -import { ESQueueWorkerExecuteFn, ExecuteJobFactory, JobDocOutput } from '../../../..//types'; -import { LevelLogger } from '../../../../lib'; +import { ESQueueWorkerExecuteFn, RunTaskFnFactory, TaskRunResult } from '../../../..//types'; import { decryptJobHeaders, getConditionalHeaders, getFullUrls, omitBlacklistedHeaders, } from '../../../common/execute_job/'; -import { JobDocPayloadPNG } from '../../types'; +import { ScheduledTaskParamsPNG } from '../../types'; import { generatePngObservableFactory } from '../lib/generate_png'; -type QueuedPngExecutorFactory = ExecuteJobFactory>; +type QueuedPngExecutorFactory = RunTaskFnFactory>; -export const executeJobFactory: QueuedPngExecutorFactory = async function executeJobFactoryFn( - reporting: ReportingCore, - parentLogger: LevelLogger +export const runTaskFnFactory: QueuedPngExecutorFactory = function executeJobFactoryFn( + reporting, + parentLogger ) { const config = reporting.getConfig(); const encryptionKey = config.get('encryptionKey'); const logger = parentLogger.clone([PNG_JOB_TYPE, 'execute']); - return async function executeJob(jobId: string, job: JobDocPayloadPNG, cancellationToken: any) { + return async function runTask(jobId, job, cancellationToken) { const apmTrans = apm.startTransaction('reporting execute_job png', 'reporting'); const apmGetAssets = apmTrans?.startSpan('get_assets', 'setup'); let apmGeneratePng: { end: () => void } | null | undefined; const generatePngObservable = await generatePngObservableFactory(reporting); const jobLogger = logger.clone([jobId]); - const process$: Rx.Observable = Rx.of(1).pipe( + const process$: Rx.Observable = Rx.of(1).pipe( mergeMap(() => decryptJobHeaders({ encryptionKey, job, logger })), map((decryptedHeaders) => omitBlacklistedHeaders({ job, decryptedHeaders })), map((filteredHeaders) => getConditionalHeaders({ config, job, filteredHeaders })), diff --git a/x-pack/plugins/reporting/server/export_types/png/types.d.ts b/x-pack/plugins/reporting/server/export_types/png/types.d.ts index 486a8e91a722f..7a25f4ed8fe73 100644 --- a/x-pack/plugins/reporting/server/export_types/png/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/png/types.d.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { JobDocPayload } from '../../../server/types'; +import { ScheduledTaskParams } from '../../../server/types'; import { LayoutInstance, LayoutParams } from '../common/layouts'; // Job params: structure of incoming user request data @@ -17,7 +17,7 @@ export interface JobParamsPNG { } // Job payload: structure of stored job data provided by create_job -export interface JobDocPayloadPNG extends JobDocPayload { +export interface ScheduledTaskParamsPNG extends ScheduledTaskParams { basePath?: string; browserTimezone: string; forceNow?: string; diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts index 39a0cbd5270a1..073bd38b538fb 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/index.ts @@ -14,22 +14,22 @@ import { } from '../../../common/constants'; import { ESQueueCreateJobFn, ESQueueWorkerExecuteFn, ExportTypeDefinition } from '../../types'; import { metadata } from './metadata'; -import { createJobFactory } from './server/create_job'; -import { executeJobFactory } from './server/execute_job'; -import { JobDocPayloadPDF, JobParamsPDF } from './types'; +import { scheduleTaskFnFactory } from './server/create_job'; +import { runTaskFnFactory } from './server/execute_job'; +import { JobParamsPDF, ScheduledTaskParamsPDF } from './types'; export const getExportType = (): ExportTypeDefinition< JobParamsPDF, ESQueueCreateJobFn, - JobDocPayloadPDF, - ESQueueWorkerExecuteFn + ScheduledTaskParamsPDF, + ESQueueWorkerExecuteFn > => ({ ...metadata, jobType, jobContentEncoding: 'base64', jobContentExtension: 'pdf', - createJobFactory, - executeJobFactory, + scheduleTaskFnFactory, + runTaskFnFactory, validLicenses: [ LICENSE_TYPE_TRIAL, LICENSE_TYPE_STANDARD, diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/server/create_job/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/server/create_job/index.ts index 06a0902a56954..76c5718249720 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/server/create_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/server/create_job/index.ts @@ -6,18 +6,18 @@ import { validateUrls } from '../../../../../common/validate_urls'; import { cryptoFactory } from '../../../../lib'; -import { CreateJobFactory, ESQueueCreateJobFn } from '../../../../types'; +import { ESQueueCreateJobFn, ScheduleTaskFnFactory } from '../../../../types'; import { JobParamsPDF } from '../../types'; -export const createJobFactory: CreateJobFactory> = function createJobFactoryFn(reporting) { const config = reporting.getConfig(); const setupDeps = reporting.getPluginSetupDeps(); const crypto = cryptoFactory(config.get('encryptionKey')); - return async function createJobFn( - { title, relativeUrls, browserTimezone, layout, objectType }: JobParamsPDF, + return async function scheduleTaskFn( + { title, relativeUrls, browserTimezone, layout, objectType }, context, req ) { diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/server/execute_job/index.test.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/server/execute_job/index.test.ts index 2f4ca47cf739e..d4df8ef7072d3 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/server/execute_job/index.test.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/server/execute_job/index.test.ts @@ -11,9 +11,9 @@ import { ReportingCore } from '../../../../'; import { CancellationToken } from '../../../../../common'; import { cryptoFactory, LevelLogger } from '../../../../lib'; import { createMockReportingCore } from '../../../../test_helpers'; -import { JobDocPayloadPDF } from '../../types'; +import { ScheduledTaskParamsPDF } from '../../types'; import { generatePdfObservableFactory } from '../lib/generate_pdf'; -import { executeJobFactory } from './'; +import { runTaskFnFactory } from './'; let mockReporting: ReportingCore; @@ -36,7 +36,7 @@ const encryptHeaders = async (headers: Record) => { return await crypto.encrypt(headers); }; -const getJobDocPayload = (baseObj: any) => baseObj as JobDocPayloadPDF; +const getScheduledTaskParams = (baseObj: any) => baseObj as ScheduledTaskParamsPDF; beforeEach(async () => { const kbnConfig = { @@ -79,11 +79,11 @@ test(`passes browserTimezone to generatePdf`, async () => { const generatePdfObservable = (await generatePdfObservableFactory(mockReporting)) as jest.Mock; generatePdfObservable.mockReturnValue(Rx.of(Buffer.from(''))); - const executeJob = await executeJobFactory(mockReporting, getMockLogger()); + const runTask = await runTaskFnFactory(mockReporting, getMockLogger()); const browserTimezone = 'UTC'; - await executeJob( + await runTask( 'pdfJobId', - getJobDocPayload({ + getScheduledTaskParams({ title: 'PDF Params Timezone Test', relativeUrl: '/app/kibana#/something', browserTimezone, @@ -98,15 +98,15 @@ test(`passes browserTimezone to generatePdf`, async () => { test(`returns content_type of application/pdf`, async () => { const logger = getMockLogger(); - const executeJob = await executeJobFactory(mockReporting, logger); + const runTask = await runTaskFnFactory(mockReporting, logger); const encryptedHeaders = await encryptHeaders({}); const generatePdfObservable = await generatePdfObservableFactory(mockReporting); (generatePdfObservable as jest.Mock).mockReturnValue(Rx.of(Buffer.from(''))); - const { content_type: contentType } = await executeJob( + const { content_type: contentType } = await runTask( 'pdfJobId', - getJobDocPayload({ relativeUrls: [], headers: encryptedHeaders }), + getScheduledTaskParams({ relativeUrls: [], headers: encryptedHeaders }), cancellationToken ); expect(contentType).toBe('application/pdf'); @@ -117,11 +117,11 @@ test(`returns content of generatePdf getBuffer base64 encoded`, async () => { const generatePdfObservable = await generatePdfObservableFactory(mockReporting); (generatePdfObservable as jest.Mock).mockReturnValue(Rx.of({ buffer: Buffer.from(testContent) })); - const executeJob = await executeJobFactory(mockReporting, getMockLogger()); + const runTask = await runTaskFnFactory(mockReporting, getMockLogger()); const encryptedHeaders = await encryptHeaders({}); - const { content } = await executeJob( + const { content } = await runTask( 'pdfJobId', - getJobDocPayload({ relativeUrls: [], headers: encryptedHeaders }), + getScheduledTaskParams({ relativeUrls: [], headers: encryptedHeaders }), cancellationToken ); diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/server/execute_job/index.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/server/execute_job/index.ts index a4d84b2f9f1e0..7f8f2f4f6906a 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/server/execute_job/index.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/server/execute_job/index.ts @@ -7,10 +7,8 @@ import apm from 'elastic-apm-node'; import * as Rx from 'rxjs'; import { catchError, map, mergeMap, takeUntil } from 'rxjs/operators'; -import { ReportingCore } from '../../../..'; import { PDF_JOB_TYPE } from '../../../../../common/constants'; -import { LevelLogger } from '../../../../lib'; -import { ESQueueWorkerExecuteFn, ExecuteJobFactory, JobDocOutput } from '../../../../types'; +import { ESQueueWorkerExecuteFn, RunTaskFnFactory, TaskRunResult } from '../../../../types'; import { decryptJobHeaders, getConditionalHeaders, @@ -18,21 +16,21 @@ import { getFullUrls, omitBlacklistedHeaders, } from '../../../common/execute_job'; -import { JobDocPayloadPDF } from '../../types'; +import { ScheduledTaskParamsPDF } from '../../types'; import { generatePdfObservableFactory } from '../lib/generate_pdf'; -type QueuedPdfExecutorFactory = ExecuteJobFactory>; +type QueuedPdfExecutorFactory = RunTaskFnFactory>; -export const executeJobFactory: QueuedPdfExecutorFactory = async function executeJobFactoryFn( - reporting: ReportingCore, - parentLogger: LevelLogger +export const runTaskFnFactory: QueuedPdfExecutorFactory = function executeJobFactoryFn( + reporting, + parentLogger ) { const config = reporting.getConfig(); const encryptionKey = config.get('encryptionKey'); const logger = parentLogger.clone([PDF_JOB_TYPE, 'execute']); - return async function executeJob(jobId: string, job: JobDocPayloadPDF, cancellationToken: any) { + return async function runTask(jobId, job, cancellationToken) { const apmTrans = apm.startTransaction('reporting execute_job pdf', 'reporting'); const apmGetAssets = apmTrans?.startSpan('get_assets', 'setup'); let apmGeneratePdf: { end: () => void } | null | undefined; @@ -40,7 +38,7 @@ export const executeJobFactory: QueuedPdfExecutorFactory = async function execut const generatePdfObservable = await generatePdfObservableFactory(reporting); const jobLogger = logger.clone([jobId]); - const process$: Rx.Observable = Rx.of(1).pipe( + const process$: Rx.Observable = Rx.of(1).pipe( mergeMap(() => decryptJobHeaders({ encryptionKey, job, logger })), map((decryptedHeaders) => omitBlacklistedHeaders({ job, decryptedHeaders })), map((filteredHeaders) => getConditionalHeaders({ config, job, filteredHeaders })), diff --git a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.d.ts b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.d.ts index 087ef5a6ca82c..5399781a77753 100644 --- a/x-pack/plugins/reporting/server/export_types/printable_pdf/types.d.ts +++ b/x-pack/plugins/reporting/server/export_types/printable_pdf/types.d.ts @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { JobDocPayload } from '../../../server/types'; +import { ScheduledTaskParams } from '../../../server/types'; import { LayoutInstance, LayoutParams } from '../common/layouts'; // Job params: structure of incoming user request data, after being parsed from RISON @@ -17,7 +17,7 @@ export interface JobParamsPDF { } // Job payload: structure of stored job data provided by create_job -export interface JobDocPayloadPDF extends JobDocPayload { +export interface ScheduledTaskParamsPDF extends ScheduledTaskParams { basePath?: string; browserTimezone: string; forceNow?: string; diff --git a/x-pack/plugins/reporting/server/lib/create_queue.ts b/x-pack/plugins/reporting/server/lib/create_queue.ts index d993a17c0b314..5d09af312a41b 100644 --- a/x-pack/plugins/reporting/server/lib/create_queue.ts +++ b/x-pack/plugins/reporting/server/lib/create_queue.ts @@ -5,7 +5,7 @@ */ import { ReportingCore } from '../core'; -import { JobDocOutput, JobSource } from '../types'; +import { JobSource, TaskRunResult } from '../types'; import { createTaggedLogger } from './create_tagged_logger'; // TODO remove createTaggedLogger once esqueue is removed import { createWorkerFactory } from './create_worker'; import { Job } from './enqueue_job'; @@ -31,11 +31,11 @@ export interface ESQueueInstance { ) => ESQueueWorker; } -// GenericWorkerFn is a generic for ImmediateExecuteFn | ESQueueWorkerExecuteFn, +// GenericWorkerFn is a generic for ImmediateExecuteFn | ESQueueWorkerExecuteFn, type GenericWorkerFn = ( jobSource: JobSource, ...workerRestArgs: any[] -) => void | Promise; +) => void | Promise; export async function createQueueFactory( reporting: ReportingCore, diff --git a/x-pack/plugins/reporting/server/lib/create_worker.test.ts b/x-pack/plugins/reporting/server/lib/create_worker.test.ts index 8e1174e01aa7f..85188c07eeb20 100644 --- a/x-pack/plugins/reporting/server/lib/create_worker.test.ts +++ b/x-pack/plugins/reporting/server/lib/create_worker.test.ts @@ -26,7 +26,7 @@ const executeJobFactoryStub = sinon.stub(); const getMockLogger = sinon.stub(); const getMockExportTypesRegistry = ( - exportTypes: any[] = [{ executeJobFactory: executeJobFactoryStub }] + exportTypes: any[] = [{ runTaskFnFactory: executeJobFactoryStub }] ) => ({ getAll: () => exportTypes, @@ -75,11 +75,11 @@ Object { test('Creates a single Esqueue worker for Reporting, even if there are multiple export types', async () => { const exportTypesRegistry = getMockExportTypesRegistry([ - { executeJobFactory: executeJobFactoryStub }, - { executeJobFactory: executeJobFactoryStub }, - { executeJobFactory: executeJobFactoryStub }, - { executeJobFactory: executeJobFactoryStub }, - { executeJobFactory: executeJobFactoryStub }, + { runTaskFnFactory: executeJobFactoryStub }, + { runTaskFnFactory: executeJobFactoryStub }, + { runTaskFnFactory: executeJobFactoryStub }, + { runTaskFnFactory: executeJobFactoryStub }, + { runTaskFnFactory: executeJobFactoryStub }, ]); mockReporting.getExportTypesRegistry = () => exportTypesRegistry; const createWorker = createWorkerFactory(mockReporting, getMockLogger()); diff --git a/x-pack/plugins/reporting/server/lib/create_worker.ts b/x-pack/plugins/reporting/server/lib/create_worker.ts index c9e865668bb30..837be1f44a093 100644 --- a/x-pack/plugins/reporting/server/lib/create_worker.ts +++ b/x-pack/plugins/reporting/server/lib/create_worker.ts @@ -27,7 +27,7 @@ export function createWorkerFactory(reporting: ReportingCore, log for (const exportType of reporting.getExportTypesRegistry().getAll() as Array< ExportTypeDefinition> >) { - const jobExecutor = await exportType.executeJobFactory(reporting, logger); // FIXME: does not "need" to be async + const jobExecutor = exportType.runTaskFnFactory(reporting, logger); jobExecutors.set(exportType.jobType, jobExecutor); } diff --git a/x-pack/plugins/reporting/server/lib/enqueue_job.ts b/x-pack/plugins/reporting/server/lib/enqueue_job.ts index 3837f593df5b2..625da90f3b4f2 100644 --- a/x-pack/plugins/reporting/server/lib/enqueue_job.ts +++ b/x-pack/plugins/reporting/server/lib/enqueue_job.ts @@ -52,7 +52,7 @@ export function enqueueJobFactory( context: RequestHandlerContext, request: KibanaRequest ): Promise { - type CreateJobFn = ESQueueCreateJobFn; + type ScheduleTaskFnType = ESQueueCreateJobFn; const username = user ? user.username : false; const esqueue = await reporting.getEsqueue(); const exportType = reporting.getExportTypesRegistry().getById(exportTypeId); @@ -61,8 +61,8 @@ export function enqueueJobFactory( throw new Error(`Export type ${exportTypeId} does not exist in the registry!`); } - const createJob = exportType.createJobFactory(reporting, logger) as CreateJobFn; - const payload = await createJob(jobParams, context, request); + const scheduleTask = exportType.scheduleTaskFnFactory(reporting, logger) as ScheduleTaskFnType; + const payload = await scheduleTask(jobParams, context, request); const options = { timeout: queueTimeout, diff --git a/x-pack/plugins/reporting/server/lib/export_types_registry.ts b/x-pack/plugins/reporting/server/lib/export_types_registry.ts index 893a2635561ff..501989f21103e 100644 --- a/x-pack/plugins/reporting/server/lib/export_types_registry.ts +++ b/x-pack/plugins/reporting/server/lib/export_types_registry.ts @@ -5,15 +5,14 @@ */ import { isString } from 'lodash'; -import memoizeOne from 'memoize-one'; import { getExportType as getTypeCsv } from '../export_types/csv'; import { getExportType as getTypeCsvFromSavedObject } from '../export_types/csv_from_savedobject'; import { getExportType as getTypePng } from '../export_types/png'; import { getExportType as getTypePrintablePdf } from '../export_types/printable_pdf'; import { ExportTypeDefinition } from '../types'; -type GetCallbackFn = ( - item: ExportTypeDefinition +type GetCallbackFn = ( + item: ExportTypeDefinition ) => boolean; // => ExportTypeDefinition @@ -22,8 +21,8 @@ export class ExportTypesRegistry { constructor() {} - register( - item: ExportTypeDefinition + register( + item: ExportTypeDefinition ): void { if (!isString(item.id)) { throw new Error(`'item' must have a String 'id' property `); @@ -33,8 +32,6 @@ export class ExportTypesRegistry { throw new Error(`'item' with id ${item.id} has already been registered`); } - // TODO: Unwrap the execute function from the item's executeJobFactory - // Move that work out of server/lib/create_worker to reduce dependence on ESQueue this._map.set(item.id, item); } @@ -46,24 +43,24 @@ export class ExportTypesRegistry { return this._map.size; } - getById( + getById( id: string - ): ExportTypeDefinition { + ): ExportTypeDefinition { if (!this._map.has(id)) { throw new Error(`Unknown id ${id}`); } return this._map.get(id) as ExportTypeDefinition< JobParamsType, - CreateJobFnType, + ScheduleTaskFnType, JobPayloadType, - ExecuteJobFnType + RunTaskFnType >; } - get( - findType: GetCallbackFn - ): ExportTypeDefinition { + get( + findType: GetCallbackFn + ): ExportTypeDefinition { let result; for (const value of this._map.values()) { if (!findType(value)) { @@ -71,9 +68,9 @@ export class ExportTypesRegistry { } const foundResult: ExportTypeDefinition< JobParamsType, - CreateJobFnType, + ScheduleTaskFnType, JobPayloadType, - ExecuteJobFnType + RunTaskFnType > = value; if (result) { @@ -91,7 +88,7 @@ export class ExportTypesRegistry { } } -function getExportTypesRegistryFn(): ExportTypesRegistry { +export function getExportTypesRegistry(): ExportTypesRegistry { const registry = new ExportTypesRegistry(); /* this replaces the previously async method of registering export types, @@ -108,6 +105,3 @@ function getExportTypesRegistryFn(): ExportTypesRegistry { }); return registry; } - -// FIXME: is this the best way to return a singleton? -export const getExportTypesRegistry = memoizeOne(getExportTypesRegistryFn); diff --git a/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts b/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts index 1221f67855410..7d93a36c85bc8 100644 --- a/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts +++ b/x-pack/plugins/reporting/server/routes/generate_from_savedobject_immediate.ts @@ -7,12 +7,12 @@ import { schema } from '@kbn/config-schema'; import { ReportingCore } from '../'; import { API_BASE_GENERATE_V1 } from '../../common/constants'; -import { createJobFactory } from '../export_types/csv_from_savedobject/server/create_job'; -import { executeJobFactory } from '../export_types/csv_from_savedobject/server/execute_job'; +import { scheduleTaskFnFactory } from '../export_types/csv_from_savedobject/server/create_job'; +import { runTaskFnFactory } from '../export_types/csv_from_savedobject/server/execute_job'; import { getJobParamsFromRequest } from '../export_types/csv_from_savedobject/server/lib/get_job_params_from_request'; -import { JobDocPayloadPanelCsv } from '../export_types/csv_from_savedobject/types'; +import { ScheduledTaskParamsPanelCsv } from '../export_types/csv_from_savedobject/types'; import { LevelLogger as Logger } from '../lib'; -import { JobDocOutput } from '../types'; +import { TaskRunResult } from '../types'; import { authorizedUserPreRoutingFactory } from './lib/authorized_user_pre_routing'; import { HandlerErrorFunction } from './types'; @@ -36,8 +36,8 @@ export function registerGenerateCsvFromSavedObjectImmediate( /* * CSV export with the `immediate` option does not queue a job with Reporting's ESQueue to run the job async. Instead, this does: - * - re-use the createJob function to build up es query config - * - re-use the executeJob function to run the scan and scroll queries and capture the entire CSV in a result object. + * - re-use the scheduleTask function to build up es query config + * - re-use the runTask function to run the scan and scroll queries and capture the entire CSV in a result object. */ router.post( { @@ -60,11 +60,11 @@ export function registerGenerateCsvFromSavedObjectImmediate( userHandler(async (user, context, req, res) => { const logger = parentLogger.clone(['savedobject-csv']); const jobParams = getJobParamsFromRequest(req, { isImmediate: true }); - const createJobFn = createJobFactory(reporting, logger); - const executeJobFn = await executeJobFactory(reporting, logger); // FIXME: does not "need" to be async + const scheduleTaskFn = scheduleTaskFnFactory(reporting, logger); + const runTaskFn = runTaskFnFactory(reporting, logger); try { - const jobDocPayload: JobDocPayloadPanelCsv = await createJobFn( + const jobDocPayload: ScheduledTaskParamsPanelCsv = await scheduleTaskFn( jobParams, req.headers, context, @@ -74,13 +74,13 @@ export function registerGenerateCsvFromSavedObjectImmediate( content_type: jobOutputContentType, content: jobOutputContent, size: jobOutputSize, - }: JobDocOutput = await executeJobFn(null, jobDocPayload, context, req); + }: TaskRunResult = await runTaskFn(null, jobDocPayload, context, req); logger.info(`Job output size: ${jobOutputSize} bytes`); /* * ESQueue worker function defaults `content` to null, even if the - * executeJob returned undefined. + * runTask returned undefined. * * This converts null to undefined so the value can be sent to h.response() */ diff --git a/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts b/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts index e16f5278c8cc7..93f79bfd892b9 100644 --- a/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts +++ b/x-pack/plugins/reporting/server/routes/lib/get_document_payload.ts @@ -10,7 +10,7 @@ import * as _ from 'lodash'; import { CSV_JOB_TYPE } from '../../../common/constants'; import { statuses } from '../../lib/esqueue/constants/statuses'; import { ExportTypesRegistry } from '../../lib/export_types_registry'; -import { ExportTypeDefinition, JobDocOutput, JobSource } from '../../types'; +import { ExportTypeDefinition, JobSource, TaskRunResult } from '../../types'; type ExportTypeType = ExportTypeDefinition; @@ -18,7 +18,7 @@ interface ErrorFromPayload { message: string; } -// A camelCase version of JobDocOutput +// A camelCase version of TaskRunResult interface Payload { statusCode: number; content: string | Buffer | ErrorFromPayload; @@ -31,7 +31,7 @@ const DEFAULT_TITLE = 'report'; const getTitle = (exportType: ExportTypeType, title?: string): string => `${title || DEFAULT_TITLE}.${exportType.jobContentExtension}`; -const getReportingHeaders = (output: JobDocOutput, exportType: ExportTypeType) => { +const getReportingHeaders = (output: TaskRunResult, exportType: ExportTypeType) => { const metaDataHeaders: Record = {}; if (exportType.jobType === CSV_JOB_TYPE) { @@ -55,7 +55,7 @@ export function getDocumentPayloadFactory(exportTypesRegistry: ExportTypesRegist } } - function getCompleted(output: JobDocOutput, jobType: string, title: string): Payload { + function getCompleted(output: TaskRunResult, jobType: string, title: string): Payload { const exportType = exportTypesRegistry.get((item: ExportTypeType) => item.jobType === jobType); const filename = getTitle(exportType, title); const headers = getReportingHeaders(output, exportType); @@ -73,7 +73,7 @@ export function getDocumentPayloadFactory(exportTypesRegistry: ExportTypesRegist // @TODO: These should be semantic HTTP codes as 500/503's indicate // error then these are really operating properly. - function getFailure(output: JobDocOutput): Payload { + function getFailure(output: TaskRunResult): Payload { return { statusCode: 500, content: { diff --git a/x-pack/plugins/reporting/server/routes/types.d.ts b/x-pack/plugins/reporting/server/routes/types.d.ts index 5eceed0a7f2ab..607ce34ab9465 100644 --- a/x-pack/plugins/reporting/server/routes/types.d.ts +++ b/x-pack/plugins/reporting/server/routes/types.d.ts @@ -6,7 +6,7 @@ import { KibanaRequest, KibanaResponseFactory, RequestHandlerContext } from 'src/core/server'; import { AuthenticatedUser } from '../../../security/server'; -import { JobDocPayload } from '../types'; +import { ScheduledTaskParams } from '../types'; export type HandlerFunction = ( user: AuthenticatedUser | null, @@ -23,7 +23,7 @@ export interface QueuedJobPayload { error?: boolean; source: { job: { - payload: JobDocPayload; + payload: ScheduledTaskParams; }; }; } diff --git a/x-pack/plugins/reporting/server/types.ts b/x-pack/plugins/reporting/server/types.ts index 409a89899bee0..96eef81672610 100644 --- a/x-pack/plugins/reporting/server/types.ts +++ b/x-pack/plugins/reporting/server/types.ts @@ -58,7 +58,7 @@ export interface JobParamPostPayload { timerange: TimeRangeParams; } -export interface JobDocPayload { +export interface ScheduledTaskParams { headers?: string; // serialized encrypted headers jobParams: JobParamsType; title: string; @@ -70,13 +70,13 @@ export interface JobSource { _index: string; _source: { jobtype: string; - output: JobDocOutput; - payload: JobDocPayload; + output: TaskRunResult; + payload: ScheduledTaskParams; status: JobStatus; }; } -export interface JobDocOutput { +export interface TaskRunResult { content_type: string; content: string | null; size: number; @@ -173,43 +173,43 @@ export type ReportingSetup = object; * Internal Types */ +export type CaptureConfig = ReportingConfigType['capture']; +export type ScrollConfig = ReportingConfigType['csv']['scroll']; + export type ESQueueCreateJobFn = ( jobParams: JobParamsType, context: RequestHandlerContext, request: KibanaRequest ) => Promise; -export type ESQueueWorkerExecuteFn = ( +export type ESQueueWorkerExecuteFn = ( jobId: string, - job: JobDocPayloadType, - cancellationToken?: CancellationToken + job: ScheduledTaskParamsType, + cancellationToken: CancellationToken ) => Promise; -export type CaptureConfig = ReportingConfigType['capture']; -export type ScrollConfig = ReportingConfigType['csv']['scroll']; - -export type CreateJobFactory = ( +export type ScheduleTaskFnFactory = ( reporting: ReportingCore, logger: LevelLogger -) => CreateJobFnType; +) => ScheduleTaskFnType; -export type ExecuteJobFactory = ( +export type RunTaskFnFactory = ( reporting: ReportingCore, logger: LevelLogger -) => Promise; // FIXME: does not "need" to be async +) => RunTaskFnType; export interface ExportTypeDefinition< JobParamsType, - CreateJobFnType, + ScheduleTaskFnType, JobPayloadType, - ExecuteJobFnType + RunTaskFnType > { id: string; name: string; jobType: string; jobContentEncoding?: string; jobContentExtension: string; - createJobFactory: CreateJobFactory; - executeJobFactory: ExecuteJobFactory; + scheduleTaskFnFactory: ScheduleTaskFnFactory; + runTaskFnFactory: RunTaskFnFactory; validLicenses: string[]; } From 5c87a27c4dfda3a214e4f76c941d218475f08255 Mon Sep 17 00:00:00 2001 From: Oliver Gupte Date: Tue, 16 Jun 2020 14:31:09 -0700 Subject: [PATCH 18/41] [APM] Fix service maps not loading when there are no APM ML jobs (#69240) * Closes #69238 by handling 404 thrown error from the query for APM ML jobs. * Improved coded readability * moved anomaly job fetch to new function getApmAnomalyDetectionJobs for improved readability and only handle a 404 status code response else throw --- .../lib/service_map/get_service_anomalies.ts | 26 ++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts index ac76464e2f2e8..900141e9040ae 100644 --- a/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts +++ b/x-pack/plugins/apm/server/lib/service_map/get_service_anomalies.ts @@ -8,12 +8,33 @@ import { leftJoin } from '../../../common/utils/left_join'; import { Job as AnomalyDetectionJob } from '../../../../ml/server'; import { PromiseReturnType } from '../../../typings/common'; import { IEnvOptions } from './get_service_map'; +import { Setup } from '../helpers/setup_request'; import { APM_ML_JOB_GROUP_NAME, encodeForMlApi, } from '../../../common/ml_job_constants'; +async function getApmAnomalyDetectionJobs( + setup: Setup +): Promise { + const { ml } = setup; + + if (!ml) { + return []; + } + try { + const { jobs } = await ml.anomalyDetectors.jobs(APM_ML_JOB_GROUP_NAME); + return jobs; + } catch (error) { + if (error.statusCode === 404) { + return []; + } + throw error; + } +} + type ApmMlJobCategory = NonNullable>; + export const getApmMlJobCategory = ( mlJob: AnomalyDetectionJob, serviceNames: string[] @@ -62,7 +83,10 @@ export async function getServiceAnomalies( return []; } - const { jobs: apmMlJobs } = await ml.anomalyDetectors.jobs('apm'); + const apmMlJobs = await getApmAnomalyDetectionJobs(options.setup); + if (apmMlJobs.length === 0) { + return []; + } const apmMlJobCategories = apmMlJobs .map((job) => getApmMlJobCategory(job, serviceNames)) .filter( From e03f2428b1914634774c34e683205b5ef3fb891b Mon Sep 17 00:00:00 2001 From: Spencer Date: Tue, 16 Jun 2020 15:16:35 -0700 Subject: [PATCH 19/41] [BundleRefPlugin] resolve imports to files too (#69241) Co-authored-by: spalger --- examples/embeddable_examples/kibana.json | 2 +- .../src/worker/bundle_refs_plugin.ts | 133 +++++++++++------- 2 files changed, 81 insertions(+), 54 deletions(-) diff --git a/examples/embeddable_examples/kibana.json b/examples/embeddable_examples/kibana.json index b3ee0de096989..486c6322fad93 100644 --- a/examples/embeddable_examples/kibana.json +++ b/examples/embeddable_examples/kibana.json @@ -6,5 +6,5 @@ "ui": true, "requiredPlugins": ["embeddable"], "optionalPlugins": [], - "extraPublicDirs": ["public/todo", "public/hello_world"] + "extraPublicDirs": ["public/todo", "public/hello_world", "public/todo/todo_ref_embeddable"] } diff --git a/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts b/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts index 6defcaa787b7d..9c4d5ed7f8a98 100644 --- a/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts +++ b/packages/kbn-optimizer/src/worker/bundle_refs_plugin.ts @@ -40,51 +40,69 @@ interface RequestData { type Callback = (error?: any, result?: T) => void; type ModuleFactory = (data: RequestData, callback: Callback) => void; -/** - * Isolate the weired type juggling we have to do to add a hook to the webpack compiler - */ -function hookIntoCompiler( - compiler: webpack.Compiler, - handler: (context: string, request: string) => Promise -) { - compiler.hooks.compile.tap('BundleRefsPlugin', (compilationParams: any) => { - compilationParams.normalModuleFactory.hooks.factory.tap( - 'BundleRefsPlugin/normalModuleFactory/factory', - (wrappedFactory: ModuleFactory): ModuleFactory => (data, callback) => { - const context = data.context; - const dep = data.dependencies[0]; - - handler(context, dep.request).then( - (result) => { - if (!result) { - wrappedFactory(data, callback); - } else { - callback(undefined, result); - } - }, - (error) => callback(error) - ); - } - ); - }); -} - export class BundleRefsPlugin { - private resolvedRequestCache = new Map>(); + private readonly resolvedRefEntryCache = new Map>(); + private readonly resolvedRequestCache = new Map>(); + private readonly ignorePrefix = Path.resolve(this.bundle.contextDir) + Path.sep; - constructor(private readonly bundle: Bundle, public readonly bundleRefs: BundleRefs) {} + constructor(private readonly bundle: Bundle, private readonly bundleRefs: BundleRefs) {} - apply(compiler: webpack.Compiler) { - hookIntoCompiler(compiler, async (context, request) => { - const ref = await this.resolveRef(context, request); - if (ref) { - return new BundleRefModule(ref.exportId); + /** + * Called by webpack when the plugin is passed in the webpack config + */ + public apply(compiler: webpack.Compiler) { + // called whenever the compiler starts to compile, passed the params + // that will be used to create the compilation + compiler.hooks.compile.tap('BundleRefsPlugin', (compilationParams: any) => { + // clear caches because a new compilation is starting, meaning that files have + // changed and we should re-run resolutions + this.resolvedRefEntryCache.clear(); + this.resolvedRequestCache.clear(); + + // hook into the creation of NormalModule instances in webpack, if the import + // statement leading to the creation of the module is pointing to a bundleRef + // entry then create a BundleRefModule instead of a NormalModule. + compilationParams.normalModuleFactory.hooks.factory.tap( + 'BundleRefsPlugin/normalModuleFactory/factory', + (wrappedFactory: ModuleFactory): ModuleFactory => (data, callback) => { + const context = data.context; + const dep = data.dependencies[0]; + + this.maybeReplaceImport(context, dep.request).then( + (module) => { + if (!module) { + wrappedFactory(data, callback); + } else { + callback(undefined, module); + } + }, + (error) => callback(error) + ); + } + ); + }); + } + + private cachedResolveRefEntry(ref: BundleRef) { + const cached = this.resolvedRefEntryCache.get(ref); + + if (cached) { + return cached; + } + + const absoluteRequest = Path.resolve(ref.contextDir, ref.entry); + const promise = this.cachedResolveRequest(absoluteRequest).then((resolved) => { + if (!resolved) { + throw new Error(`Unable to resolve request [${ref.entry}] relative to [${ref.contextDir}]`); } + + return resolved; }); + this.resolvedRefEntryCache.set(ref, promise); + return promise; } - private cachedResolveRequest(context: string, request: string) { - const absoluteRequest = Path.resolve(context, request); + private cachedResolveRequest(absoluteRequest: string) { const cached = this.resolvedRequestCache.get(absoluteRequest); if (cached) { @@ -102,6 +120,7 @@ export class BundleRefsPlugin { return absoluteRequest; } + // look for an index file in directories if (stats?.isDirectory()) { for (const ext of RESOLVE_EXTENSIONS) { const indexPath = Path.resolve(absoluteRequest, `index${ext}`); @@ -112,6 +131,15 @@ export class BundleRefsPlugin { } } + // look for a file with one of the supported extensions + for (const ext of RESOLVE_EXTENSIONS) { + const filePath = `${absoluteRequest}${ext}`; + const fileStats = await safeStat(filePath); + if (fileStats?.isFile()) { + return filePath; + } + } + return; } @@ -121,7 +149,7 @@ export class BundleRefsPlugin { * then an error is thrown. If the request does not resolve to a bundleRef then * undefined is returned. Otherwise it returns the referenced bundleRef. */ - private async resolveRef(context: string, request: string) { + private async maybeReplaceImport(context: string, request: string) { // ignore imports that have loaders defined or are not relative seeming if (request.includes('!') || !request.startsWith('.')) { return; @@ -132,7 +160,12 @@ export class BundleRefsPlugin { return; } - const resolved = await this.cachedResolveRequest(context, request); + const absoluteRequest = Path.resolve(context, request); + if (absoluteRequest.startsWith(this.ignorePrefix)) { + return; + } + + const resolved = await this.cachedResolveRequest(absoluteRequest); if (!resolved) { return; } @@ -143,23 +176,17 @@ export class BundleRefsPlugin { return; } - let matchingRef: BundleRef | undefined; for (const ref of eligibleRefs) { - const resolvedEntry = await this.cachedResolveRequest(ref.contextDir, ref.entry); + const resolvedEntry = await this.cachedResolveRefEntry(ref); if (resolved === resolvedEntry) { - matchingRef = ref; - break; + return new BundleRefModule(ref.exportId); } } - if (!matchingRef) { - const bundleId = Array.from(new Set(eligibleRefs.map((r) => r.bundleId))).join(', '); - const publicDir = eligibleRefs.map((r) => r.entry).join(', '); - throw new Error( - `import [${request}] references a non-public export of the [${bundleId}] bundle and must point to one of the public directories: [${publicDir}]` - ); - } - - return matchingRef; + const bundleId = Array.from(new Set(eligibleRefs.map((r) => r.bundleId))).join(', '); + const publicDir = eligibleRefs.map((r) => r.entry).join(', '); + throw new Error( + `import [${request}] references a non-public export of the [${bundleId}] bundle and must point to one of the public directories: [${publicDir}]` + ); } } From ca9a1626a280f5e0ee783a3c92983d31b288a2b0 Mon Sep 17 00:00:00 2001 From: Lisa Cawley Date: Tue, 16 Jun 2020 17:03:59 -0700 Subject: [PATCH 20/41] [DOCS] Fixes license management links (#69347) --- docs/management/managing-beats.asciidoc | 2 +- docs/setup/docker.asciidoc | 2 +- docs/setup/install/deb.asciidoc | 2 +- docs/setup/install/rpm.asciidoc | 2 +- docs/setup/install/targz.asciidoc | 2 +- docs/setup/install/windows.asciidoc | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/management/managing-beats.asciidoc b/docs/management/managing-beats.asciidoc index 26998a3b5b8f4..d5a9c52feae23 100644 --- a/docs/management/managing-beats.asciidoc +++ b/docs/management/managing-beats.asciidoc @@ -21,7 +21,7 @@ Don't have a license? You can start a 30-day trial. Open the menu, go to *Stack Management > Elasticsearch > License Management*. At the end of the trial period, you can purchase a subscription to keep using central management. For more information, see https://www.elastic.co/subscriptions and -{stack-ov}/license-management.html[License Management]. +<>. ==== {kib} makes it easy for you to use central management by walking you through the diff --git a/docs/setup/docker.asciidoc b/docs/setup/docker.asciidoc index ab7a85a2ff851..0dee112d15e86 100644 --- a/docs/setup/docker.asciidoc +++ b/docs/setup/docker.asciidoc @@ -13,7 +13,7 @@ https://github.com/elastic/dockerfiles/tree/{branch}/kibana[GitHub]. These images are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. -{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the +<> to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/install/deb.asciidoc b/docs/setup/install/deb.asciidoc index dfa1e3a37fd05..d24c1cf8ae9d1 100644 --- a/docs/setup/install/deb.asciidoc +++ b/docs/setup/install/deb.asciidoc @@ -10,7 +10,7 @@ Kibana on any Debian-based system such as Debian and Ubuntu. This package is free to use under the Elastic license. It contains open source and free commercial features and access to paid commercial features. -{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the +<> to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/install/rpm.asciidoc b/docs/setup/install/rpm.asciidoc index ccc38c2696158..5d4f47f300eac 100644 --- a/docs/setup/install/rpm.asciidoc +++ b/docs/setup/install/rpm.asciidoc @@ -15,7 +15,7 @@ such as SLES 11 and CentOS 5. Please see <> instead. This package is free to use under the Elastic license. It contains open source and free commercial features and access to paid commercial features. -{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the +<> to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/install/targz.asciidoc b/docs/setup/install/targz.asciidoc index c8bff5d58889d..14ee1b297ffc6 100644 --- a/docs/setup/install/targz.asciidoc +++ b/docs/setup/install/targz.asciidoc @@ -9,7 +9,7 @@ are the easiest formats to use when trying out Kibana. These packages are free to use under the Elastic license. They contain open source and free commercial features and access to paid commercial features. -{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the +<> to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. diff --git a/docs/setup/install/windows.asciidoc b/docs/setup/install/windows.asciidoc index 24bf74f607fef..0d467f2fa7dd9 100644 --- a/docs/setup/install/windows.asciidoc +++ b/docs/setup/install/windows.asciidoc @@ -8,7 +8,7 @@ Kibana can be installed on Windows using the `.zip` package. This package is free to use under the Elastic license. It contains open source and free commercial features and access to paid commercial features. -{stack-ov}/license-management.html[Start a 30-day trial] to try out all of the +<> to try out all of the paid commercial features. See the https://www.elastic.co/subscriptions[Subscriptions] page for information about Elastic license levels. From a34a3a7e090b371e625a64e2d533d3c4dc8f38fc Mon Sep 17 00:00:00 2001 From: Alison Goryachev Date: Tue, 16 Jun 2020 21:48:28 -0400 Subject: [PATCH 21/41] [Component template] Details flyout (#68732) --- .../component_template_details.test.ts | 230 ++++++++++++++++++ .../component_template_list.test.ts | 5 +- .../component_template_details.helpers.ts | 86 +++++++ .../client_integration/helpers/constants.ts | 7 + .../helpers/http_requests.ts | 23 +- .../client_integration/helpers/index.ts | 2 + .../helpers/setup_environment.tsx | 6 +- .../component_template_details.tsx | 150 ++++++++++++ .../component_template_details/index.ts | 7 + .../manage_button.tsx | 105 ++++++++ .../tab_summary.tsx | 106 ++++++++ .../component_template_details/tabs.tsx | 70 ++++++ .../component_template_list.tsx | 50 +++- .../component_template_list_container.tsx | 16 +- .../component_template_list/table.tsx | 26 +- .../component_templates_context.tsx | 6 +- .../component_templates/constants.ts | 1 + .../components/component_templates/index.ts | 2 +- .../components/component_templates/lib/api.ts | 12 +- .../component_templates/shared_imports.ts | 8 + .../components/component_templates/types.ts | 17 -- .../shared/components/details_panel/index.ts | 9 + .../components/details_panel/tab_aliases.tsx | 39 +++ .../components/details_panel/tab_mappings.tsx | 38 +++ .../components/details_panel/tab_settings.tsx | 38 +++ .../components/shared/components/index.ts | 7 + .../application/components/shared/index.ts | 7 + .../public/application/index.tsx | 3 +- .../public/application/sections/home/home.tsx | 9 +- 29 files changed, 1044 insertions(+), 41 deletions(-) create mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_details.test.ts create mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/component_template_details.helpers.ts create mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/constants.ts create mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/component_template_details.tsx create mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/index.ts create mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/manage_button.tsx create mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/tab_summary.tsx create mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/tabs.tsx delete mode 100644 x-pack/plugins/index_management/public/application/components/component_templates/types.ts create mode 100644 x-pack/plugins/index_management/public/application/components/shared/components/details_panel/index.ts create mode 100644 x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_aliases.tsx create mode 100644 x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_mappings.tsx create mode 100644 x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_settings.tsx create mode 100644 x-pack/plugins/index_management/public/application/components/shared/components/index.ts create mode 100644 x-pack/plugins/index_management/public/application/components/shared/index.ts diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_details.test.ts b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_details.test.ts new file mode 100644 index 0000000000000..7c17dde119c42 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_details.test.ts @@ -0,0 +1,230 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { act } from 'react-dom/test-utils'; + +import { setupEnvironment, pageHelpers } from './helpers'; +import { ComponentTemplateDetailsTestBed } from './helpers/component_template_details.helpers'; +import { ComponentTemplateDeserialized } from '../../shared_imports'; + +const { setup } = pageHelpers.componentTemplateDetails; + +jest.mock('ui/i18n', () => { + const I18nContext = ({ children }: any) => children; + return { I18nContext }; +}); + +const COMPONENT_TEMPLATE: ComponentTemplateDeserialized = { + name: 'comp-1', + template: { + mappings: { properties: { ip_address: { type: 'ip' } } }, + aliases: { mydata: {} }, + settings: { number_of_shards: 1 }, + }, + version: 1, + _meta: { description: 'component template test' }, + _kbnMeta: { usedBy: ['template_1'] }, +}; + +const COMPONENT_TEMPLATE_ONLY_REQUIRED_FIELDS: ComponentTemplateDeserialized = { + name: 'comp-base', + template: {}, + _kbnMeta: { usedBy: [] }, +}; + +describe('', () => { + const { server, httpRequestsMockHelpers } = setupEnvironment(); + let testBed: ComponentTemplateDetailsTestBed; + + afterAll(() => { + server.restore(); + }); + + describe('With component template details', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadComponentTemplateResponse(COMPONENT_TEMPLATE); + + await act(async () => { + testBed = setup({ + componentTemplateName: COMPONENT_TEMPLATE.name, + onClose: () => {}, + }); + }); + + testBed.component.update(); + }); + + test('renders the details flyout', () => { + const { exists, find, actions, component } = testBed; + + // Verify flyout exists with correct title + expect(exists('componentTemplateDetails')).toBe(true); + expect(find('componentTemplateDetails.title').text()).toBe(COMPONENT_TEMPLATE.name); + + // Verify footer does not display since "actions" prop was not provided + expect(exists('componentTemplateDetails.footer')).toBe(false); + + // Verify tabs exist + expect(exists('settingsTab')).toBe(true); + expect(exists('mappingsTab')).toBe(true); + expect(exists('aliasesTab')).toBe(true); + // Summary tab should be active by default + expect(find('summaryTab').props()['aria-selected']).toBe(true); + + // [Summary tab] Verify description list items + expect(exists('summaryTabContent.usedByTitle')).toBe(true); + expect(exists('summaryTabContent.versionTitle')).toBe(true); + expect(exists('summaryTabContent.metaTitle')).toBe(true); + + // [Settings tab] Navigate to tab and verify content + act(() => { + actions.clickSettingsTab(); + }); + + component.update(); + + expect(exists('settingsTabContent')).toBe(true); + + // [Mappings tab] Navigate to tab and verify content + act(() => { + actions.clickMappingsTab(); + }); + + component.update(); + expect(exists('mappingsTabContent')).toBe(true); + + // [Aliases tab] Navigate to tab and verify content + act(() => { + actions.clickAliasesTab(); + }); + + component.update(); + expect(exists('aliasesTabContent')).toBe(true); + }); + }); + + describe('With only required component template fields', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadComponentTemplateResponse( + COMPONENT_TEMPLATE_ONLY_REQUIRED_FIELDS + ); + + await act(async () => { + testBed = setup({ + componentTemplateName: COMPONENT_TEMPLATE_ONLY_REQUIRED_FIELDS.name, + onClose: () => {}, + }); + }); + + testBed.component.update(); + }); + + test('renders the details flyout', () => { + const { exists, actions, component } = testBed; + + // [Summary tab] Verify optional description list items do not display + expect(exists('summaryTabContent.usedByTitle')).toBe(false); + expect(exists('summaryTabContent.versionTitle')).toBe(false); + expect(exists('summaryTabContent.metaTitle')).toBe(false); + // Verify callout renders indicating the component template is not in use + expect(exists('notInUseCallout')).toBe(true); + + // [Settings tab] Navigate to tab and verify info callout + act(() => { + actions.clickSettingsTab(); + }); + + component.update(); + + expect(exists('noSettingsCallout')).toBe(true); + + // [Mappings tab] Navigate to tab and verify info callout + act(() => { + actions.clickMappingsTab(); + }); + + component.update(); + expect(exists('noMappingsCallout')).toBe(true); + + // [Aliases tab] Navigate to tab and verify info callout + act(() => { + actions.clickAliasesTab(); + }); + + component.update(); + expect(exists('noAliasesCallout')).toBe(true); + }); + }); + + describe('With actions', () => { + beforeEach(async () => { + httpRequestsMockHelpers.setLoadComponentTemplateResponse(COMPONENT_TEMPLATE); + + await act(async () => { + testBed = setup({ + componentTemplateName: COMPONENT_TEMPLATE.name, + onClose: () => {}, + actions: [ + { + name: 'Test', + icon: 'info', + closePopoverOnClick: true, + handleActionClick: () => {}, + }, + ], + }); + }); + + testBed.component.update(); + }); + + test('should render a footer with context menu', () => { + const { exists, actions, component, find } = testBed; + + // Verify footer exists + expect(exists('componentTemplateDetails.footer')).toBe(true); + expect(exists('manageComponentTemplateButton')).toBe(true); + + // Click manage button and verify actions + act(() => { + actions.clickManageButton(); + }); + + component.update(); + + expect(exists('manageComponentTemplateContextMenu')).toBe(true); + expect(find('manageComponentTemplateContextMenu.action').length).toEqual(1); + }); + }); + + describe('Error handling', () => { + const error = { + status: 500, + error: 'Internal server error', + message: 'Internal server error', + }; + + beforeEach(async () => { + httpRequestsMockHelpers.setLoadComponentTemplateResponse(undefined, { body: error }); + + await act(async () => { + testBed = setup({ + componentTemplateName: COMPONENT_TEMPLATE.name, + onClose: () => {}, + }); + }); + + testBed.component.update(); + }); + + test('should render an error message if error fetching pipelines', async () => { + const { exists, find } = testBed; + + expect(exists('sectionError')).toBe(true); + expect(find('sectionError').text()).toContain('Error loading component template'); + }); + }); +}); diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_list.test.ts b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_list.test.ts index 830cc0ee6a980..86eb88017b77f 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_list.test.ts +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/component_template_list.test.ts @@ -6,10 +6,11 @@ import { act } from 'react-dom/test-utils'; +import { ComponentTemplateListItem } from '../../shared_imports'; + import { setupEnvironment, pageHelpers } from './helpers'; import { ComponentTemplateListTestBed } from './helpers/component_template_list.helpers'; -import { API_BASE_PATH } from '../../../../../../common/constants'; -import { ComponentTemplateListItem } from '../../types'; +import { API_BASE_PATH } from './helpers/constants'; const { setup } = pageHelpers.componentTemplateList; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/component_template_details.helpers.ts b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/component_template_details.helpers.ts new file mode 100644 index 0000000000000..25c2d654fd900 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/component_template_details.helpers.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { registerTestBed, TestBed } from '../../../../../../../../../test_utils'; +import { WithAppDependencies } from './setup_environment'; +import { ComponentTemplateDetailsFlyout } from '../../../component_template_details'; + +export type ComponentTemplateDetailsTestBed = TestBed & { + actions: ReturnType; +}; + +const createActions = (testBed: TestBed) => { + const { find } = testBed; + + /** + * User Actions + */ + const clickSettingsTab = () => { + find('settingsTab').simulate('click'); + }; + + const clickMappingsTab = () => { + find('mappingsTab').simulate('click'); + }; + + const clickAliasesTab = () => { + find('aliasesTab').simulate('click'); + }; + + const clickManageButton = () => { + find('manageComponentTemplateButton').simulate('click'); + }; + + return { + clickSettingsTab, + clickAliasesTab, + clickMappingsTab, + clickManageButton, + }; +}; + +export const setup = (props: any): ComponentTemplateDetailsTestBed => { + const setupTestBed = registerTestBed( + WithAppDependencies(ComponentTemplateDetailsFlyout), + { + memoryRouter: { + wrapComponent: false, + }, + defaultProps: props, + } + ); + + const testBed = setupTestBed() as ComponentTemplateDetailsTestBed; + + return { + ...testBed, + actions: createActions(testBed), + }; +}; + +export type ComponentTemplateDetailsTestSubjects = + | 'componentTemplateDetails' + | 'componentTemplateDetails.title' + | 'componentTemplateDetails.footer' + | 'summaryTab' + | 'mappingsTab' + | 'settingsTab' + | 'aliasesTab' + | 'sectionError' + | 'summaryTabContent' + | 'summaryTabContent.usedByTitle' + | 'summaryTabContent.versionTitle' + | 'summaryTabContent.metaTitle' + | 'notInUseCallout' + | 'aliasesTabContent' + | 'noAliasesCallout' + | 'mappingsTabContent' + | 'noMappingsCallout' + | 'settingsTabContent' + | 'noSettingsCallout' + | 'manageComponentTemplateButton' + | 'manageComponentTemplateContextMenu' + | 'manageComponentTemplateContextMenu.action'; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/constants.ts b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/constants.ts new file mode 100644 index 0000000000000..00b07fadd0c08 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/constants.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export const API_BASE_PATH = '/api/index_management'; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/http_requests.ts b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/http_requests.ts index 8473041ee0af3..b7b674292dd98 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/http_requests.ts +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/http_requests.ts @@ -5,11 +5,15 @@ */ import sinon, { SinonFakeServer } from 'sinon'; -import { API_BASE_PATH } from '../../../../../../../common'; +import { ComponentTemplateListItem, ComponentTemplateDeserialized } from '../../../shared_imports'; +import { API_BASE_PATH } from './constants'; // Register helpers to mock HTTP Requests const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { - const setLoadComponentTemplatesResponse = (response?: any[], error?: any) => { + const setLoadComponentTemplatesResponse = ( + response?: ComponentTemplateListItem[], + error?: any + ) => { const status = error ? error.status || 400 : 200; const body = error ? error.body : response; @@ -20,6 +24,20 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { ]); }; + const setLoadComponentTemplateResponse = ( + response?: ComponentTemplateDeserialized, + error?: any + ) => { + const status = error ? error.status || 400 : 200; + const body = error ? error.body : response; + + server.respondWith('GET', `${API_BASE_PATH}/component_templates/:name`, [ + status, + { 'Content-Type': 'application/json' }, + JSON.stringify(body), + ]); + }; + const setDeleteComponentTemplateResponse = (response?: object) => { server.respondWith('DELETE', `${API_BASE_PATH}/component_templates/:name`, [ 200, @@ -31,6 +49,7 @@ const registerHttpRequestMockHelpers = (server: SinonFakeServer) => { return { setLoadComponentTemplatesResponse, setDeleteComponentTemplateResponse, + setLoadComponentTemplateResponse, }; }; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/index.ts b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/index.ts index c1d75b3c2dd9b..93eb65aac0761 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/index.ts +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/index.ts @@ -5,6 +5,7 @@ */ import { setup as componentTemplatesListSetup } from './component_template_list.helpers'; +import { setup as componentTemplateDetailsSetup } from './component_template_details.helpers'; export { nextTick, getRandomString, findTestSubject } from '../../../../../../../../../test_utils'; @@ -12,4 +13,5 @@ export { setupEnvironment } from './setup_environment'; export const pageHelpers = { componentTemplateList: { setup: componentTemplatesListSetup }, + componentTemplateDetails: { setup: componentTemplateDetailsSetup }, }; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/setup_environment.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/setup_environment.tsx index c0aeb70166b5b..a2194bbfa0186 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/setup_environment.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/__jest__/client_integration/helpers/setup_environment.tsx @@ -9,21 +9,21 @@ import axios from 'axios'; import axiosXhrAdapter from 'axios/lib/adapters/xhr'; import { HttpSetup } from 'kibana/public'; -import { BASE_PATH, API_BASE_PATH } from '../../../../../../../common/constants'; import { notificationServiceMock, docLinksServiceMock, } from '../../../../../../../../../../src/core/public/mocks'; -import { init as initHttpRequests } from './http_requests'; import { ComponentTemplatesProvider } from '../../../component_templates_context'; +import { init as initHttpRequests } from './http_requests'; +import { API_BASE_PATH } from './constants'; + const mockHttpClient = axios.create({ adapter: axiosXhrAdapter }); const appDependencies = { httpClient: (mockHttpClient as unknown) as HttpSetup, apiBasePath: API_BASE_PATH, - appBasePath: BASE_PATH, trackMetric: () => {}, docLinks: docLinksServiceMock.createStartContract(), toasts: notificationServiceMock.createSetupContract().toasts, diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/component_template_details.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/component_template_details.tsx new file mode 100644 index 0000000000000..a8007c6363584 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/component_template_details.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 { FormattedMessage } from '@kbn/i18n/react'; +import { + EuiFlyout, + EuiFlyoutHeader, + EuiTitle, + EuiFlyoutBody, + EuiFlyoutFooter, + EuiFlexGroup, + EuiFlexItem, + EuiButtonEmpty, + EuiSpacer, + EuiCallOut, +} from '@elastic/eui'; + +import { SectionLoading, TabSettings, TabAliases, TabMappings } from '../shared_imports'; +import { useComponentTemplatesContext } from '../component_templates_context'; +import { TabSummary } from './tab_summary'; +import { ComponentTemplateTabs, TabType } from './tabs'; +import { ManageButton, ManageAction } from './manage_button'; + +interface Props { + componentTemplateName: string; + onClose: () => void; + showFooter?: boolean; + actions?: ManageAction[]; +} + +export const ComponentTemplateDetailsFlyout: React.FunctionComponent = ({ + componentTemplateName, + onClose, + actions, +}) => { + const { api } = useComponentTemplatesContext(); + + const { data: componentTemplateDetails, isLoading, error } = api.useLoadComponentTemplate( + componentTemplateName + ); + + const [activeTab, setActiveTab] = useState('summary'); + + let content: React.ReactNode | undefined; + + if (isLoading) { + content = ( + + + + ); + } else if (error) { + content = ( + + } + color="danger" + iconType="alert" + data-test-subj="sectionError" + > +

{error.message}

+ + ); + } else if (componentTemplateDetails) { + const { + template: { settings, mappings, aliases }, + } = componentTemplateDetails; + + const tabToComponentMap: Record = { + summary: , + settings: , + mappings: , + aliases: , + }; + + const tabContent = tabToComponentMap[activeTab]; + + content = ( + <> + + + + + {tabContent} + + ); + } + + return ( + + + +

+ {componentTemplateName} +

+
+
+ + {content} + + {actions && ( + + + {/* "Close" link */} + + + + + + + {/* "Manage" context menu */} + {componentTemplateDetails && ( + + + + )} + + + )} +
+ ); +}; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/index.ts b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/index.ts new file mode 100644 index 0000000000000..11aac200a2f14 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/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 { ComponentTemplateDetailsFlyout } from './component_template_details'; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/manage_button.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/manage_button.tsx new file mode 100644 index 0000000000000..c3a4f9b4dce35 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/manage_button.tsx @@ -0,0 +1,105 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { + EuiPopover, + EuiButton, + EuiContextMenu, + EuiContextMenuPanelItemDescriptor, +} from '@elastic/eui'; +import { ComponentTemplateDeserialized } from '../shared_imports'; + +export interface ManageAction { + name: string; + icon: string; + handleActionClick: () => void; + getIsDisabled?: (data: ComponentTemplateDeserialized) => boolean; + closePopoverOnClick?: boolean; +} + +interface Props { + actions: ManageAction[]; + componentTemplateDetails: ComponentTemplateDeserialized; +} + +export const ManageButton: React.FunctionComponent = ({ + actions, + componentTemplateDetails, +}) => { + const [isPopoverOpen, setIsPopOverOpen] = useState(false); + + const items: EuiContextMenuPanelItemDescriptor[] = actions.map( + ({ name, icon, getIsDisabled, closePopoverOnClick, handleActionClick }) => { + const isDisabled = getIsDisabled ? getIsDisabled(componentTemplateDetails) : false; + + return { + name, + icon, + disabled: isDisabled, + toolTipContent: isDisabled ? ( + + ) : null, + onClick: () => { + handleActionClick(); + + if (closePopoverOnClick) { + setIsPopOverOpen(false); + } + }, + 'data-test-subj': 'action', + }; + } + ); + + return ( + setIsPopOverOpen((prevBoolean) => !prevBoolean)} + > + + + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopOverOpen(false)} + panelPaddingSize="none" + withTitle + anchorPosition="rightUp" + repositionOnScroll + > + + + ); +}; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/tab_summary.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/tab_summary.tsx new file mode 100644 index 0000000000000..401186f6c962e --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/tab_summary.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 { + EuiDescriptionList, + EuiDescriptionListTitle, + EuiDescriptionListDescription, + EuiCodeBlock, + EuiTitle, + EuiCallOut, + EuiSpacer, +} from '@elastic/eui'; + +import { ComponentTemplateDeserialized } from '../shared_imports'; + +interface Props { + componentTemplateDetails: ComponentTemplateDeserialized; +} + +export const TabSummary: React.FunctionComponent = ({ componentTemplateDetails }) => { + const { version, _meta, _kbnMeta } = componentTemplateDetails; + + const { usedBy } = _kbnMeta; + const templateIsInUse = usedBy.length > 0; + + return ( + <> + {/* Callout when component template is not in use */} + {!templateIsInUse && ( + <> + + } + iconType="pin" + data-test-subj="notInUseCallout" + size="s" + /> + + + )} + + {/* Summary description list */} + + {/* Used by templates */} + {templateIsInUse && ( + <> + + + + +
    + {usedBy.map((templateName: string) => ( +
  • + + {templateName} + +
  • + ))} +
+
+ + )} + + {/* Version (optional) */} + {version && ( + <> + + + + {version} + + )} + + {/* Metadata (optional) */} + {_meta && ( + <> + + + + + {JSON.stringify(_meta, null, 2)} + + + )} +
+ + ); +}; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/tabs.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/tabs.tsx new file mode 100644 index 0000000000000..89370e3f6f1b8 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_details/tabs.tsx @@ -0,0 +1,70 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiTab, EuiTabs } from '@elastic/eui'; + +export type TabType = 'summary' | 'mappings' | 'aliases' | 'settings'; + +interface Props { + setActiveTab: (id: TabType) => void; + activeTab: TabType; +} + +interface Tab { + id: TabType; + name: string; +} + +const TABS: Tab[] = [ + { + id: 'summary', + name: i18n.translate('xpack.idxMgmt.componentTemplateDetails.summaryTabTitle', { + defaultMessage: 'Summary', + }), + }, + { + id: 'settings', + name: i18n.translate('xpack.idxMgmt.componentTemplateDetails.settingsTabTitle', { + defaultMessage: 'Settings', + }), + }, + { + id: 'mappings', + name: i18n.translate('xpack.idxMgmt.componentTemplateDetails.mappingsTabTitle', { + defaultMessage: 'Mappings', + }), + }, + { + id: 'aliases', + name: i18n.translate('xpack.idxMgmt.componentTemplateDetails.aliasesTabTitle', { + defaultMessage: 'Aliases', + }), + }, +]; + +export const ComponentTemplateTabs: React.FunctionComponent = ({ + setActiveTab, + activeTab, +}) => { + return ( + + {TABS.map((tab) => ( + { + setActiveTab(tab.id); + }} + isSelected={tab.id === activeTab} + key={tab.id} + data-test-subj={`${tab.id}Tab`} + > + {tab.name} + + ))} + + ); +}; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx index 41fa608ef538b..05a5ed462d8f7 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list.tsx @@ -5,24 +5,39 @@ */ import React, { useState, useEffect } from 'react'; +import { RouteComponentProps } from 'react-router-dom'; +import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { ScopedHistory } from 'kibana/public'; -import { SectionLoading } from '../shared_imports'; -import { useComponentTemplatesContext } from '../component_templates_context'; +import { SectionLoading, ComponentTemplateDeserialized } from '../shared_imports'; import { UIM_COMPONENT_TEMPLATE_LIST_LOAD } from '../constants'; - +import { useComponentTemplatesContext } from '../component_templates_context'; +import { ComponentTemplateDetailsFlyout } from '../component_template_details'; import { EmptyPrompt } from './empty_prompt'; import { ComponentTable } from './table'; import { LoadError } from './error'; import { ComponentTemplatesDeleteModal } from './delete_modal'; -export const ComponentTemplateList: React.FunctionComponent = () => { +interface Props { + componentTemplateName?: string; + history: RouteComponentProps['history']; +} + +export const ComponentTemplateList: React.FunctionComponent = ({ + componentTemplateName, + history, +}) => { const { api, trackMetric } = useComponentTemplatesContext(); const { data, isLoading, error, sendRequest } = api.useLoadComponentTemplates(); const [componentTemplatesToDelete, setComponentTemplatesToDelete] = useState([]); + const goToList = () => { + return history.push('component_templates'); + }; + // Track component loaded useEffect(() => { trackMetric('loaded', UIM_COMPONENT_TEMPLATE_LIST_LOAD); @@ -49,6 +64,7 @@ export const ComponentTemplateList: React.FunctionComponent = () => { componentTemplates={data} onReloadClick={sendRequest} onDeleteClick={setComponentTemplatesToDelete} + history={history as ScopedHistory} /> ); } else if (error) { @@ -58,18 +74,44 @@ export const ComponentTemplateList: React.FunctionComponent = () => { return (
{content} + + {/* delete modal */} {componentTemplatesToDelete?.length > 0 ? ( { if (deleteResponse?.hasDeletedComponentTemplates) { // refetch the component templates sendRequest(); + // go back to list view (if deleted from details flyout) + goToList(); } setComponentTemplatesToDelete([]); }} componentTemplatesToDelete={componentTemplatesToDelete} /> ) : null} + + {/* details flyout */} + {componentTemplateName && ( + + details._kbnMeta.usedBy.length > 0, + closePopoverOnClick: true, + handleActionClick: () => { + setComponentTemplatesToDelete([componentTemplateName]); + }, + }, + ]} + /> + )}
); }; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list_container.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list_container.tsx index af8ab1b94c790..d0636da8cf93a 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list_container.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/component_template_list_container.tsx @@ -5,16 +5,28 @@ */ import React from 'react'; +import { RouteComponentProps } from 'react-router-dom'; import { ComponentTemplatesAuthProvider } from './auth_provider'; import { ComponentTemplatesWithPrivileges } from './with_privileges'; import { ComponentTemplateList } from './component_template_list'; -export const ComponentTemplateListContainer: React.FunctionComponent = () => { +interface MatchParams { + componentTemplateName?: string; +} + +export const ComponentTemplateListContainer: React.FunctionComponent> = ({ + match: { + params: { componentTemplateName }, + }, + history, +}) => { return ( - + ); diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/table.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/table.tsx index 2d9557e64e6e7..b67a249ae6976 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/table.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_template_list/table.tsx @@ -12,21 +12,30 @@ import { EuiInMemoryTableProps, EuiTextColor, EuiIcon, + EuiLink, } from '@elastic/eui'; +import { ScopedHistory } from 'kibana/public'; -import { ComponentTemplateListItem } from '../types'; +import { reactRouterNavigate } from '../../../../../../../../src/plugins/kibana_react/public'; +import { ComponentTemplateListItem } from '../shared_imports'; +import { UIM_COMPONENT_TEMPLATE_DETAILS } from '../constants'; +import { useComponentTemplatesContext } from '../component_templates_context'; export interface Props { componentTemplates: ComponentTemplateListItem[]; onReloadClick: () => void; onDeleteClick: (componentTemplateName: string[]) => void; + history: ScopedHistory; } export const ComponentTable: FunctionComponent = ({ componentTemplates, onReloadClick, onDeleteClick, + history, }) => { + const { trackMetric } = useComponentTemplatesContext(); + const [selection, setSelection] = useState([]); const tableProps: EuiInMemoryTableProps = { @@ -120,6 +129,21 @@ export const ComponentTable: FunctionComponent = ({ defaultMessage: 'Name', }), sortable: true, + render: (name: string) => ( + /* eslint-disable-next-line @elastic/eui/href-or-on-click */ + trackMetric('click', UIM_COMPONENT_TEMPLATE_DETAILS) + )} + data-test-subj="templateDetailsLink" + > + {name} + + ), }, { field: 'usedBy', diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/component_templates_context.tsx b/x-pack/plugins/index_management/public/application/components/component_templates/component_templates_context.tsx index 55f20ce21d417..e8116409def4b 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/component_templates_context.tsx +++ b/x-pack/plugins/index_management/public/application/components/component_templates/component_templates_context.tsx @@ -14,7 +14,6 @@ const ComponentTemplatesContext = createContext(undefined); interface Props { httpClient: HttpSetup; apiBasePath: string; - appBasePath: string; trackMetric: (type: 'loaded' | 'click' | 'count', eventName: string) => void; docLinks: DocLinksSetup; toasts: NotificationsSetup['toasts']; @@ -27,7 +26,6 @@ interface Context { documentation: ReturnType; trackMetric: (type: 'loaded' | 'click' | 'count', eventName: string) => void; toasts: NotificationsSetup['toasts']; - appBasePath: string; } export const ComponentTemplatesProvider = ({ @@ -37,7 +35,7 @@ export const ComponentTemplatesProvider = ({ value: Props; children: React.ReactNode; }) => { - const { httpClient, apiBasePath, trackMetric, docLinks, toasts, appBasePath } = value; + const { httpClient, apiBasePath, trackMetric, docLinks, toasts } = value; const useRequest = getUseRequest(httpClient); const sendRequest = getSendRequest(httpClient); @@ -47,7 +45,7 @@ export const ComponentTemplatesProvider = ({ return ( {children} diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/constants.ts b/x-pack/plugins/index_management/public/application/components/component_templates/constants.ts index 501acde07fc00..e9acfa8dcc56d 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/constants.ts +++ b/x-pack/plugins/index_management/public/application/components/component_templates/constants.ts @@ -8,6 +8,7 @@ export const UIM_COMPONENT_TEMPLATE_LIST_LOAD = 'component_template_list_load'; export const UIM_COMPONENT_TEMPLATE_DELETE = 'component_template_delete'; export const UIM_COMPONENT_TEMPLATE_DELETE_MANY = 'component_template_delete_many'; +export const UIM_COMPONENT_TEMPLATE_DETAILS = 'component_template_details'; // privileges export const APP_CLUSTER_REQUIRED_PRIVILEGES = ['manage_index_templates']; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/index.ts b/x-pack/plugins/index_management/public/application/components/component_templates/index.ts index e0219ec71787f..72e79a57ae413 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/index.ts +++ b/x-pack/plugins/index_management/public/application/components/component_templates/index.ts @@ -8,4 +8,4 @@ export { ComponentTemplatesProvider } from './component_templates_context'; export { ComponentTemplateList } from './component_template_list'; -export * from './types'; +export { ComponentTemplateDetailsFlyout } from './component_template_details'; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/lib/api.ts b/x-pack/plugins/index_management/public/application/components/component_templates/lib/api.ts index 351e83c6c0cb5..4a8cf965adfb9 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/lib/api.ts +++ b/x-pack/plugins/index_management/public/application/components/component_templates/lib/api.ts @@ -4,9 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { ComponentTemplateListItem } from '../types'; -import { UseRequestHook, SendRequestHook } from './request'; +import { ComponentTemplateListItem, ComponentTemplateDeserialized } from '../shared_imports'; import { UIM_COMPONENT_TEMPLATE_DELETE_MANY, UIM_COMPONENT_TEMPLATE_DELETE } from '../constants'; +import { UseRequestHook, SendRequestHook } from './request'; export const getApi = ( useRequest: UseRequestHook, @@ -37,8 +37,16 @@ export const getApi = ( return result; } + function useLoadComponentTemplate(name: string) { + return useRequest({ + path: `${apiBasePath}/component_templates/${encodeURIComponent(name)}`, + method: 'get', + }); + } + return { useLoadComponentTemplates, deleteComponentTemplates, + useLoadComponentTemplate, }; }; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/shared_imports.ts b/x-pack/plugins/index_management/public/application/components/component_templates/shared_imports.ts index 049204f03c0c1..4e56f4a8c9818 100644 --- a/x-pack/plugins/index_management/public/application/components/component_templates/shared_imports.ts +++ b/x-pack/plugins/index_management/public/application/components/component_templates/shared_imports.ts @@ -19,3 +19,11 @@ export { useAuthorizationContext, NotAuthorizedSection, } from '../../../../../../../src/plugins/es_ui_shared/public'; + +export { TabMappings, TabSettings, TabAliases } from '../shared'; + +export { + ComponentTemplateSerialized, + ComponentTemplateDeserialized, + ComponentTemplateListItem, +} from '../../../../common'; diff --git a/x-pack/plugins/index_management/public/application/components/component_templates/types.ts b/x-pack/plugins/index_management/public/application/components/component_templates/types.ts deleted file mode 100644 index 0aab3b6b0a94a..0000000000000 --- a/x-pack/plugins/index_management/public/application/components/component_templates/types.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License; - * you may not use this file except in compliance with the Elastic License. - */ - -// Ideally, we shouldn't depend on anything in index management that is -// outside of the components_templates directory -// We could consider creating shared types or duplicating the types here if -// the component_templates app were to move outside of index management -import { - ComponentTemplateSerialized, - ComponentTemplateDeserialized, - ComponentTemplateListItem, -} from '../../../../common'; - -export { ComponentTemplateSerialized, ComponentTemplateDeserialized, ComponentTemplateListItem }; diff --git a/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/index.ts b/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/index.ts new file mode 100644 index 0000000000000..af5cd500a286a --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/index.ts @@ -0,0 +1,9 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { TabAliases } from './tab_aliases'; +export { TabMappings } from './tab_mappings'; +export { TabSettings } from './tab_settings'; diff --git a/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_aliases.tsx b/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_aliases.tsx new file mode 100644 index 0000000000000..bcf59fd13bad6 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_aliases.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 from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCodeBlock, EuiCallOut } from '@elastic/eui'; + +import { Aliases } from '../../../../../../common'; + +interface Props { + aliases: Aliases | undefined; +} + +export const TabAliases: React.FunctionComponent = ({ aliases }) => { + if (aliases && Object.keys(aliases).length) { + return ( +
+ {JSON.stringify(aliases, null, 2)} +
+ ); + } + + return ( + + } + iconType="pin" + data-test-subj="noAliasesCallout" + size="s" + /> + ); +}; diff --git a/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_mappings.tsx b/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_mappings.tsx new file mode 100644 index 0000000000000..3c3d88345e5a1 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_mappings.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCodeBlock, EuiCallOut } from '@elastic/eui'; +import { Mappings } from '../../../../../../common'; + +interface Props { + mappings: Mappings | undefined; +} + +export const TabMappings: React.FunctionComponent = ({ mappings }) => { + if (mappings && Object.keys(mappings).length) { + return ( +
+ {JSON.stringify(mappings, null, 2)} +
+ ); + } + + return ( + + } + iconType="pin" + data-test-subj="noMappingsCallout" + size="s" + /> + ); +}; diff --git a/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_settings.tsx b/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_settings.tsx new file mode 100644 index 0000000000000..6d5cf09588a1c --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/shared/components/details_panel/tab_settings.tsx @@ -0,0 +1,38 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import { FormattedMessage } from '@kbn/i18n/react'; +import { EuiCodeBlock, EuiCallOut } from '@elastic/eui'; +import { IndexSettings } from '../../../../../../common'; + +interface Props { + settings: IndexSettings | undefined; +} + +export const TabSettings: React.FunctionComponent = ({ settings }) => { + if (settings && Object.keys(settings).length) { + return ( +
+ {JSON.stringify(settings, null, 2)} +
+ ); + } + + return ( + + } + iconType="pin" + data-test-subj="noSettingsCallout" + size="s" + /> + ); +}; diff --git a/x-pack/plugins/index_management/public/application/components/shared/components/index.ts b/x-pack/plugins/index_management/public/application/components/shared/components/index.ts new file mode 100644 index 0000000000000..90d66bd1a5da4 --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/shared/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 { TabAliases, TabMappings, TabSettings } from './details_panel'; diff --git a/x-pack/plugins/index_management/public/application/components/shared/index.ts b/x-pack/plugins/index_management/public/application/components/shared/index.ts new file mode 100644 index 0000000000000..e015ef72e244f --- /dev/null +++ b/x-pack/plugins/index_management/public/application/components/shared/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 { TabAliases, TabMappings, TabSettings } from './components'; diff --git a/x-pack/plugins/index_management/public/application/index.tsx b/x-pack/plugins/index_management/public/application/index.tsx index 5d1096c9ee24e..ff54b4b1bfe35 100644 --- a/x-pack/plugins/index_management/public/application/index.tsx +++ b/x-pack/plugins/index_management/public/application/index.tsx @@ -10,7 +10,7 @@ import { render, unmountComponentAtNode } from 'react-dom'; import { CoreStart } from '../../../../../src/core/public'; -import { API_BASE_PATH, BASE_PATH } from '../../common'; +import { API_BASE_PATH } from '../../common'; import { AppContextProvider, AppDependencies } from './app_context'; import { App } from './app'; @@ -32,7 +32,6 @@ export const renderApp = ( const componentTemplateProviderValues = { httpClient: services.httpService.httpClient, apiBasePath: API_BASE_PATH, - appBasePath: BASE_PATH, trackMetric: services.uiMetricService.trackMetric.bind(services.uiMetricService), docLinks, toasts: notifications.toasts, diff --git a/x-pack/plugins/index_management/public/application/sections/home/home.tsx b/x-pack/plugins/index_management/public/application/sections/home/home.tsx index 51deaf42cc72c..7bd04cdbf0c91 100644 --- a/x-pack/plugins/index_management/public/application/sections/home/home.tsx +++ b/x-pack/plugins/index_management/public/application/sections/home/home.tsx @@ -150,7 +150,14 @@ export const IndexManagementHome: React.FunctionComponent - + From effd504d0b807f1579fcf7547832edd58a282fd6 Mon Sep 17 00:00:00 2001 From: Frank Hassanabad Date: Tue, 16 Jun 2020 23:12:13 -0600 Subject: [PATCH 22/41] [SIEM] Adds example unit test to convert KQL using a nested query ## Summary Adds example unit test to convert KQL using a nested query ### Checklist - [x] [Unit or functional tests](https://github.com/elastic/kibana/blob/master/CONTRIBUTING.md#cross-browser-compatibility) were updated or added to match the most common scenarios --- .../signals/get_filter.test.ts | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.test.ts index b1500e47db843..61cd9cfedd94f 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/signals/get_filter.test.ts @@ -462,6 +462,61 @@ describe('get_filter', () => { }, }); }); + + test('it should work with a nested object queries', () => { + const esQuery = getQueryFilter( + 'category:{ name:Frank and trusted:true }', + 'kuery', + [], + ['auditbeat-*'], + [] + ); + expect(esQuery).toEqual({ + bool: { + must: [], + filter: [ + { + nested: { + path: 'category', + query: { + bool: { + filter: [ + { + bool: { + should: [ + { + match: { + 'category.name': 'Frank', + }, + }, + ], + minimum_should_match: 1, + }, + }, + { + bool: { + should: [ + { + match: { + 'category.trusted': true, + }, + }, + ], + minimum_should_match: 1, + }, + }, + ], + }, + }, + score_mode: 'none', + }, + }, + ], + should: [], + must_not: [], + }, + }); + }); }); describe('getFilter', () => { From 3ee0bf21324841a80e09cb3606b8f9f4887b550d Mon Sep 17 00:00:00 2001 From: Vadim Dalecky Date: Wed, 17 Jun 2020 10:31:16 +0200 Subject: [PATCH 23/41] Explore underlying data (#68496) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 stub discover_enhanced plugin * feat: 🎸 improve view in discover action * feat: 🎸 add URL generator to "View in Discover" action * feat: 🎸 implement navigation and getHref in view raw logs actio * fix: 🐛 disable action in "edit" mode * refactor: 💡 renamce context menu view in discover action * feat: 🎸 rename action to "explore data" * fix: 🐛 correctly generate action path * feat: 🎸 add internationalization to "explore action" * fix: 🐛 correctly parse generated Discover URL path * test: 💍 setup basic functional tests * refactor: 💡 modularize url generation logic * feat: 🎸 export CommonlyUsed type * test: 💍 add test subjects to panel custom time range modal * test: 💍 add index patterna and time range functional tests * refactor: 💡 rename action file * refactor: 💡 use URL generator from Discover plugin's contract * test: 💍 add "Explore raw data" action unit tests * fix: 🐛 import share plugin to check if it is enabled * Update x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.ts Co-authored-by: Matthias Wilhelm * chore: 🤖 add discover_enhanced to KibanaApp codeowners * test: 💍 improve "Explore underlying data" functional tests * test: 💍 improve
link assertion Co-authored-by: Elastic Machine Co-authored-by: Matthias Wilhelm --- .github/CODEOWNERS | 1 + test/functional/page_objects/discover_page.ts | 17 ++ test/functional/page_objects/time_picker.ts | 30 +- x-pack/.i18nrc.json | 1 + x-pack/plugins/discover_enhanced/kibana.json | 9 + .../discover_enhanced/public/actions/index.ts | 7 + .../explore_data_context_menu_action.test.ts | 209 ++++++++++++++ .../explore_data_context_menu_action.ts | 156 +++++++++++ .../public/actions/view_in_discover/index.ts | 7 + .../plugins/discover_enhanced/public/index.ts | 17 ++ .../discover_enhanced/public/plugin.ts | 61 ++++ .../public/custom_time_range_action.tsx | 5 +- .../public/custom_time_range_badge.tsx | 5 +- .../public/customize_time_range_modal.tsx | 5 +- .../drilldowns/dashboard_drilldowns.ts | 33 +-- .../drilldowns/explore_data_panel_action.ts | 83 ++++++ .../apps/dashboard/drilldowns/index.ts | 17 +- .../dashboard/drilldowns/data.json | 263 ++++++++++++++++++ .../dashboard/drilldowns/data.json.gz | Bin 2662 -> 0 bytes .../services/dashboard/drilldowns_manage.ts | 14 + .../functional/services/dashboard/index.ts | 1 + .../services/dashboard/panel_time_range.ts | 56 ++++ x-pack/test/functional/services/index.ts | 2 + 23 files changed, 963 insertions(+), 36 deletions(-) create mode 100644 x-pack/plugins/discover_enhanced/kibana.json create mode 100644 x-pack/plugins/discover_enhanced/public/actions/index.ts create mode 100644 x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.test.ts create mode 100644 x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.ts create mode 100644 x-pack/plugins/discover_enhanced/public/actions/view_in_discover/index.ts create mode 100644 x-pack/plugins/discover_enhanced/public/index.ts create mode 100644 x-pack/plugins/discover_enhanced/public/plugin.ts create mode 100644 x-pack/test/functional/apps/dashboard/drilldowns/explore_data_panel_action.ts create mode 100644 x-pack/test/functional/es_archives/dashboard/drilldowns/data.json delete mode 100644 x-pack/test/functional/es_archives/dashboard/drilldowns/data.json.gz create mode 100644 x-pack/test/functional/services/dashboard/panel_time_range.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 681564b44297f..e6f6e83253c8b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,6 +4,7 @@ # App /x-pack/plugins/dashboard_enhanced/ @elastic/kibana-app +/x-pack/plugins/discover_enhanced/ @elastic/kibana-app /x-pack/plugins/lens/ @elastic/kibana-app /x-pack/plugins/graph/ @elastic/kibana-app /src/legacy/core_plugins/kibana/public/local_application_service/ @elastic/kibana-app diff --git a/test/functional/page_objects/discover_page.ts b/test/functional/page_objects/discover_page.ts index 4e2e06eaecf96..9ba3c9c1c2c88 100644 --- a/test/functional/page_objects/discover_page.ts +++ b/test/functional/page_objects/discover_page.ts @@ -324,6 +324,23 @@ export function DiscoverPageProvider({ getService, getPageObjects }: FtrProvider const nr = await el.getAttribute('data-fetch-counter'); return Number(nr); } + + /** + * Check if Discover app is currently rendered on the screen. + */ + public async isDiscoverAppOnScreen(): Promise { + const result = await find.allByCssSelector('discover-app'); + return result.length === 1; + } + + /** + * Wait until Discover app is rendered on the screen. + */ + public async waitForDiscoverAppOnScreen() { + await retry.waitFor('Discover app on screen', async () => { + return await this.isDiscoverAppOnScreen(); + }); + } } return new DiscoverPage(); diff --git a/test/functional/page_objects/time_picker.ts b/test/functional/page_objects/time_picker.ts index b7c1599fd48c5..20ae89fc1a8d0 100644 --- a/test/functional/page_objects/time_picker.ts +++ b/test/functional/page_objects/time_picker.ts @@ -21,6 +21,18 @@ import moment from 'moment'; import { FtrProviderContext } from '../ftr_provider_context.d'; import { WebElementWrapper } from '../services/lib/web_element_wrapper'; +export type CommonlyUsed = + | 'Today' + | 'This_week' + | 'Last_15 minutes' + | 'Last_30 minutes' + | 'Last_1 hour' + | 'Last_24 hours' + | 'Last_7 days' + | 'Last_30 days' + | 'Last_90 days' + | 'Last_1 year'; + export function TimePickerProvider({ getService, getPageObjects }: FtrProviderContext) { const log = getService('log'); const retry = getService('retry'); @@ -30,18 +42,6 @@ export function TimePickerProvider({ getService, getPageObjects }: FtrProviderCo const { header, common } = getPageObjects(['header', 'common']); const kibanaServer = getService('kibanaServer'); - type CommonlyUsed = - | 'Today' - | 'This_week' - | 'Last_15 minutes' - | 'Last_30 minutes' - | 'Last_1 hour' - | 'Last_24 hours' - | 'Last_7 days' - | 'Last_30 days' - | 'Last_90 days' - | 'Last_1 year'; - class TimePicker { defaultStartTime = 'Sep 19, 2015 @ 06:31:44.000'; defaultEndTime = 'Sep 23, 2015 @ 18:31:44.000'; @@ -227,6 +227,12 @@ export function TimePickerProvider({ getService, getPageObjects }: FtrProviderCo }; } + public async getShowDatesButtonText() { + const button = await testSubjects.find('superDatePickerShowDatesButton'); + const text = await button.getVisibleText(); + return text; + } + public async getTimeDurationForSharing() { return await testSubjects.getAttribute( 'dataSharedTimefilterDuration', diff --git a/x-pack/.i18nrc.json b/x-pack/.i18nrc.json index 85b40d33c4089..21b2df3ba12f8 100644 --- a/x-pack/.i18nrc.json +++ b/x-pack/.i18nrc.json @@ -9,6 +9,7 @@ "xpack.beatsManagement": ["legacy/plugins/beats_management", "plugins/beats_management"], "xpack.canvas": "plugins/canvas", "xpack.dashboard": "plugins/dashboard_enhanced", + "xpack.discover": "plugins/discover_enhanced", "xpack.crossClusterReplication": "plugins/cross_cluster_replication", "xpack.dashboardMode": "legacy/plugins/dashboard_mode", "xpack.data": "plugins/data_enhanced", diff --git a/x-pack/plugins/discover_enhanced/kibana.json b/x-pack/plugins/discover_enhanced/kibana.json new file mode 100644 index 0000000000000..25b2a83baf98f --- /dev/null +++ b/x-pack/plugins/discover_enhanced/kibana.json @@ -0,0 +1,9 @@ +{ + "id": "discoverEnhanced", + "version": "8.0.0", + "kibanaVersion": "kibana", + "server": false, + "ui": true, + "requiredPlugins": ["uiActions", "embeddable", "discover"], + "optionalPlugins": ["share"] +} diff --git a/x-pack/plugins/discover_enhanced/public/actions/index.ts b/x-pack/plugins/discover_enhanced/public/actions/index.ts new file mode 100644 index 0000000000000..cbb955fa46340 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/public/actions/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 * from './view_in_discover'; diff --git a/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.test.ts b/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.test.ts new file mode 100644 index 0000000000000..a7167d2e2e691 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.test.ts @@ -0,0 +1,209 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { + ExploreDataContextMenuAction, + ACTION_EXPLORE_DATA, + Params, + PluginDeps, +} from './explore_data_context_menu_action'; +import { coreMock } from '../../../../../../src/core/public/mocks'; +import { UrlGeneratorContract } from '../../../../../../src/plugins/share/public'; +import { i18n } from '@kbn/i18n'; +import { + VisualizeEmbeddableContract, + VISUALIZE_EMBEDDABLE_TYPE, +} from '../../../../../../src/plugins/visualizations/public'; +import { ViewMode } from '../../../../../../src/plugins/embeddable/public'; + +const i18nTranslateSpy = (i18n.translate as unknown) as jest.SpyInstance; + +jest.mock('@kbn/i18n', () => ({ + i18n: { + translate: jest.fn((key, options) => options.defaultMessage), + }, +})); + +afterEach(() => { + i18nTranslateSpy.mockClear(); +}); + +const setup = () => { + type UrlGenerator = UrlGeneratorContract<'DISCOVER_APP_URL_GENERATOR'>; + + const core = coreMock.createStart(); + + const urlGenerator: UrlGenerator = ({ + id: ACTION_EXPLORE_DATA, + createUrl: jest.fn(() => Promise.resolve('/xyz/app/discover/foo#bar')), + } as unknown) as UrlGenerator; + + const plugins: PluginDeps = { + discover: { + urlGenerator, + }, + }; + + const params: Params = { + start: () => ({ + plugins, + self: {}, + core, + }), + }; + const action = new ExploreDataContextMenuAction(params); + + const input = { + viewMode: ViewMode.VIEW, + }; + + const output = { + indexPatterns: [ + { + id: 'index-ptr-foo', + }, + ], + }; + + const embeddable: VisualizeEmbeddableContract = ({ + type: VISUALIZE_EMBEDDABLE_TYPE, + getInput: () => input, + getOutput: () => output, + } as unknown) as VisualizeEmbeddableContract; + + const context = { + embeddable, + }; + + return { core, plugins, urlGenerator, params, action, input, output, embeddable, context }; +}; + +describe('"Explore underlying data" panel action', () => { + test('action has Discover icon', () => { + const { action } = setup(); + expect(action.getIconType()).toBe('discoverApp'); + }); + + test('title is "Explore underlying data"', () => { + const { action } = setup(); + expect(action.getDisplayName()).toBe('Explore underlying data'); + }); + + test('translates title', () => { + expect(i18nTranslateSpy).toHaveBeenCalledTimes(0); + + setup().action.getDisplayName(); + + expect(i18nTranslateSpy).toHaveBeenCalledTimes(1); + expect(i18nTranslateSpy.mock.calls[0][0]).toBe( + 'xpack.discover.FlyoutCreateDrilldownAction.displayName' + ); + }); + + describe('isCompatible()', () => { + test('returns true when all conditions are met', async () => { + const { action, context } = setup(); + + const isCompatible = await action.isCompatible(context); + + expect(isCompatible).toBe(true); + }); + + test('returns false when URL generator is not present', async () => { + const { action, plugins, context } = setup(); + (plugins.discover as any).urlGenerator = undefined; + + const isCompatible = await action.isCompatible(context); + + expect(isCompatible).toBe(false); + }); + + test('returns false if embeddable is not Visualize embeddable', async () => { + const { action, embeddable, context } = setup(); + (embeddable as any).type = 'NOT_VISUALIZE_EMBEDDABLE'; + + const isCompatible = await action.isCompatible(context); + + expect(isCompatible).toBe(false); + }); + + test('returns false if embeddable does not have index patterns', async () => { + const { action, output, context } = setup(); + delete output.indexPatterns; + + const isCompatible = await action.isCompatible(context); + + expect(isCompatible).toBe(false); + }); + + test('returns false if embeddable index patterns are empty', async () => { + const { action, output, context } = setup(); + output.indexPatterns = []; + + const isCompatible = await action.isCompatible(context); + + expect(isCompatible).toBe(false); + }); + + test('returns false if dashboard is in edit mode', async () => { + const { action, input, context } = setup(); + input.viewMode = ViewMode.EDIT; + + const isCompatible = await action.isCompatible(context); + + expect(isCompatible).toBe(false); + }); + }); + + describe('getHref()', () => { + test('returns URL path generated by URL generator', async () => { + const { action, context } = setup(); + + const href = await action.getHref(context); + + expect(href).toBe('/xyz/app/discover/foo#bar'); + }); + + test('calls URL generator with right arguments', async () => { + const { action, urlGenerator, context } = setup(); + + expect(urlGenerator.createUrl).toHaveBeenCalledTimes(0); + + await action.getHref(context); + + expect(urlGenerator.createUrl).toHaveBeenCalledTimes(1); + expect(urlGenerator.createUrl).toHaveBeenCalledWith({ + indexPatternId: 'index-ptr-foo', + }); + }); + }); + + describe('execute()', () => { + test('calls platform SPA navigation method', async () => { + const { action, context, core } = setup(); + + expect(core.application.navigateToApp).toHaveBeenCalledTimes(0); + + await action.execute(context); + + expect(core.application.navigateToApp).toHaveBeenCalledTimes(1); + }); + + test('calls platform SPA navigation method with right arguments', async () => { + const { action, context, core } = setup(); + + await action.execute(context); + + expect(core.application.navigateToApp).toHaveBeenCalledTimes(1); + expect(core.application.navigateToApp.mock.calls[0]).toEqual([ + 'discover', + { + path: '/foo#bar', + }, + ]); + }); + }); +}); diff --git a/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.ts b/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.ts new file mode 100644 index 0000000000000..d66ca129934a8 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/explore_data_context_menu_action.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. + */ + +/* eslint-disable max-classes-per-file */ + +import { i18n } from '@kbn/i18n'; +import { Action } from '../../../../../../src/plugins/ui_actions/public'; +import { DiscoverStart } from '../../../../../../src/plugins/discover/public'; +import { + EmbeddableContext, + IEmbeddable, + ViewMode, +} from '../../../../../../src/plugins/embeddable/public'; +import { StartServicesGetter } from '../../../../../../src/plugins/kibana_utils/public'; +import { CoreStart } from '../../../../../../src/core/public'; +import { + VisualizeEmbeddableContract, + VISUALIZE_EMBEDDABLE_TYPE, +} from '../../../../../../src/plugins/visualizations/public'; + +// TODO: Replace this logic with KibanaURL once it is available. +// https://github.com/elastic/kibana/issues/64497 +class KibanaURL { + public readonly path: string; + public readonly appName: string; + public readonly appPath: string; + + constructor(path: string) { + const match = path.match(/^.*\/app\/([^\/#]+)(.+)$/); + + if (!match) { + throw new Error('Unexpected Discover URL path.'); + } + + const [, appName, appPath] = match; + + if (!appName || !appPath) { + throw new Error('Could not parse Discover URL path.'); + } + + this.path = path; + this.appName = appName; + this.appPath = appPath; + } +} + +export const ACTION_EXPLORE_DATA = 'ACTION_EXPLORE_DATA'; + +const isOutputWithIndexPatterns = ( + output: unknown +): output is { indexPatterns: Array<{ id: string }> } => { + if (!output || typeof output !== 'object') return false; + return Array.isArray((output as any).indexPatterns); +}; + +const isVisualizeEmbeddable = ( + embeddable: IEmbeddable +): embeddable is VisualizeEmbeddableContract => embeddable?.type === VISUALIZE_EMBEDDABLE_TYPE; + +export interface PluginDeps { + discover: Pick; +} + +export interface CoreDeps { + application: Pick; +} + +export interface Params { + start: StartServicesGetter; +} + +export class ExploreDataContextMenuAction implements Action { + public readonly id = ACTION_EXPLORE_DATA; + + public readonly type = ACTION_EXPLORE_DATA; + + public readonly order = 200; + + constructor(private readonly params: Params) {} + + public getDisplayName() { + return i18n.translate('xpack.discover.FlyoutCreateDrilldownAction.displayName', { + defaultMessage: 'Explore underlying data', + }); + } + + public getIconType() { + return 'discoverApp'; + } + + public async isCompatible({ embeddable }: EmbeddableContext) { + if (!this.params.start().plugins.discover.urlGenerator) return false; + if (!isVisualizeEmbeddable(embeddable)) return false; + if (!this.getIndexPattern(embeddable)) return false; + if (embeddable.getInput().viewMode !== ViewMode.VIEW) return false; + return true; + } + + public async execute({ embeddable }: EmbeddableContext) { + if (!isVisualizeEmbeddable(embeddable)) return; + + const { core } = this.params.start(); + const { appName, appPath } = await this.getUrl(embeddable); + + await core.application.navigateToApp(appName, { + path: appPath, + }); + } + + public async getHref({ embeddable }: EmbeddableContext): Promise { + if (!isVisualizeEmbeddable(embeddable)) { + throw new Error(`Embeddable not supported for "${this.getDisplayName()}" action.`); + } + + const { path } = await this.getUrl(embeddable); + + return path; + } + + private async getUrl(embeddable: VisualizeEmbeddableContract): Promise { + const { plugins } = this.params.start(); + const { urlGenerator } = plugins.discover; + + if (!urlGenerator) { + throw new Error('Discover URL generator not available.'); + } + + const { timeRange, query, filters } = embeddable.getInput(); + const indexPatternId = this.getIndexPattern(embeddable); + + const path = await urlGenerator.createUrl({ + indexPatternId, + filters, + query, + timeRange, + }); + + return new KibanaURL(path); + } + + /** + * @returns Returns empty string if no index pattern ID found. + */ + private getIndexPattern(embeddable: VisualizeEmbeddableContract): string { + const output = embeddable!.getOutput(); + + if (isOutputWithIndexPatterns(output) && output.indexPatterns.length > 0) { + return output.indexPatterns[0].id; + } + + return ''; + } +} diff --git a/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/index.ts b/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/index.ts new file mode 100644 index 0000000000000..8788621365385 --- /dev/null +++ b/x-pack/plugins/discover_enhanced/public/actions/view_in_discover/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 * from './explore_data_context_menu_action'; diff --git a/x-pack/plugins/discover_enhanced/public/index.ts b/x-pack/plugins/discover_enhanced/public/index.ts new file mode 100644 index 0000000000000..943a212dd7c4e --- /dev/null +++ b/x-pack/plugins/discover_enhanced/public/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. + */ + +import { PluginInitializerContext } from 'kibana/public'; +import { DiscoverEnhancedPlugin } from './plugin'; + +export { + DiscoverEnhancedPlugin, + DiscoverEnhancedSetupDependencies, + DiscoverEnhancedStartDependencies, +} from './plugin'; + +export const plugin = (initializerContext: PluginInitializerContext) => + new DiscoverEnhancedPlugin(initializerContext); diff --git a/x-pack/plugins/discover_enhanced/public/plugin.ts b/x-pack/plugins/discover_enhanced/public/plugin.ts new file mode 100644 index 0000000000000..f55c5dab3449b --- /dev/null +++ b/x-pack/plugins/discover_enhanced/public/plugin.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 { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { PluginInitializerContext } from 'kibana/public'; +import { UiActionsSetup, UiActionsStart } from '../../../../src/plugins/ui_actions/public'; +import { createStartServicesGetter } from '../../../../src/plugins/kibana_utils/public'; +import { DiscoverSetup, DiscoverStart } from '../../../../src/plugins/discover/public'; +import { SharePluginSetup, SharePluginStart } from '../../../../src/plugins/share/public'; +import { + EmbeddableSetup, + EmbeddableStart, + EmbeddableContext, + CONTEXT_MENU_TRIGGER, +} from '../../../../src/plugins/embeddable/public'; +import { ExploreDataContextMenuAction, ACTION_EXPLORE_DATA } from './actions'; + +declare module '../../../../src/plugins/ui_actions/public' { + export interface ActionContextMapping { + [ACTION_EXPLORE_DATA]: EmbeddableContext; + } +} + +export interface DiscoverEnhancedSetupDependencies { + discover: DiscoverSetup; + embeddable: EmbeddableSetup; + share?: SharePluginSetup; + uiActions: UiActionsSetup; +} + +export interface DiscoverEnhancedStartDependencies { + discover: DiscoverStart; + embeddable: EmbeddableStart; + share?: SharePluginStart; + uiActions: UiActionsStart; +} + +export class DiscoverEnhancedPlugin + implements + Plugin { + constructor(public readonly initializerContext: PluginInitializerContext) {} + + setup( + core: CoreSetup, + { uiActions, share }: DiscoverEnhancedSetupDependencies + ) { + const start = createStartServicesGetter(core.getStartServices); + + if (!!share) { + const exploreDataAction = new ExploreDataContextMenuAction({ start }); + uiActions.addTriggerAction(CONTEXT_MENU_TRIGGER, exploreDataAction); + } + } + + start(core: CoreStart, plugins: DiscoverEnhancedStartDependencies) {} + + stop() {} +} diff --git a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx index 4da4d648bc0ec..5d9804d2a5c33 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_action.tsx @@ -103,7 +103,10 @@ export class CustomTimeRangeAction implements ActionByType + />, + { + 'data-test-subj': 'customizeTimeRangeModal', + } ); } } diff --git a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.tsx b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.tsx index 59a2fc27267b0..28d99db9b3ef7 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/custom_time_range_badge.tsx @@ -82,7 +82,10 @@ export class CustomTimeRangeBadge implements ActionByType + />, + { + 'data-test-subj': 'customizeTimeRangeModal', + } ); } } diff --git a/x-pack/plugins/ui_actions_enhanced/public/customize_time_range_modal.tsx b/x-pack/plugins/ui_actions_enhanced/public/customize_time_range_modal.tsx index 8a9eeacb66564..993720775a29f 100644 --- a/x-pack/plugins/ui_actions_enhanced/public/customize_time_range_modal.tsx +++ b/x-pack/plugins/ui_actions_enhanced/public/customize_time_range_modal.tsx @@ -101,7 +101,7 @@ export class CustomizeTimeRangeModal extends Component - + - +
diff --git a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts index 2c63baf7c75cb..bcdd3d1f82e7d 100644 --- a/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts +++ b/x-pack/test/functional/apps/dashboard/drilldowns/dashboard_drilldowns.ts @@ -7,9 +7,6 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; -const DASHBOARD_WITH_PIE_CHART_NAME = 'Dashboard with Pie Chart'; -const DASHBOARD_WITH_AREA_CHART_NAME = 'Dashboard With Area Chart'; - const DRILLDOWN_TO_PIE_CHART_NAME = 'Go to pie chart dashboard'; const DRILLDOWN_TO_AREA_CHART_NAME = 'Go to area chart dashboard'; @@ -18,8 +15,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { const dashboardDrilldownPanelActions = getService('dashboardDrilldownPanelActions'); const dashboardDrilldownsManage = getService('dashboardDrilldownsManage'); const PageObjects = getPageObjects(['dashboard', 'common', 'header', 'timePicker']); - const kibanaServer = getService('kibanaServer'); - const esArchiver = getService('esArchiver'); const pieChart = getService('pieChart'); const log = getService('log'); const browser = getService('browser'); @@ -30,19 +25,14 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { describe('Dashboard Drilldowns', function () { before(async () => { log.debug('Dashboard Drilldowns:initTests'); - await esArchiver.loadIfNeeded('logstash_functional'); - await esArchiver.load('dashboard/drilldowns'); - await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' }); await PageObjects.common.navigateToApp('dashboard'); await PageObjects.dashboard.preserveCrossAppState(); }); - after(async () => { - await esArchiver.unload('dashboard/drilldowns'); - }); - it('should create dashboard to dashboard drilldown, use it, and then delete it', async () => { - await PageObjects.dashboard.gotoDashboardEditMode(DASHBOARD_WITH_PIE_CHART_NAME); + await PageObjects.dashboard.gotoDashboardEditMode( + dashboardDrilldownsManage.DASHBOARD_WITH_PIE_CHART_NAME + ); // create drilldown await dashboardPanelActions.openContextMenu(); @@ -51,7 +41,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await dashboardDrilldownsManage.expectsCreateDrilldownFlyoutOpen(); await dashboardDrilldownsManage.fillInDashboardToDashboardDrilldownWizard({ drilldownName: DRILLDOWN_TO_AREA_CHART_NAME, - destinationDashboardTitle: DASHBOARD_WITH_AREA_CHART_NAME, + destinationDashboardTitle: dashboardDrilldownsManage.DASHBOARD_WITH_AREA_CHART_NAME, }); await dashboardDrilldownsManage.saveChanges(); await dashboardDrilldownsManage.expectsCreateDrilldownFlyoutClose(); @@ -60,10 +50,13 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { expect(await PageObjects.dashboard.getPanelDrilldownCount()).to.be(1); // save dashboard, navigate to view mode - await PageObjects.dashboard.saveDashboard(DASHBOARD_WITH_PIE_CHART_NAME, { - saveAsNew: false, - waitDialogIsClosed: true, - }); + await PageObjects.dashboard.saveDashboard( + dashboardDrilldownsManage.DASHBOARD_WITH_PIE_CHART_NAME, + { + saveAsNew: false, + waitDialogIsClosed: true, + } + ); // trigger drilldown action by clicking on a pie and picking drilldown action by it's name await pieChart.filterOnPieSlice('40,000'); @@ -117,7 +110,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { }); it('browser back/forward navigation works after drilldown navigation', async () => { - await PageObjects.dashboard.loadSavedDashboard(DASHBOARD_WITH_AREA_CHART_NAME); + await PageObjects.dashboard.loadSavedDashboard( + dashboardDrilldownsManage.DASHBOARD_WITH_AREA_CHART_NAME + ); const originalTimeRangeDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); await brushAreaChart(); await dashboardDrilldownPanelActions.expectMultipleActionsMenuOpened(); diff --git a/x-pack/test/functional/apps/dashboard/drilldowns/explore_data_panel_action.ts b/x-pack/test/functional/apps/dashboard/drilldowns/explore_data_panel_action.ts new file mode 100644 index 0000000000000..24d6e820ac0eb --- /dev/null +++ b/x-pack/test/functional/apps/dashboard/drilldowns/explore_data_panel_action.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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +const ACTION_ID = 'ACTION_EXPLORE_DATA'; +const EXPLORE_RAW_DATA_ACTION_TEST_SUBJ = `embeddablePanelAction-${ACTION_ID}`; + +export default function ({ getService, getPageObjects }: FtrProviderContext) { + const drilldowns = getService('dashboardDrilldownsManage'); + const { dashboard, discover, common, timePicker } = getPageObjects([ + 'dashboard', + 'discover', + 'common', + 'timePicker', + ]); + const panelActions = getService('dashboardPanelActions'); + const panelActionsTimeRange = getService('dashboardPanelTimeRange'); + const testSubjects = getService('testSubjects'); + const kibanaServer = getService('kibanaServer'); + + describe('Explore underlying data - panel action', function () { + before(async () => { + await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash*' }); + await common.navigateToApp('dashboard'); + await dashboard.preserveCrossAppState(); + }); + + after(async () => { + await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' }); + }); + + it('action exists in panel context menu', async () => { + await dashboard.loadSavedDashboard(drilldowns.DASHBOARD_WITH_PIE_CHART_NAME); + await panelActions.openContextMenu(); + await testSubjects.existOrFail(EXPLORE_RAW_DATA_ACTION_TEST_SUBJ); + }); + + it('is a link element', async () => { + const actionElement = await testSubjects.find(EXPLORE_RAW_DATA_ACTION_TEST_SUBJ); + const tag = await actionElement.getTagName(); + + expect(tag.toLowerCase()).to.be('a'); + }); + + it('navigates to Discover app to index pattern of the panel on action click', async () => { + await testSubjects.clickWhenNotDisabled(EXPLORE_RAW_DATA_ACTION_TEST_SUBJ); + await discover.waitForDiscoverAppOnScreen(); + + const el = await testSubjects.find('indexPattern-switch-link'); + const text = await el.getVisibleText(); + + expect(text).to.be('logstash-*'); + }); + + it('carries over panel time range', async () => { + await common.navigateToApp('dashboard'); + + await dashboard.gotoDashboardEditMode(drilldowns.DASHBOARD_WITH_PIE_CHART_NAME); + + await panelActions.openContextMenu(); + await panelActionsTimeRange.clickTimeRangeActionInContextMenu(); + await panelActionsTimeRange.clickToggleQuickMenuButton(); + await panelActionsTimeRange.clickCommonlyUsedTimeRange('Last_90 days'); + await panelActionsTimeRange.clickModalPrimaryButton(); + + await dashboard.saveDashboard('Dashboard with Pie Chart'); + + await panelActions.openContextMenu(); + await testSubjects.clickWhenNotDisabled(EXPLORE_RAW_DATA_ACTION_TEST_SUBJ); + await discover.waitForDiscoverAppOnScreen(); + + const text = await timePicker.getShowDatesButtonText(); + const lowercaseText = text.toLowerCase(); + + expect(lowercaseText.includes('last 90 days')).to.be(true); + }); + }); +} diff --git a/x-pack/test/functional/apps/dashboard/drilldowns/index.ts b/x-pack/test/functional/apps/dashboard/drilldowns/index.ts index d1081b053a8b9..19d85ad0e448f 100644 --- a/x-pack/test/functional/apps/dashboard/drilldowns/index.ts +++ b/x-pack/test/functional/apps/dashboard/drilldowns/index.ts @@ -5,9 +5,24 @@ */ import { FtrProviderContext } from '../../../ftr_provider_context'; -export default function ({ loadTestFile }: FtrProviderContext) { +export default function ({ loadTestFile, getService }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + const esArchiver = getService('esArchiver'); + describe('drilldowns', function () { this.tags(['skipFirefox']); + + before(async () => { + await esArchiver.loadIfNeeded('logstash_functional'); + await esArchiver.load('dashboard/drilldowns'); + await kibanaServer.uiSettings.replace({ defaultIndex: 'logstash-*' }); + }); + + after(async () => { + await esArchiver.unload('dashboard/drilldowns'); + }); + loadTestFile(require.resolve('./dashboard_drilldowns')); + loadTestFile(require.resolve('./explore_data_panel_action')); }); } diff --git a/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json b/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json new file mode 100644 index 0000000000000..220daaeb61d0e --- /dev/null +++ b/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json @@ -0,0 +1,263 @@ +{ + "type": "doc", + "value": { + "id": "space:default", + "index": ".kibana", + "source": { + "space": { + "description": "This is the default space!", + "name": "Default" + }, + "type": "space" + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:Visualization☺漢字-DataTable", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "DataTable", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Visualization☺漢字 DataTable", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"table\",\"params\":{\"perPage\":10,\"showPartialRows\":false,\"showMeticsAtAllLevels\":false},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"histogram\",\"schema\":\"bucket\",\"params\":{\"field\":\"bytes\",\"interval\":2000,\"extended_bounds\":{}}}],\"listeners\":{}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:Visualization☺-VerticalBarChart", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "VerticalBarChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Visualization☺ VerticalBarChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"histogram\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"scale\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:Visualization-TileMap", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "TileMap", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Visualization TileMap", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"tile_map\",\"params\":{\"mapType\":\"Scaled Circle Markers\",\"isDesaturated\":true,\"addTooltip\":true,\"heatMaxZoom\":16,\"heatMinOpacity\":0.1,\"heatRadius\":25,\"heatBlur\":15,\"heatNormalizeData\":true,\"wms\":{\"enabled\":false,\"url\":\"https://basemap.nationalmap.gov/arcgis/services/USGSTopo/MapServer/WMSServer\",\"options\":{\"version\":\"1.3.0\",\"layers\":\"0\",\"format\":\"image/png\",\"transparent\":true,\"attribution\":\"Maps provided by USGS\",\"styles\":\"\"}}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"geohash_grid\",\"schema\":\"segment\",\"params\":{\"field\":\"geo.coordinates\",\"autoPrecision\":true,\"precision\":2}}],\"listeners\":{}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "index-pattern:logstash-*", + "index": ".kibana", + "source": { + "index-pattern": { + "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", + "timeFieldName": "@timestamp", + "title": "logstash-*" + }, + "type": "index-pattern" + } + } +} + +{ + "type": "doc", + "value": { + "id": "index-pattern:logstash*", + "index": ".kibana", + "source": { + "index-pattern": { + "fields": "[{\"name\":\"referer\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"agent\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"xss.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.lastname\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.dest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"utc_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.char\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"clientip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"machine.ram\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"links\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"id\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"phpmemory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.twitter:card.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"ip\",\"type\":\"ip\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:modified_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:site_name.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:tag\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"agent.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"headings\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"_source\",\"type\":\"_source\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.og:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"request\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"index.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"memory\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_index\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"relatedContent.twitter:site\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.coordinates\",\"type\":\"geo_point\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"meta.related\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@message.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.article:section\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"xss\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"links.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"geo.srcdest\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"extension.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"machine.os.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@tags\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"host.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:type.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"geo.src\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"spaces.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:image:height.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"url\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:site_name\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:title\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"@message\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.twitter:image.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"@timestamp\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"bytes\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"response\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"meta.user.firstname\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":true,\"doc_values\":false},{\"name\":\"relatedContent.og:image:width.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.og:description.raw\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"relatedContent.article:published_time\",\"type\":\"date\",\"count\":0,\"scripted\":false,\"indexed\":true,\"analyzed\":false,\"doc_values\":true},{\"name\":\"_id\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_type\",\"type\":\"string\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false},{\"name\":\"_score\",\"type\":\"number\",\"count\":0,\"scripted\":false,\"indexed\":false,\"analyzed\":false,\"doc_values\":false}]", + "timeFieldName": "@timestamp", + "title": "logstash*" + }, + "type": "index-pattern" + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:Visualization-PieChart", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "PieChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Visualization PieChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"pie\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"isDonut\":false},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"memory\",\"interval\":40000,\"extended_bounds\":{}}}],\"listeners\":{}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:Visualization漢字-LineChart", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "LineChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Visualization漢字 LineChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"line\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"showCircles\":true,\"smoothLines\":false,\"interpolate\":\"linear\",\"scale\":\"linear\",\"drawLinesBetweenPoints\":true,\"radiusRatio\":9,\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"terms\",\"schema\":\"split\",\"params\":{\"field\":\"extension.raw\",\"size\":5,\"order\":\"desc\",\"orderBy\":\"1\",\"row\":false}}],\"listeners\":{}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:Visualization-MetricChart", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "MetricChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Visualization MetricChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"metric\",\"params\":{\"handleNoResults\":true,\"fontSize\":60},\"aggs\":[{\"id\":\"1\",\"type\":\"percentile_ranks\",\"schema\":\"metric\",\"params\":{\"field\":\"memory\",\"values\":[99]}}],\"listeners\":{}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "visualization:Visualization漢字-AreaChart", + "index": ".kibana", + "source": { + "type": "visualization", + "visualization": { + "description": "AreaChart", + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"index\":\"logstash-*\",\"query\":{\"query_string\":{\"query\":\"*\",\"analyze_wildcard\":true}},\"filter\":[]}" + }, + "title": "Visualization漢字 AreaChart", + "uiStateJSON": "{}", + "version": 1, + "visState": "{\"title\":\"New Visualization\",\"type\":\"area\",\"params\":{\"shareYAxis\":true,\"addTooltip\":true,\"addLegend\":true,\"smoothLines\":false,\"scale\":\"linear\",\"interpolate\":\"linear\",\"mode\":\"stacked\",\"times\":[],\"addTimeMarker\":false,\"defaultYExtents\":false,\"setYExtents\":false,\"yAxis\":{}},\"aggs\":[{\"id\":\"1\",\"type\":\"count\",\"schema\":\"metric\",\"params\":{}},{\"id\":\"2\",\"type\":\"date_histogram\",\"schema\":\"segment\",\"params\":{\"field\":\"@timestamp\",\"interval\":\"auto\",\"customInterval\":\"2h\",\"min_doc_count\":1,\"extended_bounds\":{}}}],\"listeners\":{}}" + } + } + } +} + +{ + "type": "doc", + "value": { + "id": "dashboard:24f3f950-69d9-11ea-a14d-e341629a29e6", + "index": ".kibana", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"version\":\"7.7.0\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"e637d5f0-a7e6-4635-81ed-39f2b1aac6f4\"},\"panelIndex\":\"e637d5f0-a7e6-4635-81ed-39f2b1aac6f4\",\"embeddableConfig\":{\"enhancements\":{\"dynamicActions\":{\"events\":[{\"eventId\":\"ffd3e4dc-cb1a-419f-afeb-03e8c7742bbf\",\"triggers\":[\"VALUE_CLICK_TRIGGER\",\"SELECT_RANGE_TRIGGER\"],\"action\":{\"name\":\"Go to pie chart dashboard\",\"config\":{\"dashboardId\":\"41e77910-69d9-11ea-a14d-e341629a29e6\",\"useCurrentDateRange\":true,\"useCurrentFilters\":true},\"factoryId\":\"DASHBOARD_TO_DASHBOARD_DRILLDOWN\"}}]}}},\"panelRefName\":\"panel_0\"}]", + "refreshInterval": { "pause": true, "value": 0 }, + "timeFrom": "2015-09-19T17:34:10.297Z", + "timeRestore": true, + "timeTo": "2015-09-23T00:09:17.180Z", + "title": "Dashboard With Area Chart", + "version": 1 + }, + "references": [ + { + "id": "Visualization漢字-AreaChart", + "name": "panel_0", + "type": "visualization" + } + ], + "type": "dashboard", + "updated_at": "2020-03-19T11:59:53.701Z" + } + } +} + +{ + "type": "doc", + "value": { + "id": "dashboard:41e77910-69d9-11ea-a14d-e341629a29e6", + "index": ".kibana", + "source": { + "dashboard": { + "description": "", + "hits": 0, + "kibanaSavedObjectMeta": { + "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[]}" + }, + "optionsJSON": "{\"useMargins\":true,\"hidePanelTitles\":false}", + "panelsJSON": "[{\"version\":\"7.7.0\",\"gridData\":{\"w\":24,\"h\":15,\"x\":0,\"y\":0,\"i\":\"8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\"},\"panelIndex\":\"8c5df6b2-0cc9-4887-a2d9-6a9a192f3407\",\"embeddableConfig\":{},\"panelRefName\":\"panel_0\"}]", + "refreshInterval": { "pause": true, "value": 0 }, + "timeFrom": "2015-09-19T17:34:10.297Z", + "timeRestore": true, + "timeTo": "2015-09-23T00:09:17.180Z", + "title": "Dashboard with Pie Chart", + "version": 1 + }, + "references": [ + { + "id": "Visualization-PieChart", + "name": "panel_0", + "type": "visualization" + } + ], + "type": "dashboard", + "updated_at": "2020-03-19T11:59:53.701Z" + } + } +} + + diff --git a/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json.gz b/x-pack/test/functional/es_archives/dashboard/drilldowns/data.json.gz deleted file mode 100644 index a9b23ca7a579bdd2de633c67e386a31313162e2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2662 zcmV-s3YqmEiwFoonWQOZ*BnXT-|cpxD~$7Q?R=1L^3JKlBKISwl{U_ z*d9rn%*OU`AQBYOkOY?iEh`>9M|<7-zCfo>)0y@;dH{kHDanqr>jV7i;;teF7{9waCx6-id=jrT3esV z6h$bfGnyvOstZFsULpX=#mq@a%n6M|7ZaZ_1O9Oz8)_IsKJ`1*t9&Rzp=9=0F``)tU;pu+fBx;?fB#GK7;!W~(*S?F zK5{N9;}n9fksnjrIuG)mZ1gd@#qP!Q&)DJbF-Mhd1XCC#jz5;H{c(J8E_%Da&Sbc5 z46hpjoiUD>-~9b`~94$-ybHW3up6!Y^whEn+F-LqQ%Cg*eixZY<%qmj}lg}v8<*-tS zb38XHV@sig(PT3hV@pzu5)`sb2Qf}A(M;T7nb5?1I=@5-Cny-vxwywe0mG^VEJ7T1 z$Pa_y4Bz6QXcrnnvzfTQ66SE_h*p&Who%viB#9x zxO2UyY3h8&d_zEw;2`U0y5N|}b`pUtA%uY3HccTnzT+5t$hD`yq^p=%-atzLF8bsvxjj3fIFshiQj6c9pg#s>+p4CfowJ6yj<$!Dq691~Q^ z`{_hP53isF-bP(0rtgXzIP9o6-6t{#6MVl>4kw?fSsbHnO zuPASWRH)a=ug_@`3ZbwlpH{=na{+K9${M!>GHH^l*(ZaoR;OjkTLQGm zV)wd{5j?>@mjn_*owXMWuM?(8Pz2?EBC)4XC;4wom zz6fwO&~;O)}JvxKiH0lC_;yIF^i;(>DLoUt2-}F4L8*!adpJ?9RcJTIrPqbIhO#V|pjmNqIbbCk zGuSHMBl3=vJFgU^T?-DtACOikFMVAt0vXzq8vHBQx|5ycNpQ= z7VX+!jedqEuAPgA-aRxLP0n*@R*YQQ*O`qUNCd)tYcjW>Q8{)tp;zUgOnfp6Ipu3= zc=~jh_K23aqO*<^U1-*VT(M)iCz&+YlJ+x|0?!vCWfZF)w$@{AauZhcmQdT4fXb^& zc1(#{me_f{0-DhbG;&r+aaA9u$vs*wIBQQx8>=(5;EKgGV!GLQ6Jo~n7Y+FY7_Cvo zyEds_AI367)@-pmrqfh%s#1FdZ^aeOnUW=r<|Q-zzF8FCwLvxAC@&_rH7~E!FIs_* z8Z2-_z-pgns-11h%YwRBv+Fc}yyZ=?cD5@fxa+4j-3dCcw(F;vI?NodeK@aU?P|5< zN7w3W_ExC-GZp!1nn#jt-=@{)lh4{gUu|JIf0vEZX+W5-dx_Xy|I}m0v%>cCe4qPk zIA9J<@UKUjZ)4%6QQ3GB;vdAP=I3g=@d|$%+xDlFzIK0bLvr=2_V2O@>5^dG`yAI; zc*)z4wu!pKeMm9MV&s{&GZJ=8qm-{gQvWXGuWx}VE#sB;5_ZixZA4aQ1)PycdvLDv z@PeaL9Tc!t;vEL5*c$wtQ7TRj$Tk(0o@F7W+!vyjHwepsh-n~8mtkd>^46`(E>vZ* zkGGi5F^(?9(qUR+0HG`%?wgEqJKpq31&8bvIzKH(BeoLCTQVrKK z24$-xytWG+X*8t_=FJ`qHszfjE3#5*YO7XX0tbN2TjYusEMqu+r*u& z)oTw>dw_f2jz&fQk3vm3qRm zGU5F*5|x6~CoaB35e_CI{#WxpWnp8{UUYP|b~Hu5)mKMTi1QlM85(epsNvdOF~qex zY(v1RcmZ9g|4CLa_Bwrc-!q%2k9*B-ue0Agu&~?g47~Q#LdfZP-Arc5$7zAjPkT^! zYBzdx`ZjUd?x zc*{|mh|@#Brg#K?h*xg2YWzVu;%d?sGy@z%p`yk+J{Dk%w z#m94Tw#ZF(yoj{#2z%$n?lwWN!MUo_kO}q@%={dvM2rb11)kuiWN?Ke=2~J6@ec_N zg&(&~YrkoN3I-FaKkRgemf30#`k&S(JfZXhaf+_1jT2h#s@<8G=Fl7rt$xcoFxR?L zIsG^{i1CqdU#4?oBcGR2_QuR Date: Wed, 17 Jun 2020 12:10:28 +0200 Subject: [PATCH 24/41] [APM] Only add decimals for numbers below 10 (#69334) --- .../apm/e2e/cypress/integration/snapshots.js | 6 +- .../ServiceList/__test__/List.test.js | 2 +- .../__snapshots__/CustomPlot.test.js.snap | 6 +- .../Histogram/__test__/Histogram.test.js | 10 +- .../__snapshots__/Histogram.test.js.snap | 24 ++-- .../Timeline/Marker/ErrorMarker.test.tsx | 2 +- .../formatters/__test__/duration.test.ts | 12 +- .../apm/public/utils/formatters/duration.ts | 119 +++++++++++------- 8 files changed, 102 insertions(+), 79 deletions(-) diff --git a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js index 2fae8bdab2b30..d4c8ba4910850 100644 --- a/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js +++ b/x-pack/plugins/apm/e2e/cypress/integration/snapshots.js @@ -1,9 +1,9 @@ module.exports = { APM: { 'Transaction duration charts': { - '1': '350.0 ms', - '2': '175.0 ms', - '3': '0.0 ms', + '1': '350 ms', + '2': '175 ms', + '3': '0 ms', }, }, __version: '4.5.0', diff --git a/x-pack/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 index 09fef5da16ae7..927779b571fd8 100644 --- a/x-pack/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 @@ -40,7 +40,7 @@ describe('ServiceOverview -> List', () => { expect(renderedColumns[0]).toMatchSnapshot(); expect(renderedColumns.slice(2)).toEqual([ 'python', - '91.5 ms', + '92 ms', '86.9 tpm', '12.6 err.', ]); diff --git a/x-pack/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 index ba3174156d5d4..6c5a200fb6f27 100644 --- a/x-pack/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 @@ -9,7 +9,7 @@ Array [ "text": Avg. - 467.6 ms + 468 ms , }, @@ -2744,7 +2744,7 @@ Array [ - 467.6 ms + 468 ms @@ -5923,7 +5923,7 @@ Array [ - 467.6 ms + 468 ms diff --git a/x-pack/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 index f84b0cfeda369..7eaeecca31b36 100644 --- a/x-pack/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 @@ -11,8 +11,8 @@ import d3 from 'd3'; import { HistogramInner } from '../index'; import response from './response.json'; import { - asDecimal, getDurationFormatter, + asInteger, } from '../../../../../utils/formatters'; import { toJson } from '../../../../../utils/testHelpers'; import { getFormattedBuckets } from '../../../../app/TransactionDetails/Distribution/index'; @@ -33,8 +33,8 @@ describe('Histogram', () => { transactionId="myTransactionId" onClick={onClick} formatX={(time) => timeFormatter(time).formatted} - formatYShort={(t) => `${asDecimal(t)} occ.`} - formatYLong={(t) => `${asDecimal(t)} occurrences`} + formatYShort={(t) => `${asInteger(t)} occ.`} + formatYLong={(t) => `${asInteger(t)} occurrences`} tooltipHeader={(bucket) => { const xFormatted = timeFormatter(bucket.x); const x0Formatted = timeFormatter(bucket.x0); @@ -78,9 +78,9 @@ describe('Histogram', () => { const tooltips = wrapper.find('Tooltip'); expect(tooltips.length).toBe(1); - expect(tooltips.prop('header')).toBe('811.1 - 926.9 ms'); + expect(tooltips.prop('header')).toBe('811 - 927 ms'); expect(tooltips.prop('tooltipPoints')).toEqual([ - { value: '49.0 occurrences' }, + { value: '49 occurrences' }, ]); expect(tooltips.prop('x')).toEqual(869010); expect(tooltips.prop('y')).toEqual(27.5); diff --git a/x-pack/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 index ff38ae4b563dd..1f935af7c8999 100644 --- a/x-pack/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 @@ -127,7 +127,7 @@ exports[`Histogram Initially should have default markup 1`] = ` textAnchor="middle" transform="translate(0, 18)" > - 0.0 ms + 0 ms - 500.0 ms + 500 ms - 1,000.0 ms + 1,000 ms - 1,500.0 ms + 1,500 ms - 2,000.0 ms + 2,000 ms - 2,500.0 ms + 2,500 ms - 3,000.0 ms + 3,000 ms @@ -371,7 +371,7 @@ exports[`Histogram Initially should have default markup 1`] = ` textAnchor="end" transform="translate(-8, 0)" > - 0.0 occ. + 0 occ. - 27.5 occ. + 28 occ. - 55.0 occ. + 55 occ. @@ -1477,7 +1477,7 @@ exports[`Histogram when hovering over a non-empty bucket should have correct mar
- 811.1 - 926.9 ms + 811 - 927 ms
@@ -1488,7 +1488,7 @@ exports[`Histogram when hovering over a non-empty bucket should have correct mar
- 49.0 occurrences + 49 occurrences
diff --git a/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.test.tsx b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.test.tsx index 2b6f0c7aa1319..7dc68910c6bed 100644 --- a/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.test.tsx +++ b/x-pack/plugins/apm/public/components/shared/charts/Timeline/Marker/ErrorMarker.test.tsx @@ -37,7 +37,7 @@ describe('ErrorMarker', () => { act(() => { fireEvent.click(component.getByTestId('popover')); }); - expectTextsInDocument(component, ['10.0 ms']); + expectTextsInDocument(component, ['10 ms']); return component; } function getKueryDecoded(url: string) { diff --git a/x-pack/plugins/apm/public/utils/formatters/__test__/duration.test.ts b/x-pack/plugins/apm/public/utils/formatters/__test__/duration.test.ts index 6d4b65d2aa9b4..c4d59beb4b7a2 100644 --- a/x-pack/plugins/apm/public/utils/formatters/__test__/duration.test.ts +++ b/x-pack/plugins/apm/public/utils/formatters/__test__/duration.test.ts @@ -14,14 +14,14 @@ describe('duration formatters', () => { expect(asDuration(1)).toEqual('1 μs'); expect(asDuration(toMicroseconds(1, 'milliseconds'))).toEqual('1,000 μs'); expect(asDuration(toMicroseconds(1000, 'milliseconds'))).toEqual( - '1,000.0 ms' + '1,000 ms' ); expect(asDuration(toMicroseconds(10000, 'milliseconds'))).toEqual( - '10,000.0 ms' + '10,000 ms' ); - expect(asDuration(toMicroseconds(20, 'seconds'))).toEqual('20.0 s'); - expect(asDuration(toMicroseconds(10, 'minutes'))).toEqual('10.0 min'); - expect(asDuration(toMicroseconds(1, 'hours'))).toEqual('60.0 min'); + expect(asDuration(toMicroseconds(20, 'seconds'))).toEqual('20 s'); + expect(asDuration(toMicroseconds(10, 'minutes'))).toEqual('10 min'); + expect(asDuration(toMicroseconds(1, 'hours'))).toEqual('60 min'); expect(asDuration(toMicroseconds(1.5, 'hours'))).toEqual('1.5 h'); }); @@ -41,7 +41,7 @@ describe('duration formatters', () => { describe('asMilliseconds', () => { it('converts to formatted decimal milliseconds', () => { - expect(asMillisecondDuration(0)).toEqual('0.0 ms'); + expect(asMillisecondDuration(0)).toEqual('0 ms'); }); }); }); diff --git a/x-pack/plugins/apm/public/utils/formatters/duration.ts b/x-pack/plugins/apm/public/utils/formatters/duration.ts index a603faab37538..64a9e3b952b98 100644 --- a/x-pack/plugins/apm/public/utils/formatters/duration.ts +++ b/x-pack/plugins/apm/public/utils/formatters/duration.ts @@ -18,13 +18,6 @@ interface FormatterOptions { type DurationTimeUnit = TimeUnit | 'microseconds'; -interface DurationUnit { - [unit: string]: { - label: string; - convert: (value: number) => string; - }; -} - interface ConvertedDuration { value: string; unit?: string; @@ -38,42 +31,69 @@ export type TimeFormatter = ( type TimeFormatterBuilder = (max: number) => TimeFormatter; -const durationUnit: DurationUnit = { - hours: { - label: i18n.translate('xpack.apm.formatters.hoursTimeUnitLabel', { - defaultMessage: 'h', - }), - convert: (value: number) => - asDecimal(moment.duration(value / 1000).asHours()), - }, - minutes: { - label: i18n.translate('xpack.apm.formatters.minutesTimeUnitLabel', { - defaultMessage: 'min', - }), - convert: (value: number) => - asDecimal(moment.duration(value / 1000).asMinutes()), - }, - seconds: { - label: i18n.translate('xpack.apm.formatters.secondsTimeUnitLabel', { - defaultMessage: 's', - }), - convert: (value: number) => - asDecimal(moment.duration(value / 1000).asSeconds()), - }, - milliseconds: { - label: i18n.translate('xpack.apm.formatters.millisTimeUnitLabel', { - defaultMessage: 'ms', - }), - convert: (value: number) => - asDecimal(moment.duration(value / 1000).asMilliseconds()), - }, - microseconds: { - label: i18n.translate('xpack.apm.formatters.microsTimeUnitLabel', { - defaultMessage: 'μs', - }), - convert: (value: number) => asInteger(value), - }, -}; +function asDecimalOrInteger(value: number) { + // exact 0 or above 10 should not have decimal + if (value === 0 || value >= 10) { + return asInteger(value); + } + return asDecimal(value); +} + +function getUnitLabelAndConvertedValue( + unitKey: DurationTimeUnit, + value: number +) { + switch (unitKey) { + case 'hours': { + return { + unitLabel: i18n.translate('xpack.apm.formatters.hoursTimeUnitLabel', { + defaultMessage: 'h', + }), + convertedValue: asDecimalOrInteger( + moment.duration(value / 1000).asHours() + ), + }; + } + case 'minutes': { + return { + unitLabel: i18n.translate('xpack.apm.formatters.minutesTimeUnitLabel', { + defaultMessage: 'min', + }), + convertedValue: asDecimalOrInteger( + moment.duration(value / 1000).asMinutes() + ), + }; + } + case 'seconds': { + return { + unitLabel: i18n.translate('xpack.apm.formatters.secondsTimeUnitLabel', { + defaultMessage: 's', + }), + convertedValue: asDecimalOrInteger( + moment.duration(value / 1000).asSeconds() + ), + }; + } + case 'milliseconds': { + return { + unitLabel: i18n.translate('xpack.apm.formatters.millisTimeUnitLabel', { + defaultMessage: 'ms', + }), + convertedValue: asDecimalOrInteger( + moment.duration(value / 1000).asMilliseconds() + ), + }; + } + case 'microseconds': { + return { + unitLabel: i18n.translate('xpack.apm.formatters.microsTimeUnitLabel', { + defaultMessage: 'μs', + }), + convertedValue: asInteger(value), + }; + } + } +} /** * Converts a microseconds value into the unit defined. @@ -87,16 +107,19 @@ function convertTo({ microseconds: Maybe; defaultValue?: string; }): ConvertedDuration { - const duration = durationUnit[unit]; - if (!duration || microseconds == null) { + if (microseconds == null) { return { value: defaultValue, formatted: defaultValue }; } - const convertedValue = duration.convert(microseconds); + const { convertedValue, unitLabel } = getUnitLabelAndConvertedValue( + unit, + microseconds + ); + return { value: convertedValue, - unit: duration.label, - formatted: `${convertedValue} ${duration.label}`, + unit: unitLabel, + formatted: `${convertedValue} ${unitLabel}`, }; } From ab1270e566f878dfc5e9ae226fe42cccb1ff92d6 Mon Sep 17 00:00:00 2001 From: Stratoula Kalafateli Date: Wed, 17 Jun 2020 14:27:05 +0300 Subject: [PATCH 25/41] Replaces the Custom Color Picker on TSVB with the EuiColorPicker (#68888) * Replace the Custom Color Picker on TSVB with the EuiColorPicker * Remove the custom picker sass * Remove private modules of eui and the custom color swatches * Clear the color * changes in test implementation Co-authored-by: Elastic Machine --- .../application/components/_color_picker.scss | 33 --- .../components/_custom_color_picker.scss | 97 --------- .../public/application/components/_index.scss | 1 - .../application/components/color_picker.js | 125 ----------- .../components/color_picker.test.js | 69 ------ .../components/color_picker.test.tsx | 61 ++++++ .../application/components/color_picker.tsx | 95 +++++++++ .../components/custom_color_picker.js | 200 ------------------ .../page_objects/visual_builder_page.ts | 4 +- 9 files changed, 158 insertions(+), 527 deletions(-) delete mode 100644 src/plugins/vis_type_timeseries/public/application/components/_custom_color_picker.scss delete mode 100644 src/plugins/vis_type_timeseries/public/application/components/color_picker.js delete mode 100644 src/plugins/vis_type_timeseries/public/application/components/color_picker.test.js create mode 100644 src/plugins/vis_type_timeseries/public/application/components/color_picker.test.tsx create mode 100644 src/plugins/vis_type_timeseries/public/application/components/color_picker.tsx delete mode 100644 src/plugins/vis_type_timeseries/public/application/components/custom_color_picker.js diff --git a/src/plugins/vis_type_timeseries/public/application/components/_color_picker.scss b/src/plugins/vis_type_timeseries/public/application/components/_color_picker.scss index e486f56fe0fe8..9d50b0875dd0d 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/_color_picker.scss +++ b/src/plugins/vis_type_timeseries/public/application/components/_color_picker.scss @@ -8,39 +8,6 @@ position: relative; } -.tvbColorPicker__swatch-empty, -.tvbColorPicker__swatch { - // SASSTODO: Replace with EUI component - // sass-lint:disable-block placeholder-in-extend - @extend .euiColorPickerSwatch; -} - -.tvbColorPicker__swatch-empty { - background-color: transparent; - background-size: 22px 22px; - background-image: repeating-linear-gradient( - -45deg, - $euiColorDanger, - $euiColorDanger 2px, - transparent 2px, - transparent $euiSize - ); -} - .tvbColorPicker__clear { margin-left: $euiSizeXS; } - -.tvbColorPicker__popover { - position: absolute; - top: $euiSizeL; - z-index: 2; -} - -.tvbColorPicker__cover { - position: fixed; - top: 0; - right: 0; - left: 0; - bottom: 0; -} diff --git a/src/plugins/vis_type_timeseries/public/application/components/_custom_color_picker.scss b/src/plugins/vis_type_timeseries/public/application/components/_custom_color_picker.scss deleted file mode 100644 index f2f5eff35fc5d..0000000000000 --- a/src/plugins/vis_type_timeseries/public/application/components/_custom_color_picker.scss +++ /dev/null @@ -1,97 +0,0 @@ -// EUITODO: Convert to EuiColorPicker -// with additional support for alpha, saturation, swatches - -// SASSTODO: This custom picker moved all styles from react-color inline styles -// to SASS, but it should be in EUI. -// Also, some pixel values were kept as is to match inline styles from react-color -.tvbColorPickerPopUp { - @include euiBottomShadowMedium; - background-color: $euiColorEmptyShade; - border-radius: $euiBorderRadius; - box-sizing: initial; - width: 275px; - font-family: 'Menlo'; -} - -.tvbColorPickerPopUp__saturation { - width: 100%; - padding-bottom: 55%; - position: relative; - border-radius: $euiBorderRadius $euiBorderRadius 0 0; - overflow: hidden; -} - -.tvbColorPickerPopUp__body { - padding: $euiSize; -} - -.tvbColorPickerPopUp__controls { - display: flex; -} - -.tvbColorPickerPopUp__color { - width: $euiSizeXL; - - // The color indicator doesn't work, hiding it until it does - display: none; -} - -.tvbColorPickerPopUp__color-disableAlpha { - width: $euiSizeL; -} - -.tvbColorPickerPopUp__swatch { - margin-top: 6px; - width: $euiSize; - height: $euiSize; - border-radius: $euiSizeS; - position: relative; - overflow: hidden; -} - -.tvbColorPickerPopUp__swatch-disableAlpha { - width: 10px; - height: 10px; - margin: 0; -} - -.tvbColorPickerPopUp__active { - @include euiBottomShadowMedium; - position: absolute; - top: 0; - left: 0; - right: 0; - bottom: 0; - border-radius: $euiSizeS; - z-index: 2; -} - -.tvbColorPickerPopUp__toggles { - flex: 1; -} - -.tvbColorPickerPopUp__hue { - height: 10px; - position: relative; - margin-bottom: $euiSizeS; -} - -.tvbColorPickerPopUp__hue-disableAlpha { - margin-bottom: 0; -} - -.tvbColorPickerPopUp__alpha { - height: 10px; - position: relative; -} - -.tvbColorPickerPopUp__alpha-disableAlpha { - display: none; -} - -.tvbColorPickerPopUp__swatches { - display: flex; - flex-wrap: wrap; - justify-content: center; - margin-top: $euiSize; -} diff --git a/src/plugins/vis_type_timeseries/public/application/components/_index.scss b/src/plugins/vis_type_timeseries/public/application/components/_index.scss index 3a10b07c23e2b..4ee5c1863946b 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/_index.scss +++ b/src/plugins/vis_type_timeseries/public/application/components/_index.scss @@ -1,7 +1,6 @@ @import './annotations_editor'; @import './color_rules'; @import './color_picker'; -@import './custom_color_picker'; @import './error'; @import './no_data'; @import './markdown_editor'; diff --git a/src/plugins/vis_type_timeseries/public/application/components/color_picker.js b/src/plugins/vis_type_timeseries/public/application/components/color_picker.js deleted file mode 100644 index f12797518cd28..0000000000000 --- a/src/plugins/vis_type_timeseries/public/application/components/color_picker.js +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* eslint-disable jsx-a11y/click-events-have-key-events, jsx-a11y/no-static-element-interactions */ -// The color picker is not yet accessible. - -import PropTypes from 'prop-types'; -import React, { Component } from 'react'; -import { EuiIconTip } from '@elastic/eui'; -import { CustomColorPicker } from './custom_color_picker'; -import { i18n } from '@kbn/i18n'; - -export class ColorPicker extends Component { - constructor(props) { - super(props); - this.state = { - displayPicker: false, - color: {}, - }; - } - - handleChange = (color) => { - const { rgb } = color; - const part = {}; - part[this.props.name] = `rgba(${rgb.r},${rgb.g},${rgb.b},${rgb.a})`; - if (this.props.onChange) this.props.onChange(part); - }; - - handleClick = () => { - this.setState({ displayPicker: !this.state.displayColorPicker }); - }; - - handleClose = () => { - this.setState({ displayPicker: false }); - }; - - handleClear = () => { - const part = {}; - part[this.props.name] = null; - this.props.onChange(part); - }; - - renderSwatch() { - if (!this.props.value) { - return ( -