From a9d73e868395c7d29ee5b96a38756b758ae6e802 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Tue, 16 Jun 2020 18:04:52 +0200 Subject: [PATCH] [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'); + }, }; }