From e90ca93687057675b8fc836d77995b7e00635e22 Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 13 Jan 2020 20:31:28 +0100 Subject: [PATCH] [Uptime] Most recent checks info on details page (#54340) * update API * update query * hide layer control and added loc tags * update test * remove unused comment * update API * remove capitalization * style fix * update types * added location status number on details page * useref instead of createRef * update interface * update import * removed redundant file * fix header for empty data * refactor for most recent check * remove redundant code * remone unused translation * update status bar * update styling * update snaps * added API tests * fix types * fixing integration tests and a typo * remove unused translations * update tests * fixed PR feedback * update feedback * update messaging * update snap * added timestamp in front of tags * update snaps * improve readability * PR feedbacka and snaps * PR feedbacka and snaps * update txt * snaps * fix timestamp issue in tests Co-authored-by: Elastic Machine --- .../common/runtime_types/monitor/locations.ts | 1 + .../location_status_tags.test.tsx.snap | 577 ++++++++++++++++++ .../__tests__/location_status_tags.test.tsx | 101 +++ .../functional/location_map/index.tsx | 1 + .../location_map/location_status_tags.tsx | 108 +++- .../__test__/status_by_location.test.tsx | 7 + .../elasticsearch_monitors_adapter.ts | 3 +- 7 files changed, 768 insertions(+), 30 deletions(-) create mode 100644 x-pack/legacy/plugins/uptime/public/components/functional/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap create mode 100644 x-pack/legacy/plugins/uptime/public/components/functional/location_map/__tests__/location_status_tags.test.tsx diff --git a/x-pack/legacy/plugins/uptime/common/runtime_types/monitor/locations.ts b/x-pack/legacy/plugins/uptime/common/runtime_types/monitor/locations.ts index a40453b3671b7..ea3cfe677ca99 100644 --- a/x-pack/legacy/plugins/uptime/common/runtime_types/monitor/locations.ts +++ b/x-pack/legacy/plugins/uptime/common/runtime_types/monitor/locations.ts @@ -10,6 +10,7 @@ import { CheckGeoType, SummaryType } from '../common'; export const MonitorLocationType = t.partial({ summary: SummaryType, geo: CheckGeoType, + timestamp: t.string, }); // Typescript type for type checking diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap b/x-pack/legacy/plugins/uptime/public/components/functional/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap new file mode 100644 index 0000000000000..6228183e7c2b2 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/functional/location_map/__tests__/__snapshots__/location_status_tags.test.tsx.snap @@ -0,0 +1,577 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StatusByLocation component renders when all locations are down 1`] = ` +.c3 { + display: inline-block; + margin-left: 4px; +} + +.c2 { + font-weight: 600; +} + +.c1 { + margin-bottom: 5px; +} + +.c0 { + padding: 10px; + max-height: 229px; + overflow: hidden; +} + +
+ +
+ + + +
+
+ Islamabad +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ Berlin +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ +
+`; + +exports[`StatusByLocation component renders when all locations are up 1`] = ` +.c3 { + display: inline-block; + margin-left: 4px; +} + +.c2 { + font-weight: 600; +} + +.c1 { + margin-bottom: 5px; +} + +.c0 { + padding: 10px; + max-height: 229px; + overflow: hidden; +} + +
+ + +
+ + + +
+
+ Islamabad +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ Berlin +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+
+`; + +exports[`StatusByLocation component renders when there are many location 1`] = ` +Array [ + .c3 { + display: inline-block; + margin-left: 4px; +} + +.c2 { + font-weight: 600; +} + +.c1 { + margin-bottom: 5px; +} + +.c0 { + padding: 10px; + max-height: 229px; + overflow: hidden; +} + +
+ +
+ + + +
+
+ Islamabad +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ Berlin +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ st-paul +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ Tokya +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ New York +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ Toronto +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ Sydney +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ + + +
+
+ Paris +
+
+
+
+
+ +
+
+ 3d ago +
+
+
+
+
+ +
, + .c0 { + padding-left: 18px; +} + +
+
+
+

+ 1 Others ... +

+
+
+
, +] +`; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/location_map/__tests__/location_status_tags.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/location_map/__tests__/location_status_tags.test.tsx new file mode 100644 index 0000000000000..21e5881654533 --- /dev/null +++ b/x-pack/legacy/plugins/uptime/public/components/functional/location_map/__tests__/location_status_tags.test.tsx @@ -0,0 +1,101 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import React from 'react'; +import moment from 'moment'; +import { renderWithIntl } from 'test_utils/enzyme_helpers'; +import { MonitorLocation } from '../../../../../common/runtime_types/monitor'; +import { LocationStatusTags } from '../'; + +describe('StatusByLocation component', () => { + let monitorLocations: MonitorLocation[]; + + const start = moment('2020-01-10T12:22:32.567Z'); + beforeAll(() => { + moment.prototype.fromNow = jest.fn((date: string) => start.from(date)); + }); + + it('renders when there are many location', () => { + monitorLocations = [ + { + summary: { up: 0, down: 1 }, + geo: { name: 'Islamabad', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', + }, + { + summary: { up: 0, down: 1 }, + geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:28.825Z', + }, + { + summary: { up: 0, down: 1 }, + geo: { name: 'st-paul', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:31.586Z', + }, + { + summary: { up: 0, down: 1 }, + geo: { name: 'Tokya', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:25.771Z', + }, + { + summary: { up: 0, down: 1 }, + geo: { name: 'New York', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:27.485Z', + }, + { + summary: { up: 0, down: 1 }, + geo: { name: 'Toronto', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:28.815Z', + }, + { + summary: { up: 0, down: 1 }, + geo: { name: 'Sydney', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.132Z', + }, + { + summary: { up: 0, down: 1 }, + geo: { name: 'Paris', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.973Z', + }, + ]; + const component = renderWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('renders when all locations are up', () => { + monitorLocations = [ + { + summary: { up: 4, down: 0 }, + geo: { name: 'Islamabad', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', + }, + { + summary: { up: 4, down: 0 }, + geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-08T12:22:28.825Z', + }, + ]; + const component = renderWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('renders when all locations are down', () => { + monitorLocations = [ + { + summary: { up: 0, down: 2 }, + geo: { name: 'Islamabad', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-06T12:22:32.567Z', + }, + { + summary: { up: 0, down: 2 }, + geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:28.825Z', + }, + ]; + const component = renderWithIntl(); + expect(component).toMatchSnapshot(); + }); +}); diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/location_map/index.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/location_map/index.tsx index 1f4b88b971c4c..140d33bbeef66 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/location_map/index.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/location_map/index.tsx @@ -5,3 +5,4 @@ */ export * from './location_map'; +export * from './location_status_tags'; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/location_map/location_status_tags.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/location_map/location_status_tags.tsx index a10d8e02e6863..6563c03ad7c34 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/location_map/location_status_tags.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/location_map/location_status_tags.tsx @@ -7,9 +7,16 @@ import React, { useContext } from 'react'; import styled from 'styled-components'; import { EuiBadge, EuiText } from '@elastic/eui'; +import moment from 'moment'; +import { FormattedMessage } from '@kbn/i18n/react'; import { UptimeSettingsContext } from '../../../contexts'; import { MonitorLocation } from '../../../../common/runtime_types'; +const TimeStampSpan = styled.span` + display: inline-block; + margin-left: 4px; +`; + const TextStyle = styled.div` font-weight: 600; `; @@ -20,54 +27,97 @@ const BadgeItem = styled.div` const TagContainer = styled.div` padding: 10px; - max-height: 200px; + max-height: 229px; overflow: hidden; `; +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(UptimeSettingsContext); - const upLocs: string[] = []; - const downLocs: string[] = []; + const upLocations: StatusTag[] = []; + const downLocations: StatusTag[] = []; locations.forEach((item: any) => { if (item.summary.down === 0) { - upLocs.push(item.geo.name); + upLocations.push({ label: item.geo.name, timestamp: new Date(item.timestamp).valueOf() }); } else { - downLocs.push(item.geo.name); + downLocations.push({ label: item.geo.name, timestamp: new Date(item.timestamp).valueOf() }); } }); + // Sort by recent timestamp + upLocations.sort((a, b) => { + return a.timestamp < b.timestamp ? 1 : b.timestamp < a.timestamp ? -1 : 0; + }); + + moment.locale('en', { + relativeTime: { + future: 'in %s', + past: '%s ago', + s: '%ds', + ss: '%ss', + m: '%dm', + mm: '%dm', + h: '%dh', + hh: '%dh', + d: '%dd', + dd: '%dd', + M: '%d Mon', + MM: '%d Mon', + y: '%d Yr', + yy: '%d Yr', + }, + }); + + const tagLabel = (item: StatusTag, ind: number, color: string) => ( + + + + {item.label} + + + + {moment(item.timestamp).fromNow()} + + + ); + return ( - - - {downLocs.map((item, ind) => ( - - - - {item} - - - - ))} - - - {upLocs.map((item, ind) => ( - - - - {item} - - - - ))} - - + <> + + {downLocations.map((item, ind) => tagLabel(item, ind, danger))} + {upLocations.map((item, ind) => tagLabel(item, ind, gray))} + + {locations.length > 7 && ( + + +

+ +

+
+
+ )} + ); }; diff --git a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/status_by_location.test.tsx b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/status_by_location.test.tsx index 4e515a52b8de6..38864103564ca 100644 --- a/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/status_by_location.test.tsx +++ b/x-pack/legacy/plugins/uptime/public/components/functional/monitor_status_details/__test__/status_by_location.test.tsx @@ -17,6 +17,7 @@ describe('StatusByLocation component', () => { { summary: { up: 4, down: 0 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', }, { summary: { up: 4, down: 0 }, @@ -32,6 +33,7 @@ describe('StatusByLocation component', () => { { summary: { up: 4, down: 0 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', }, ]; const component = renderWithIntl(); @@ -43,6 +45,7 @@ describe('StatusByLocation component', () => { { summary: { up: 0, down: 4 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', }, ]; const component = renderWithIntl(); @@ -54,10 +57,12 @@ describe('StatusByLocation component', () => { { summary: { up: 0, down: 4 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', }, { summary: { up: 0, down: 4 }, geo: { name: 'st-paul', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', }, ]; const component = renderWithIntl(); @@ -69,10 +74,12 @@ describe('StatusByLocation component', () => { { summary: { up: 0, down: 4 }, geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', }, { summary: { up: 4, down: 0 }, geo: { name: 'st-paul', location: { lat: '52.487448', lon: ' 13.394798' } }, + timestamp: '2020-01-09T12:22:32.567Z', }, ]; const component = renderWithIntl(); diff --git a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts index 37a9e032cd442..b237fd8771f58 100644 --- a/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts +++ b/x-pack/legacy/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts @@ -334,7 +334,7 @@ export const elasticsearchMonitorsAdapter: UMMonitorsAdapter = { order: 'desc', }, }, - _source: ['monitor', 'summary', 'observer'], + _source: ['monitor', 'summary', 'observer', '@timestamp'], }, }, }, @@ -365,6 +365,7 @@ export const elasticsearchMonitorsAdapter: UMMonitorsAdapter = { const location: MonitorLocation = { summary: mostRecentLocation?.summary, geo: getGeo(mostRecentLocation?.observer?.geo), + timestamp: mostRecentLocation['@timestamp'], }; monLocs.push(location); }