From f9bdf890ba85de33f136e6777cd905c133694ef0 Mon Sep 17 00:00:00 2001 From: "dave.snider@gmail.com" Date: Thu, 4 Apr 2019 10:26:22 -0700 Subject: [PATCH] Design cleanup of Uptime app (#31663) * uptime design cleanup * uptime design cleanup * test * errorlist now styled * errorlist now styled * errorlist now styled * cleanup * replace color vars with correct naming * some titles * more cleanup * clean up silly gray graph * Address problems with UI update. * Refresh jest snapshots. * Fix busted types. * Refresh jest snapshots broken by busted type fix. * Rename duplicate localization key. * Use same curve type for both check series on monitors page. * Remove unused translations. * Display name instead of ID in ErrorList component. * Update x-pack/plugins/uptime/public/components/functional/ping_list.tsx Co-Authored-By: snide * Update x-pack/plugins/uptime/public/components/functional/ping_list.tsx Co-Authored-By: snide * Modify updated code to avoid flooding console log with errors. * Get functional and unit tests passing. * Fix busted unit test. * Update jest snapshots. * Add panel to empty state. * Avoid rendering monitor list sparkline charts when downSeries has no values. * Remove crosshair synchronization from monitor charts because of display bug. Provide default 0 value to series for check chart. * Fix broken snapshot. * Update monitor list and errors list to handle simple_query_string filters. * Make FilterBar component incremental to avoid overwriting queries that are in progress of being edited. * Update histogram query to support simple_text_query. * Delete hardcoded height prop that was breaking UI in mobile-sized windows. * Fix bug in check histogram function and add tests. * Update API tests and functional UI tests. * Fix type error in test file. * Last few fixes - Center empty prompt - remove crosshairs from sparkline - reconcile styles of text in table * Update snaps * WIP. * Update snapshot query to avoid Apollo Query class and allow manual fetching. * Update SnapshotLoading component to better reflect the actual shape of the Snapshot component. * Introduce HOC to manage GraphQL querying. * Remove unneeded code. * Update monitor page query components to use new query paradigm. * Remove remaining references to apollo query component. * Update filter bar snapshot. * Update empty state. * Fix busted type in test. * Update schema type to avoid server error. * Remove obsolete translations. * Remove more obsolete translations. * Remove obsolete code from Snapshot component. Rewrite graphql HOC with hooks. * Change loading state condition for filter bar. * Simplify app refresh process. * Update loading state for several components to avoid unnecessary renders. * Add default sort order for getAll pings function. * Add translation to bare UI string. * Update API fixtures to handle new default sort direction. * Fix type errors. * Remove unused import. * Change the way component passes children prop. * Fix typing error. --- .../translations/translations/zh-CN.json | 20 - .../plugins/uptime/common/constants/index.ts | 1 + .../plugins/uptime/common/constants/query.ts | 24 + .../uptime/common/graphql/introspection.json | 22 +- x-pack/plugins/uptime/common/graphql/types.ts | 8 +- x-pack/plugins/uptime/public/breadcrumbs.ts | 12 +- .../__snapshots__/error_list.test.tsx.snap | 185 +- .../__snapshots__/filter_bar.test.tsx.snap | 384 +-- .../monitor_charts.test.tsx.snap | 116 +- .../__snapshots__/monitor_list.test.tsx.snap | 2481 ++++++++--------- .../monitor_sparkline.test.tsx.snap | 43 + .../__snapshots__/ping_list.test.tsx.snap | 160 +- .../__snapshots__/snapshot.test.tsx.snap | 152 +- .../snapshot_histogram.test.tsx.snap | 54 +- .../functional/__tests__/error_list.test.tsx | 4 + .../__tests__/format_sparkline_counts.test.ts | 5 +- .../__tests__/monitor_charts.test.tsx | 7 +- .../__tests__/monitor_list.test.tsx | 2 +- .../__tests__/monitor_sparkline.test.tsx | 75 + .../functional/__tests__/ping_list.test.tsx | 2 - .../functional/__tests__/snapshot.test.tsx | 7 +- .../__tests__/snapshot_histogram.test.tsx | 3 +- .../__snapshots__/empty_state.test.tsx.snap | 713 +++-- .../__tests__/empty_state.test.tsx | 6 +- .../functional/empty_state/empty_index.tsx | 88 +- .../functional/empty_state/empty_state.tsx | 18 +- .../empty_state/empty_state_error.tsx | 28 +- .../empty_state/empty_state_loading.tsx | 39 +- .../components/functional/error_list.tsx | 140 +- .../components/functional/filter_bar.tsx | 35 +- .../functional/format_sparkline_counts.ts | 15 +- .../components/functional/monitor_charts.tsx | 74 +- .../components/functional/monitor_list.tsx | 168 +- .../functional/monitor_page_title.tsx | 17 +- .../functional/monitor_sparkline.tsx | 54 + .../components/functional/ping_list.tsx | 135 +- .../public/components/functional/snapshot.tsx | 122 +- .../functional/snapshot_histogram.tsx | 25 +- .../functional/snapshot_loading.tsx | 90 +- .../public/components/higher_order/index.ts | 7 + .../higher_order/uptime_graphql_query.tsx | 61 + .../queries/empty_state/empty_state_query.tsx | 61 +- .../queries/error_list/error_list_query.tsx | 41 +- .../queries/error_list/get_error_list.ts | 1 + .../queries/filter_bar/filter_bar_query.tsx | 52 +- .../monitor_charts/get_monitor_charts.ts | 2 +- .../monitor_charts/monitor_charts_query.tsx | 90 +- .../monitor_list/monitor_list_query.tsx | 59 +- .../get_monitor_page_title.ts | 2 +- .../monitor_page_title_query.tsx | 46 +- .../monitor_status_bar_query.tsx | 87 +- .../queries/ping_list/ping_list_query.tsx | 101 +- .../queries/snapshot/snapshot_query.tsx | 82 +- .../framework/kibana_framework_adapter.ts | 4 +- .../format_error_string.test.ts.snap | 7 + .../__test__/format_error_string.test.ts | 41 + .../public/lib/helper/format_error_list.ts | 20 + .../plugins/uptime/public/pages/monitor.tsx | 99 +- .../plugins/uptime/public/pages/overview.tsx | 63 +- x-pack/plugins/uptime/public/uptime_app.tsx | 135 +- .../server/graphql/monitors/schema.gql.ts | 5 +- .../uptime/server/graphql/pings/schema.gql.ts | 2 +- .../elasticsearch_monitors_adapter.ts | 2 + .../elasticsearch_pings_adapter.test.ts.snap | 82 + .../elasticsearch_pings_adapter.test.ts | 301 +- .../pings/elasticsearch_pings_adapter.ts | 17 +- ...get_filtered_query_and_status.test.ts.snap | 37 + .../get_filtered_query_and_status.test.ts | 6 + .../server/lib/helper/get_filtered_query.ts | 12 +- .../helper/get_filtered_query_and_status.ts | 9 +- .../apis/uptime/get_all_pings.js | 4 +- .../apis/uptime/graphql/error_list.js | 2 +- .../uptime/graphql/fixtures/error_list.json | 12 +- .../fixtures/error_list_filtered_by_id.json | 3 +- .../fixtures/error_list_filtered_by_port.json | 3 +- .../error_list_filtered_by_port_and_type.json | 3 +- .../uptime/graphql/fixtures/ping_list.json | 124 +- .../graphql/fixtures/ping_list_count.json | 594 ++-- .../fixtures/ping_list_monitor_id.json | 158 +- .../fixtures/snapshot_filtered_by_up.json | 6 +- x-pack/test/functional/apps/uptime/monitor.ts | 3 +- .../test/functional/apps/uptime/overview.ts | 1 + .../functional/page_objects/uptime_page.ts | 6 +- 83 files changed, 4256 insertions(+), 3731 deletions(-) create mode 100644 x-pack/plugins/uptime/common/constants/query.ts create mode 100644 x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_sparkline.test.tsx.snap create mode 100644 x-pack/plugins/uptime/public/components/functional/__tests__/monitor_sparkline.test.tsx create mode 100644 x-pack/plugins/uptime/public/components/functional/monitor_sparkline.tsx create mode 100644 x-pack/plugins/uptime/public/components/higher_order/index.ts create mode 100644 x-pack/plugins/uptime/public/components/higher_order/uptime_graphql_query.tsx create mode 100644 x-pack/plugins/uptime/public/lib/helper/__test__/__snapshots__/format_error_string.test.ts.snap create mode 100644 x-pack/plugins/uptime/public/lib/helper/__test__/format_error_string.test.ts create mode 100644 x-pack/plugins/uptime/public/lib/helper/format_error_list.ts create mode 100644 x-pack/plugins/uptime/server/lib/adapters/pings/__tests__/__snapshots__/elasticsearch_pings_adapter.test.ts.snap diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 1c8103b49f848..e6bdf194019ca 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -7789,52 +7789,36 @@ "xpack.upgradeAssistant.tabs.incompleteCallout.calloutBody.breackingChangesDocButtonLabel": "弃用内容和重大更改", "xpack.upgradeAssistant.tabs.incompleteCallout.calloutBody.calloutDetail": "Elasticsearch {nextEsVersion} 中的 {breakingChangesDocButton} 完整列表将在最终的 {currentEsVersion} 次要版本中提供。完成列表后,此警告将消失。", "xpack.upgradeAssistant.tabs.incompleteCallout.calloutTitle": "问题列表可能不完整", - "xpack.uptime.appHeader.uptimeLogoAriaLabel": "前往运行时间主页", - "xpack.uptime.appHeader.uptimeLogoText": "运行时间", - "xpack.uptime.appHeader.uptimeLogoTitle": "运行时间", - "xpack.uptime.breadcrumbs.monitorBreadcrumbText": "监测", "xpack.uptime.breadcrumbs.overviewBreadcrumbText": "概览", "xpack.uptime.emptyState.configureHeartbeatLinkText": "配置 Heartbeat", "xpack.uptime.emptyState.configureHeartbeatToGetStartedMessage": "{configureHeartbeatLink} 以开始记录运行时间数据。", - "xpack.uptime.emptyState.errorMessage": "错误 {message}", "xpack.uptime.emptyState.loadingMessage": "正在加载……", "xpack.uptime.emptyState.noDataTitle": "没有运行时间数据", "xpack.uptime.errorList.CountColumnLabel": "计数", - "xpack.uptime.errorList.errorMessage": "错误 {message}", "xpack.uptime.errorList.errorTypeColumnLabel": "错误类型", - "xpack.uptime.errorList.latestErrorColumnLabel": "最新错误", "xpack.uptime.errorList.latestMessageColumnLabel": "最新消息", "xpack.uptime.errorList.monitorIdColumnLabel": "监测 ID", "xpack.uptime.errorList.statusCodeColumnLabel": "状态代码", "xpack.uptime.errorList.title": "错误列表", "xpack.uptime.featureCatalogueDescription": "执行终端节点运行状况检查和运行时间监测。", - "xpack.uptime.filterBar.errorMessage": "错误 {message}", "xpack.uptime.filterBar.filterDownLabel": "关闭", "xpack.uptime.filterBar.filterUpLabel": "运行", "xpack.uptime.filterBar.loadingMessage": "正在加载……", "xpack.uptime.filterBar.options.portLabel": "端口", - "xpack.uptime.header.helpLinkAriaLabel": "前往我们的讨论页", - "xpack.uptime.header.helpLinkText": "讨论", "xpack.uptime.monitorCharts.checkStatus.series.downCountLabel": "关闭计数", "xpack.uptime.monitorCharts.checkStatus.series.upCountLabel": "运行计数", "xpack.uptime.monitorCharts.checkStatus.title": "检查状态", - "xpack.uptime.monitorCharts.errorMessage": "错误 {message}", "xpack.uptime.monitorCharts.loadingMessage": "正在加载……", "xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel": "持续时间范围", "xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel": "平均持续时间", "xpack.uptime.monitorCharts.monitorDuration.titleLabel": "监测持续时间 (ms)", "xpack.uptime.monitorList.downLineSeries.downLabel": "关闭", - "xpack.uptime.monitorList.errorMessage": "错误 {message}", - "xpack.uptime.monitorList.ipColumnLabel": "IP", - "xpack.uptime.monitorList.lastUpdatedColumnLabel": "最后更新时间:1/23/2016", "xpack.uptime.monitorList.monitorHistoryColumnLabel": "监测历史记录", "xpack.uptime.monitorList.monitoringStatusTitle": "检测状态", "xpack.uptime.monitorList.statusColumn.downLabel": "关闭", "xpack.uptime.monitorList.statusColumn.upLabel": "运行", "xpack.uptime.monitorList.statusColumnLabel": "状态", - "xpack.uptime.monitorList.upLineSeries.upLabel": "运行", "xpack.uptime.monitorStatusBar.durationTextAriaLabel": "监测持续时间(毫秒)", - "xpack.uptime.monitorStatusBar.errorMessage": "错误 {message}", "xpack.uptime.monitorStatusBar.healthStatus.durationInMillisecondsMessage": "{duration}ms", "xpack.uptime.monitorStatusBar.healthStatusMessage.downLabel": "关闭", "xpack.uptime.monitorStatusBar.healthStatusMessage.upLabel": "运行", @@ -7843,10 +7827,8 @@ "xpack.uptime.pingList.checkHistoryTitle": "检查历史记录", "xpack.uptime.pingList.columns.errorMessageTooltipTitle": "错误消息", "xpack.uptime.pingList.durationMsColumnLabel": "持续时间 (ms)", - "xpack.uptime.pingList.errorMessage": "错误 {message}", "xpack.uptime.pingList.errorMessageColumnLabel": "错误消息", "xpack.uptime.pingList.errorTypeColumnLabel": "错误类型", - "xpack.uptime.pingList.idColumnLabel": "ID", "xpack.uptime.pingList.ipAddressColumnLabel": "IP", "xpack.uptime.pingList.responseCodeColumnLabel": "响应代码", "xpack.uptime.pingList.statusColumnHealthDownLabel": "关闭", @@ -7856,10 +7838,8 @@ "xpack.uptime.pingList.statusOptions.allStatusOptionLabel": "全部", "xpack.uptime.pingList.statusOptions.downStatusOptionLabel": "关闭", "xpack.uptime.pingList.statusOptions.upStatusOptionLabel": "运行", - "xpack.uptime.pingList.timestampColumnLabel": "时间戳", "xpack.uptime.pluginDescription": "运行时间监测", "xpack.uptime.snapshot.endpointStatusTitle": "终端节点状态", - "xpack.uptime.snapshot.errorMessage": "错误 {message}", "xpack.uptime.snapshot.noDataDescription": "抱歉,没有可用于该直方图的数据", "xpack.uptime.snapshot.noDataTitle": "没有可用的直方图数据", "xpack.uptime.snapshot.stats.downDescription": "关闭", diff --git a/x-pack/plugins/uptime/common/constants/index.ts b/x-pack/plugins/uptime/common/constants/index.ts index da3cf73059c17..5a421651eb7ac 100644 --- a/x-pack/plugins/uptime/common/constants/index.ts +++ b/x-pack/plugins/uptime/common/constants/index.ts @@ -6,3 +6,4 @@ export { INDEX_NAMES } from './index_names'; export { PLUGIN } from './plugin'; +export { QUERY } from './query'; diff --git a/x-pack/plugins/uptime/common/constants/query.ts b/x-pack/plugins/uptime/common/constants/query.ts new file mode 100644 index 0000000000000..8021d0cc0da60 --- /dev/null +++ b/x-pack/plugins/uptime/common/constants/query.ts @@ -0,0 +1,24 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +/** + * These are the fields that will be used when users enter simple_query_string + * searches into the FilterBar component. + */ +export const QUERY = { + SIMPLE_QUERY_STRING_FIELDS: [ + 'monitor.id', + 'monitor.url', + 'monitor.type', + 'monitor.status', + 'monitor.name', + 'url.full', + 'url.path', + 'url.scheme', + 'url.domain', + 'error.type', + ], +}; diff --git a/x-pack/plugins/uptime/common/graphql/introspection.json b/x-pack/plugins/uptime/common/graphql/introspection.json index 59428b55e6fbd..38f17e6343a78 100644 --- a/x-pack/plugins/uptime/common/graphql/introspection.json +++ b/x-pack/plugins/uptime/common/graphql/introspection.json @@ -425,7 +425,7 @@ "name": "millisFromNow", "description": "Milliseconds from the timestamp to the current time", "args": [], - "type": { "kind": "SCALAR", "name": "Int", "ofType": null }, + "type": { "kind": "SCALAR", "name": "UnsignedInteger", "ofType": null }, "isDeprecated": false, "deprecationReason": null }, @@ -1600,7 +1600,11 @@ "type": { "kind": "LIST", "name": null, - "ofType": { "kind": "OBJECT", "name": "MonitorSeriesPoint", "ofType": null } + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "MonitorSeriesPoint", "ofType": null } + } }, "isDeprecated": false, "deprecationReason": null @@ -1612,7 +1616,11 @@ "type": { "kind": "LIST", "name": null, - "ofType": { "kind": "OBJECT", "name": "MonitorSeriesPoint", "ofType": null } + "ofType": { + "kind": "NON_NULL", + "name": null, + "ofType": { "kind": "OBJECT", "name": "MonitorSeriesPoint", "ofType": null } + } }, "isDeprecated": false, "deprecationReason": null @@ -2160,6 +2168,14 @@ "type": { "kind": "SCALAR", "name": "String", "ofType": null }, "isDeprecated": false, "deprecationReason": null + }, + { + "name": "name", + "description": "", + "args": [], + "type": { "kind": "SCALAR", "name": "String", "ofType": null }, + "isDeprecated": false, + "deprecationReason": null } ], "inputFields": null, diff --git a/x-pack/plugins/uptime/common/graphql/types.ts b/x-pack/plugins/uptime/common/graphql/types.ts index 07b44eafb3d98..a4a531f2894b7 100644 --- a/x-pack/plugins/uptime/common/graphql/types.ts +++ b/x-pack/plugins/uptime/common/graphql/types.ts @@ -45,7 +45,7 @@ export interface Ping { /** The timestamp of the ping's creation */ timestamp: string; /** Milliseconds from the timestamp to the current time */ - millisFromNow?: number | null; + millisFromNow?: UnsignedInteger | null; /** The agent that recorded the ping */ beat?: Beat | null; @@ -314,9 +314,9 @@ export interface LatestMonitor { /** Information from the latest document. */ ping?: Ping | null; /** Buckets of recent up count status data. */ - upSeries?: (MonitorSeriesPoint | null)[] | null; + upSeries?: MonitorSeriesPoint[] | null; /** Buckets of recent down count status data. */ - downSeries?: (MonitorSeriesPoint | null)[] | null; + downSeries?: MonitorSeriesPoint[] | null; } export interface MonitorKey { @@ -417,6 +417,8 @@ export interface ErrorListItem { statusCode?: string | null; timestamp?: string | null; + + name?: string | null; } export interface MonitorPageTitle { diff --git a/x-pack/plugins/uptime/public/breadcrumbs.ts b/x-pack/plugins/uptime/public/breadcrumbs.ts index 9e7aba684c533..316163aec4e84 100644 --- a/x-pack/plugins/uptime/public/breadcrumbs.ts +++ b/x-pack/plugins/uptime/public/breadcrumbs.ts @@ -11,22 +11,16 @@ export interface UMBreadcrumb { href?: string; } -export const monitorBreadcrumb: UMBreadcrumb = { - text: i18n.translate('xpack.uptime.breadcrumbs.monitorBreadcrumbText', { - defaultMessage: 'Monitor', - }), -}; - export const overviewBreadcrumb: UMBreadcrumb = { text: i18n.translate('xpack.uptime.breadcrumbs.overviewBreadcrumbText', { - defaultMessage: 'Overview', + defaultMessage: 'Uptime', }), href: '#/', }; export const getOverviewPageBreadcrumbs = (): UMBreadcrumb[] => [overviewBreadcrumb]; -export const getMonitorPageBreadcrumb = (): UMBreadcrumb[] => [ +export const getMonitorPageBreadcrumb = (name: string): UMBreadcrumb[] => [ overviewBreadcrumb, - monitorBreadcrumb, + { text: name }, ]; diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/error_list.test.tsx.snap b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/error_list.test.tsx.snap index da36de70ea46b..8f35b1e358a21 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/error_list.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/error_list.test.tsx.snap @@ -1,109 +1,110 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`ErrorList component renders the error list without errors 1`] = ` - +
- - - -
+ } + responsive={true} + sorting={false} + /> + `; diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/filter_bar.test.tsx.snap b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/filter_bar.test.tsx.snap index 36ec82f063c28..59ae6d0494b2f 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/filter_bar.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/filter_bar.test.tsx.snap @@ -1,196 +1,196 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`FilterBar component renders the component without errors 1`] = ` - - - - - + `; diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap index 66b72b4029fdc..65f9473168d07 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_charts.test.tsx.snap @@ -2,43 +2,44 @@ exports[`MonitorCharts component renders the component without errors 1`] = ` - + - -

- -

-
+ +

+ +

+
@@ -175,41 +176,40 @@ exports[`MonitorCharts component renders the component without errors 1`] = `
- -

- -

-
+ +

+ +

+
+ - - + - -
+ } + responsive={true} + sorting={false} + /> + `; diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_sparkline.test.tsx.snap b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_sparkline.test.tsx.snap new file mode 100644 index 0000000000000..0134f2a523d8a --- /dev/null +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/monitor_sparkline.test.tsx.snap @@ -0,0 +1,43 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MonitorSparkline component renders a series when there are down items 1`] = ` + + + +`; diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/ping_list.test.tsx.snap b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/ping_list.test.tsx.snap index 307bff663781e..58183d76e124a 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/ping_list.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/ping_list.test.tsx.snap @@ -2,78 +2,96 @@ exports[`PingList component renders sorted list without errors 1`] = ` - - - -

- -

-
-
- - - 9231 - - -
- - - + + - + +

+ +

+
+
+ + + 9231 + + +
+ + + + - + > + + + + - -
- -
-
- - - - - - - + - - +
+ +
+ +
- - - + + + + + + + + + +
- -
- -
-
+ +
+ +
+
+
diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/snapshot_histogram.test.tsx.snap b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/snapshot_histogram.test.tsx.snap index fcb1b3f17264e..14498b5d4bd6e 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/snapshot_histogram.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/__snapshots__/snapshot_histogram.test.tsx.snap @@ -2,137 +2,137 @@ exports[`SnapshotHistogram component renders the component without errors 1`] = ` `; diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/error_list.test.tsx b/x-pack/plugins/uptime/public/components/functional/__tests__/error_list.test.tsx index b692c10dd4c12..086255165b35a 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/error_list.test.tsx +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/error_list.test.tsx @@ -22,6 +22,7 @@ describe('ErrorList component', () => { count: 843, statusCode: null, timestamp: '2019-01-28T18:43:15.077Z', + name: null, }, { latestMessage: 'dial tcp 127.0.0.1:9200: connect: connection refused', @@ -30,6 +31,7 @@ describe('ErrorList component', () => { count: 748, statusCode: null, timestamp: '2019-01-28T17:59:34.075Z', + name: null, }, { latestMessage: 'lookup www.reddit.com: no such host', @@ -38,6 +40,7 @@ describe('ErrorList component', () => { count: 1, statusCode: null, timestamp: '2019-01-28T18:03:10.077Z', + name: null, }, { latestMessage: 'received status code 301 expecting 200', @@ -46,6 +49,7 @@ describe('ErrorList component', () => { count: 645, statusCode: '301', timestamp: '2019-01-28T18:43:07.078Z', + name: null, }, ], }; diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/format_sparkline_counts.test.ts b/x-pack/plugins/uptime/public/components/functional/__tests__/format_sparkline_counts.test.ts index f66342f8b5168..2a35b97de8941 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/format_sparkline_counts.test.ts +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/format_sparkline_counts.test.ts @@ -4,10 +4,11 @@ * you may not use this file except in compliance with the Elastic License. */ -import { formatSparklineCounts, PingCount } from '../format_sparkline_counts'; +import { MonitorSeriesPoint } from '../../../../common/graphql/types'; +import { formatSparklineCounts } from '../format_sparkline_counts'; describe('formatSparklineCounts', () => { - let counts: PingCount[]; + let counts: MonitorSeriesPoint[]; beforeEach(() => { counts = [ diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx b/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx index f78fb6e6a3d29..40500d037470d 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_charts.test.tsx @@ -61,9 +61,10 @@ describe('MonitorCharts component', () => { checkDomainLimits={[0, 75]} danger="dangerColor" durationDomainLimits={[0, 75]} - monitorChartData={chartResponse.monitorChartsData} - primary="primaryColor" - secondary="secondaryColor" + monitorChartsData={chartResponse.monitorChartsData} + mean="mean" + range="range" + success="success" /> ); expect(component).toMatchSnapshot(); diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_list.test.tsx b/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_list.test.tsx index a0d5dc2e84f06..47b9c6a0f599e 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_list.test.tsx +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_list.test.tsx @@ -443,8 +443,8 @@ describe('MonitorList component', () => { const { monitors } = monitorResult; const component = shallowWithIntl( diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_sparkline.test.tsx b/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_sparkline.test.tsx new file mode 100644 index 0000000000000..b2092d53d6e93 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/monitor_sparkline.test.tsx @@ -0,0 +1,75 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * 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 { shallowWithIntl } from 'test_utils/enzyme_helpers'; +import { MonitorSparkline, MonitorSparklineProps } from '../monitor_sparkline'; + +describe('MonitorSparkline component', () => { + let props: MonitorSparklineProps; + beforeEach(() => { + props = { + dangerColor: 'A danger color', + monitor: { + id: { + key: 'test', + url: null, + }, + downSeries: [ + { + x: 123, + y: 1, + }, + { + x: 124, + y: 1, + }, + { + x: 125, + y: 1, + }, + ], + ping: null, + }, + }; + }); + + it('renders a series when there are down items', () => { + const component = shallowWithIntl(); + expect(component).toMatchSnapshot(); + }); + + it('renders null when there are no down items', () => { + props.monitor.downSeries = []; + const component = shallowWithIntl(); + expect(component).toEqual({}); + }); + + it('renders null when downSeries is null', () => { + props.monitor.downSeries = null; + const component = shallowWithIntl(); + expect(component).toEqual({}); + }); + + it('renders nothing if the down count has no counts', () => { + props.monitor.downSeries = [ + { + x: 123, + y: 0, + }, + { + x: 124, + y: null, + }, + { + x: 125, + y: 0, + }, + ]; + const component = shallowWithIntl(); + expect(component).toEqual({}); + }); +}); diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/ping_list.test.tsx b/x-pack/plugins/uptime/public/components/functional/__tests__/ping_list.test.tsx index 8512cbf39034a..45dd32b4f33e4 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/ping_list.test.tsx +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/ping_list.test.tsx @@ -190,9 +190,7 @@ describe('PingList component', () => { const component = shallowWithIntl( { it('renders without errors', () => { const wrapper = shallowWithIntl( - + ); expect(wrapper).toMatchSnapshot(); }); diff --git a/x-pack/plugins/uptime/public/components/functional/__tests__/snapshot_histogram.test.tsx b/x-pack/plugins/uptime/public/components/functional/__tests__/snapshot_histogram.test.tsx index db6d89874f659..cf6f80bd3ff3a 100644 --- a/x-pack/plugins/uptime/public/components/functional/__tests__/snapshot_histogram.test.tsx +++ b/x-pack/plugins/uptime/public/components/functional/__tests__/snapshot_histogram.test.tsx @@ -10,9 +10,8 @@ import { SnapshotHistogram, SnapshotHistogramProps } from '../snapshot_histogram describe('SnapshotHistogram component', () => { const props: SnapshotHistogramProps = { - primaryColor: '#FEFEFE', + successColor: '#FEFEFE', dangerColor: '#FF00FF', - windowWidth: 1200, histogram: [ { upCount: 7, downCount: 3, x: 1548697920000, x0: 1548697620000, y: 1 }, { upCount: 7, downCount: 3, x: 1548698220000, x0: 1548697920000, y: 1 }, diff --git a/x-pack/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap b/x-pack/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap index 512529d27691c..5e34e27990427 100644 --- a/x-pack/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap +++ b/x-pack/plugins/uptime/public/components/functional/empty_state/__tests__/__snapshots__/empty_state.test.tsx.snap @@ -106,51 +106,25 @@ exports[`EmptyState component doesn't render child components when count is fals } } > - + -

- - - , - } - } - /> -

+ + + +

+ Loading… +

+
} iconColor="subdued" - title={ - -

- -

-
- } >
- - -

- - No uptime data available - -

-
-
- -
- -

- - - , - } - } + +

+ + +
+ + +

- - - - Configure Heartbeat - - - - to start collecting uptime data. - -

+ Loading… +

+
- + `; @@ -267,10 +189,10 @@ exports[`EmptyState component renders child components when count is truthy 1`] `; -exports[`EmptyState component renders empty state with appropriate base path 1`] = ` +exports[`EmptyState component renders children while loading 1`] = ` - - -

- - - , - } - } - /> -

- - } - iconColor="subdued" - title={ - -

- -

-
- } - > -
- - - - -

- - No uptime data available - -

-
-
- -
- - -
-

- - - , - } - } - > - - - - Configure Heartbeat - - - - to start collecting uptime data. - -

-
-
- - -
- - +
+ Should appear even while loading... +
`; -exports[`EmptyState component renders message while loading 1`] = ` +exports[`EmptyState component renders empty state with appropriate base path 1`] = ` - - - - -

- Loading… -

-
-
- - - - - } + +
- - - - + + +
-
+

+ + + , + } + } + /> +

+ + } + iconColor="subdued" + iconType="uptimeApp" + title={ + +

+ +

+
+ } > - -
+ - -

- Loading… -

-
-
-
- -
+ + + + + +
+ + - -
- -
- -
- - - -
- - - + + +

+ + No uptime data available + +

+
+
+ +
+ + +
+

+ + + , + } + } + > + + + + Configure Heartbeat + + + + to start logging uptime data. + +

+
+
+ + +
+ +
+ +
+
- - + + `; + exports[`EmptyState component renders the message when an error occurs 1`] = ` - - An error occurred -

- } - iconColor="subdued" - title={ - -

- Error -

-
- } +
- - + + An error occurred +

+ } + iconColor="subdued" + title={ - -

- Error -

-
+

+ Error +

- -
- - +
+ -
-

- An error occurred -

-
- - -
+ + +

+ Error +

+
+
+ +
+ + +
+

+ An error occurred +

+
+
+ + +
+
- + `; diff --git a/x-pack/plugins/uptime/public/components/functional/empty_state/__tests__/empty_state.test.tsx b/x-pack/plugins/uptime/public/components/functional/empty_state/__tests__/empty_state.test.tsx index 6be918dd63549..aeecb5bff4331 100644 --- a/x-pack/plugins/uptime/public/components/functional/empty_state/__tests__/empty_state.test.tsx +++ b/x-pack/plugins/uptime/public/components/functional/empty_state/__tests__/empty_state.test.tsx @@ -21,7 +21,7 @@ describe('EmptyState component', () => { }); it(`doesn't render child components when count is falsey`, () => { const component = mountWithIntl( - +
Shouldn't be rendered
); @@ -35,10 +35,10 @@ describe('EmptyState component', () => { ); expect(component).toMatchSnapshot(); }); - it('renders message while loading', () => { + it('renders children while loading', () => { const component = mountWithIntl( -
Shouldn't appear...
+
Should appear even while loading...
); expect(component).toMatchSnapshot(); diff --git a/x-pack/plugins/uptime/public/components/functional/empty_state/empty_index.tsx b/x-pack/plugins/uptime/public/components/functional/empty_state/empty_index.tsx index 8377f880c7c1d..0141198ec15e0 100644 --- a/x-pack/plugins/uptime/public/components/functional/empty_state/empty_index.tsx +++ b/x-pack/plugins/uptime/public/components/functional/empty_state/empty_index.tsx @@ -4,7 +4,15 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiEmptyPrompt, EuiLink, EuiTitle } from '@elastic/eui'; +import { + EuiEmptyPrompt, + EuiFlexGroup, + EuiFlexItem, + EuiLink, + EuiPanel, + EuiSpacer, + EuiTitle, +} from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; import React, { Fragment } from 'react'; @@ -13,39 +21,47 @@ interface EmptyIndexProps { } export const EmptyIndex = ({ basePath }: EmptyIndexProps) => ( - -

- -

- - } - body={ - -

- - - - ), - }} - /> -

-
- } - /> + + + + + +

+ +

+ + } + body={ + +

+ + + + ), + }} + /> +

+
+ } + /> +
+
+
); diff --git a/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state.tsx b/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state.tsx index 6f9c97de03955..746405f3f75bd 100644 --- a/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state.tsx +++ b/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state.tsx @@ -12,7 +12,7 @@ import { EmptyStateLoading } from './empty_state_loading'; interface EmptyStateProps { basePath: string; children: JSX.Element[] | JSX.Element; - count: number | undefined; + count?: number; error?: string; loading?: boolean; } @@ -21,10 +21,18 @@ export const EmptyState = ({ basePath, children, count, error, loading }: EmptyS if (error) { return ; } - if (loading) { - return ; - } else if (!count) { + /** + * We choose to render the children any time the count > 0, even if + * the component is loading. If we render the loading state for this component, + * it will blow away the state of child components and trigger an ugly + * jittery UX any time the components refresh. This way we'll keep the stale + * state displayed during the fetching process. + */ + if (count) { + return {children}; + } + if (count === 0) { return ; } - return {children}; + return ; }; diff --git a/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state_error.tsx b/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state_error.tsx index b410fa844bb35..d4c62ee336f6f 100644 --- a/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state_error.tsx +++ b/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state_error.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiEmptyPrompt, EuiTitle } from '@elastic/eui'; +import { EuiEmptyPrompt, EuiPanel, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; @@ -13,16 +13,18 @@ interface EmptyStateErrorProps { } export const EmptyStateError = ({ errorMessage }: EmptyStateErrorProps) => ( - -

- {i18n.translate('xpack.uptime.emptyStateError.title', { - defaultMessage: 'Error', - })} -

- - } - body={

{errorMessage ? errorMessage : ''}

} - /> + + +

+ {i18n.translate('xpack.uptime.emptyStateError.title', { + defaultMessage: 'Error', + })} +

+ + } + body={

{errorMessage ? errorMessage : ''}

} + /> +
); diff --git a/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state_loading.tsx b/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state_loading.tsx index 4c502ab469fea..3d6516d659429 100644 --- a/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state_loading.tsx +++ b/x-pack/plugins/uptime/public/components/functional/empty_state/empty_state_loading.tsx @@ -4,33 +4,24 @@ * you may not use this file except in compliance with the Elastic License. */ -import { - EuiEmptyPrompt, - EuiFlexGroup, - EuiFlexItem, - EuiLoadingSpinner, - EuiTitle, -} from '@elastic/eui'; +import { EuiEmptyPrompt, EuiLoadingSpinner, EuiSpacer, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import React from 'react'; +import React, { Fragment } from 'react'; -export const EmptyStateLoading = (props: any) => ( +export const EmptyStateLoading = () => ( - - -

- {i18n.translate('xpack.uptime.emptyState.loadingMessage', { - defaultMessage: 'Loading…', - })} -

-
-
- - - - + body={ + + + + +

+ {i18n.translate('xpack.uptime.emptyState.loadingMessage', { + defaultMessage: 'Loading…', + })} +

+
+
} /> ); diff --git a/x-pack/plugins/uptime/public/components/functional/error_list.tsx b/x-pack/plugins/uptime/public/components/functional/error_list.tsx index 361515245f391..de549fe9fa137 100644 --- a/x-pack/plugins/uptime/public/components/functional/error_list.tsx +++ b/x-pack/plugins/uptime/public/components/functional/error_list.tsx @@ -4,75 +4,101 @@ * you may not use this file except in compliance with the Elastic License. */ -// @ts-ignore missing typings -import { EuiInMemoryTable, EuiPanel, EuiTitle } from '@elastic/eui'; +import { + EuiBadge, + EuiCodeBlock, + EuiInMemoryTable, + EuiLink, + EuiPanel, + EuiText, + EuiTextColor, + EuiTitle, +} from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import moment from 'moment'; -import React, { Fragment } from 'react'; +import React from 'react'; import { Link } from 'react-router-dom'; -import { ErrorListItem } from '../../../common/graphql/types'; +import { ErrorListItem, Ping } from '../../../common/graphql/types'; interface ErrorListProps { loading: boolean; - errorList: ErrorListItem[]; + errorList?: ErrorListItem[]; } export const ErrorList = ({ loading, errorList }: ErrorListProps) => ( - +
- +
- - {id}, - width: '25%', - }, - { - field: 'count', - name: i18n.translate('xpack.uptime.errorList.CountColumnLabel', { - defaultMessage: 'Count', - }), - }, - { - field: 'timestamp', - name: i18n.translate('xpack.uptime.errorList.latestErrorColumnLabel', { - defaultMessage: 'Latest error', - }), - render: (timestamp: string) => moment(timestamp).fromNow(), - }, - { - field: 'statusCode', - name: i18n.translate('xpack.uptime.errorList.statusCodeColumnLabel', { - defaultMessage: 'Status code', - }), - }, - { - field: 'latestMessage', - name: i18n.translate('xpack.uptime.errorList.latestMessageColumnLabel', { - defaultMessage: 'Latest message', - }), - width: '40%', - }, - ]} - pagination={{ initialPageSize: 10, pageSizeOptions: [5, 10, 20, 50] }} - /> - -
+ ( +
+ + {count} errors + + + Latest was {moment(item.timestamp).fromNow()} + +
+ ), + }, + { + field: 'type', + name: i18n.translate('xpack.uptime.errorList.errorTypeColumnLabel', { + defaultMessage: 'Error type', + }), + }, + { + field: 'monitorId', + name: i18n.translate('xpack.uptime.errorList.monitorIdColumnLabel', { + defaultMessage: 'Monitor ID', + }), + render: (id: string, { name }: ErrorListItem) => ( + + {name || id} + + ), + width: '25%', + }, + { + field: 'statusCode', + name: i18n.translate('xpack.uptime.errorList.statusCodeColumnLabel', { + defaultMessage: 'Status code', + }), + render: (statusCode: string) => (statusCode ? {statusCode} : null), + }, + { + field: 'latestMessage', + name: i18n.translate('xpack.uptime.errorList.latestMessageColumnLabel', { + defaultMessage: 'Latest message', + }), + width: '40%', + render: (message: string) => ( +
+ { + // TODO: remove this ignore when prop is defined on type + // @ts-ignore size is not currently defined on the type for EuiCodeBlock + + {message} + + } +
+ ), + }, + ]} + pagination={{ initialPageSize: 10, pageSizeOptions: [5, 10, 20, 50] }} + /> + ); diff --git a/x-pack/plugins/uptime/public/components/functional/filter_bar.tsx b/x-pack/plugins/uptime/public/components/functional/filter_bar.tsx index b87437dd1301d..400992f7d3746 100644 --- a/x-pack/plugins/uptime/public/components/functional/filter_bar.tsx +++ b/x-pack/plugins/uptime/public/components/functional/filter_bar.tsx @@ -5,20 +5,23 @@ */ // @ts-ignore No typings for EuiSearchBar -import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSearchBar, EuiToolTip } from '@elastic/eui'; +import { EuiIcon, EuiSearchBar, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { FilterBar as FilterBarType, MonitorKey } from '../../../common/graphql/types'; +import { UptimeSearchBarQueryChangeHandler } from '../../pages/overview'; import { filterBarSearchSchema } from './search_schema'; interface FilterBarProps { + currentQuery?: object; filterBar: FilterBarType; - updateQuery: (query: object | undefined) => void; + updateQuery: UptimeSearchBarQueryChangeHandler; } const SEARCH_THRESHOLD = 2; export const FilterBar = ({ + currentQuery, filterBar: { names, ports, ids, schemes }, updateQuery, }: FilterBarProps) => { @@ -112,25 +115,13 @@ export const FilterBar = ({ }, ]; return ( - - - { - try { - let esQuery; - if (query && query.text) { - esQuery = EuiSearchBar.Query.toESQuery(query); - } - updateQuery(esQuery); - } catch (e) { - updateQuery(undefined); - } - }} - filters={filters} - schema={filterBarSearchSchema} - /> - - + ); }; diff --git a/x-pack/plugins/uptime/public/components/functional/format_sparkline_counts.ts b/x-pack/plugins/uptime/public/components/functional/format_sparkline_counts.ts index 9f64150d6e6a7..2f1079afdac7b 100644 --- a/x-pack/plugins/uptime/public/components/functional/format_sparkline_counts.ts +++ b/x-pack/plugins/uptime/public/components/functional/format_sparkline_counts.ts @@ -4,23 +4,20 @@ * you may not use this file except in compliance with the Elastic License. */ -export interface PingCount { - x: number; - y: number; -} +import { MonitorSeriesPoint } from '../../../common/graphql/types'; -export const formatSparklineCounts = (counts: PingCount[]) => { +export const formatSparklineCounts = (seriesPoints: MonitorSeriesPoint[]) => { let defaultSize = 0; - const { length } = counts; + const { length } = seriesPoints; // assume points are uniform, use this // for the last element's span if (length > 1) { - defaultSize = Math.max(counts[1].x - counts[0].x, 0); + defaultSize = Math.max(seriesPoints[1].x - seriesPoints[0].x, 0); } else if (length === 1) { // wait for another point return []; } - return counts.map(({ x: x0, y }, index, array) => { + return seriesPoints.map(({ x: x0, y: yVal }, index, array) => { let x; const nextIndex = index + 1; if (nextIndex === array.length) { @@ -29,6 +26,6 @@ export const formatSparklineCounts = (counts: PingCount[]) => { const { x: nextX } = array[nextIndex]; x = nextX; } - return { x, x0, y }; + return { x, x0, y: yVal || 0 }; }); }; diff --git a/x-pack/plugins/uptime/public/components/functional/monitor_charts.tsx b/x-pack/plugins/uptime/public/components/functional/monitor_charts.tsx index a60d1034f474c..ad96917c70ba3 100644 --- a/x-pack/plugins/uptime/public/components/functional/monitor_charts.tsx +++ b/x-pack/plugins/uptime/public/components/functional/monitor_charts.tsx @@ -31,42 +31,44 @@ interface MonitorChartsProps { checkDomainLimits: number[]; danger: string; durationDomainLimits: number[]; - monitorChartData: MonitorChart; - primary: string; - secondary: string; + monitorChartsData: MonitorChart; + mean: string; + range: string; + success: string; } export const MonitorCharts = ({ checkDomainLimits, danger, durationDomainLimits, - monitorChartData: { durationArea, durationLine, status }, - primary, - secondary, + monitorChartsData: { durationArea, durationLine, status }, + mean, + range, + success, }: MonitorChartsProps) => ( - + - -

- -

-
- + + +

+ +

+
- -

- -

-
- + + +

+ +

+
({ x, y: up }))} - curve="curveBasis" - color={primary} + data={status.map(({ x, up }) => ({ x, y: up || 0 }))} + color={success} /> ({ x, y: down }))} + data={status.map(({ x, down }) => ({ x, y: down || 0 }))} color={danger} /> diff --git a/x-pack/plugins/uptime/public/components/functional/monitor_list.tsx b/x-pack/plugins/uptime/public/components/functional/monitor_list.tsx index c3238019b6ec9..0c1bd0a45886f 100644 --- a/x-pack/plugins/uptime/public/components/functional/monitor_list.tsx +++ b/x-pack/plugins/uptime/public/components/functional/monitor_list.tsx @@ -8,6 +8,7 @@ import { EuiHealth, // @ts-ignore missing type definition EuiHistogramSeries, + EuiIcon, // @ts-ignore missing type definition EuiInMemoryTable, EuiLink, @@ -16,18 +17,21 @@ import { EuiSeriesChart, // @ts-ignore missing type definition EuiSeriesChartUtils, + EuiSpacer, + EuiText, EuiTitle, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; +import { get } from 'lodash'; import moment from 'moment'; -import React, { Fragment } from 'react'; +import React from 'react'; import { Link } from 'react-router-dom'; -import { LatestMonitor } from '../../../common/graphql/types'; -import { formatSparklineCounts } from './format_sparkline_counts'; +import { LatestMonitor, MonitorSeriesPoint } from '../../../common/graphql/types'; +import { MonitorSparkline } from './monitor_sparkline'; interface MonitorListProps { - primaryColor: string; + successColor: string; dangerColor: string; loading: boolean; monitors: LatestMonitor[]; @@ -40,8 +44,8 @@ const monitorListPagination = { pageSizeOptions: [5, 10, 20, 50], }; -export const MonitorList = ({ dangerColor, loading, monitors, primaryColor }: MonitorListProps) => ( - +export const MonitorList = ({ dangerColor, loading, monitors }: MonitorListProps) => ( +
- - ( - + + ( +
+ {status === 'up' ? i18n.translate('xpack.uptime.monitorList.statusColumn.upLabel', { defaultMessage: 'Up', @@ -68,87 +77,60 @@ export const MonitorList = ({ dangerColor, loading, monitors, primaryColor }: Mo defaultMessage: 'Down', })} - ), - }, - { - field: 'ping.timestamp', - name: i18n.translate('xpack.uptime.monitorList.lastUpdatedColumnLabel', { - defaultMessage: 'Last updated', - }), - render: (timestamp: string) => moment(timestamp).fromNow(), - }, - { - field: 'ping.monitor.id', - name: i18n.translate('xpack.uptime.monitorList.idColumnLabel', { - defaultMessage: 'ID', - }), - render: (id: string, monitor: LatestMonitor) => ( + + {moment(get(monitor, 'ping.monitor.timestamp', undefined)).fromNow()} + +
+ ), + }, + { + field: 'ping.monitor.id', + name: i18n.translate('xpack.uptime.monitorList.idColumnLabel', { + defaultMessage: 'ID', + }), + render: (id: string, monitor: LatestMonitor) => ( + {monitor.ping && monitor.ping.monitor && monitor.ping.monitor.name ? monitor.ping.monitor.name : id} - ), - }, - { - field: 'ping.url.full', - name: i18n.translate('xpack.uptime.monitorList.urlColumnLabel', { - defaultMessage: 'URL', - }), - render: (url: string) => ( - - {url} + + ), + }, + { + field: 'ping.url.full', + name: i18n.translate('xpack.uptime.monitorList.urlColumnLabel', { + defaultMessage: 'URL', + }), + render: (url: string, monitor: LatestMonitor) => ( +
+ + {url} - ), - }, - { - field: 'ping.monitor.ip', - name: i18n.translate('xpack.uptime.monitorList.ipColumnLabel', { - defaultMessage: 'IP', - }), - }, - { - field: 'upSeries', - name: i18n.translate('xpack.uptime.monitorList.monitorHistoryColumnLabel', { - defaultMessage: 'Monitor History', - }), - // @ts-ignore TODO fix typing - render: (upSeries, monitor) => { - const { downSeries } = monitor; - return ( - - - - - ); - }, - }, - ]} - loading={loading} - items={monitors} - pagination={monitorListPagination} - /> - - + {monitor.ping && monitor.ping.monitor && monitor.ping.monitor.ip ? ( + + {monitor.ping.monitor.ip} + + ) : null} +
+ ), + }, + { + field: 'upSeries', + width: '180px', + align: 'right', + name: i18n.translate('xpack.uptime.monitorList.monitorHistoryColumnLabel', { + defaultMessage: 'Downtime history', + }), + render: (downSeries: MonitorSeriesPoint, monitor: LatestMonitor) => ( + + ), + }, + ]} + loading={loading} + items={monitors} + pagination={monitorListPagination} + /> +
); diff --git a/x-pack/plugins/uptime/public/components/functional/monitor_page_title.tsx b/x-pack/plugins/uptime/public/components/functional/monitor_page_title.tsx index 4b6b876b61b8d..170aa584696e4 100644 --- a/x-pack/plugins/uptime/public/components/functional/monitor_page_title.tsx +++ b/x-pack/plugins/uptime/public/components/functional/monitor_page_title.tsx @@ -4,7 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiFlexGroup, EuiFlexItem, EuiTitle } from '@elastic/eui'; +import { EuiTextColor, EuiTitle } from '@elastic/eui'; import React from 'react'; import { MonitorPageTitle as TitleType } from '../../../common/graphql/types'; @@ -13,14 +13,9 @@ interface MonitorPageTitleProps { } export const MonitorPageTitle = ({ pageTitle: { name, url, id } }: MonitorPageTitleProps) => ( - - - -

{name ? name : url}

-
-
- -

{id}

-
-
+ + +

{id}

+
+
); diff --git a/x-pack/plugins/uptime/public/components/functional/monitor_sparkline.tsx b/x-pack/plugins/uptime/public/components/functional/monitor_sparkline.tsx new file mode 100644 index 0000000000000..90b10a5e44a89 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/functional/monitor_sparkline.tsx @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +// @ts-ignore missing type definition +import { EuiHistogramSeries, EuiSeriesChart, EuiSeriesChartUtils } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import React from 'react'; +import { LatestMonitor, MonitorSeriesPoint } from '../../../common/graphql/types'; +import { formatSparklineCounts } from './format_sparkline_counts'; + +export interface MonitorSparklineProps { + dangerColor: string; + monitor: LatestMonitor; +} + +const seriesHasCounts = (series: MonitorSeriesPoint[]) => { + return series.some(point => !!point.y); +}; + +/** + * There is a specific focus on the monitor's down count, the up series is not shown, + * so we will only render the series component if there are down counts for the selected monitor. + * @param props - the values for the monitor this sparkline reflects + */ +export const MonitorSparkline = ({ + dangerColor, + monitor: { downSeries }, +}: MonitorSparklineProps) => { + return downSeries && seriesHasCounts(downSeries) ? ( + + + + ) : null; +}; diff --git a/x-pack/plugins/uptime/public/components/functional/ping_list.tsx b/x-pack/plugins/uptime/public/components/functional/ping_list.tsx index a79ab46603557..be5109db0eeee 100644 --- a/x-pack/plugins/uptime/public/components/functional/ping_list.tsx +++ b/x-pack/plugins/uptime/public/components/functional/ping_list.tsx @@ -9,11 +9,12 @@ import { EuiComboBoxOptionProps, EuiFlexGroup, EuiFlexItem, - EuiFormRow, EuiHealth, // @ts-ignore EuiInMemoryTable, EuiPanel, + EuiSpacer, + EuiText, EuiTitle, EuiToolTip, } from '@elastic/eui'; @@ -27,9 +28,7 @@ import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../lib/h interface PingListProps { loading: boolean; - maxSearchSize: number; - pingResults: PingResults; - searchSizeOnBlur: (e: React.FocusEvent) => void; + pingResults?: PingResults; selectedOption: EuiComboBoxOptionProps; selectedOptionChanged: (selectedOptions: EuiComboBoxOptionProps[]) => void; statusOptions: EuiComboBoxOptionProps[]; @@ -37,9 +36,7 @@ interface PingListProps { export const PingList = ({ loading, - maxSearchSize, pingResults, - searchSizeOnBlur, selectedOption, selectedOptionChanged, statusOptions, @@ -50,44 +47,39 @@ export const PingList = ({ name: i18n.translate('xpack.uptime.pingList.statusColumnLabel', { defaultMessage: 'Status', }), - render: (pingStatus: string) => ( - - {pingStatus === 'up' - ? i18n.translate('xpack.uptime.pingList.statusColumnHealthUpLabel', { - defaultMessage: 'Up', - }) - : i18n.translate('xpack.uptime.pingList.statusColumnHealthDownLabel', { - defaultMessage: 'Down', - })} - + render: (pingStatus: string, item: Ping) => ( +
+ + {pingStatus === 'up' + ? i18n.translate('xpack.uptime.pingList.statusColumnHealthUpLabel', { + defaultMessage: 'Up', + }) + : i18n.translate('xpack.uptime.pingList.statusColumnHealthDownLabel', { + defaultMessage: 'Down', + })} + + + {i18n.translate('xpack.uptime.pingList.recencyMessage', { + values: { fromNow: moment(item.timestamp).fromNow() }, + defaultMessage: 'Checked {fromNow}', + description: + 'A string used to inform our users how long ago Heartbeat pinged the selected host.', + })} + +
), }, - { - field: 'timestamp', - name: i18n.translate('xpack.uptime.pingList.timestampColumnLabel', { - defaultMessage: 'Timestamp', - }), - render: (timestamp: string) => moment(timestamp).fromNow(), - }, { field: 'monitor.ip', + dataType: 'number', name: i18n.translate('xpack.uptime.pingList.ipAddressColumnLabel', { defaultMessage: 'IP', }), }, - { - field: 'monitor.id', - name: i18n.translate('xpack.uptime.pingList.idColumnLabel', { - defaultMessage: 'Id', - }), - dataType: 'string', - width: '20%', - }, { field: 'monitor.duration.us', name: i18n.translate('xpack.uptime.pingList.durationMsColumnLabel', { - defaultMessage: 'Duration ms', - description: 'The "ms" in the default message is an abbreviation for milliseconds', + defaultMessage: 'Duration', }), render: (duration: number) => microsToMillis(duration), }, @@ -111,10 +103,12 @@ export const PingList = ({ })} content={

{message}

} > -
{message.slice(0, 24)}…
+ {message.slice(0, 24)}… ) : ( - message + + {message} + ), }, ]; @@ -131,55 +125,62 @@ export const PingList = ({ if (hasStatus) { columns.push({ field: 'http.response.status_code', + // @ts-ignore "align" property missing on type definition for column type + align: 'right', name: i18n.translate('xpack.uptime.pingList.responseCodeColumnLabel', { defaultMessage: 'Response code', }), + render: (statusCode: string) => {statusCode}, }); } } return ( - - - -

- -

-
-
- {!!total && ( + + - {total} + + + +

+ +

+
+
+ {!!total && ( + + {total} + + )} +
- )} -
- - - - - - + + + + + + +
diff --git a/x-pack/plugins/uptime/public/components/functional/snapshot.tsx b/x-pack/plugins/uptime/public/components/functional/snapshot.tsx index 773588fb02fec..c5d683e9b4994 100644 --- a/x-pack/plugins/uptime/public/components/functional/snapshot.tsx +++ b/x-pack/plugins/uptime/public/components/functional/snapshot.tsx @@ -18,6 +18,7 @@ import { EuiStat, EuiTitle, } from '@elastic/eui'; +import { EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; @@ -26,86 +27,83 @@ import { SnapshotHistogram } from './snapshot_histogram'; interface SnapshotProps { dangerColor: string; - primaryColor: string; + successColor: string; snapshot: SnapshotType; - windowWidth: number; } export const Snapshot = ({ dangerColor, - primaryColor, + successColor, snapshot: { up, down, total, histogram }, - windowWidth, }: SnapshotProps) => ( - + - -
- -
-
- - - - {/* TODO: this is a UI hack that needs to be replaced */} - - - - - - - - + + + + +
+ +
+
+
- - - + + + + + + + + + + +
- - -
- -
-
- {/* TODO: this is a UI hack that should be replaced */} - + + + +
+ +
+
+ {histogram && ( )} {!histogram && ( diff --git a/x-pack/plugins/uptime/public/components/functional/snapshot_histogram.tsx b/x-pack/plugins/uptime/public/components/functional/snapshot_histogram.tsx index 317db3575932b..55b744fe6ed70 100644 --- a/x-pack/plugins/uptime/public/components/functional/snapshot_histogram.tsx +++ b/x-pack/plugins/uptime/public/components/functional/snapshot_histogram.tsx @@ -11,8 +11,7 @@ import React from 'react'; import { HistogramDataPoint } from '../../../common/graphql/types'; export interface SnapshotHistogramProps { - windowWidth: number; - primaryColor: string; + successColor: string; dangerColor: string; histogram: HistogramDataPoint[]; } @@ -22,34 +21,32 @@ export interface SnapshotHistogramProps { * working with our app, so temporarily we will use this ratio to auto-resize * the histogram. When we upgrade the charts we will delete this. */ -const windowRatio = 0.545238095238095; export const SnapshotHistogram = ({ dangerColor, histogram, - primaryColor, - windowWidth, + successColor, }: SnapshotHistogramProps) => ( ({ x, x0, y: upCount }))} - name={i18n.translate('xpack.uptime.snapshotHistogram.series.upLabel', { - defaultMessage: 'Up', - })} - color={primaryColor} - /> - ({ x, x0, y: downCount }))} + data={histogram.map(({ x, x0, downCount }) => ({ x, x0, y: downCount || 0 }))} name={i18n.translate('xpack.uptime.snapshotHistogram.series.downLabel', { defaultMessage: 'Down', })} color={dangerColor} /> + ({ x, x0, y: upCount || 0 }))} + name={i18n.translate('xpack.uptime.snapshotHistogram.series.upLabel', { + defaultMessage: 'Up', + })} + color={successColor} + /> ); diff --git a/x-pack/plugins/uptime/public/components/functional/snapshot_loading.tsx b/x-pack/plugins/uptime/public/components/functional/snapshot_loading.tsx index 6833cb5815965..24c11b9a27dbf 100644 --- a/x-pack/plugins/uptime/public/components/functional/snapshot_loading.tsx +++ b/x-pack/plugins/uptime/public/components/functional/snapshot_loading.tsx @@ -11,53 +11,53 @@ import { FormattedMessage } from '@kbn/i18n/react'; import React from 'react'; export const SnapshotLoading = () => ( - - - -
- -
-
- - - - - - - - - - - + + + + + + +
+ +
+
- - - + + + + + + + + + + +
diff --git a/x-pack/plugins/uptime/public/components/higher_order/index.ts b/x-pack/plugins/uptime/public/components/higher_order/index.ts new file mode 100644 index 0000000000000..c5b712e0ae674 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/higher_order/index.ts @@ -0,0 +1,7 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +export { UptimeGraphQLQueryProps, withUptimeGraphQL } from './uptime_graphql_query'; diff --git a/x-pack/plugins/uptime/public/components/higher_order/uptime_graphql_query.tsx b/x-pack/plugins/uptime/public/components/higher_order/uptime_graphql_query.tsx new file mode 100644 index 0000000000000..1976585fec6c4 --- /dev/null +++ b/x-pack/plugins/uptime/public/components/higher_order/uptime_graphql_query.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 { OperationVariables } from 'apollo-client'; +import { GraphQLError } from 'graphql'; +import React, { Fragment, useEffect, useState } from 'react'; +import { withApollo, WithApolloClient } from 'react-apollo'; +import { formatUptimeGraphQLErrorList } from '../../lib/helper/format_error_list'; + +export interface UptimeGraphQLQueryProps { + loading: boolean; + data?: T; + errors?: GraphQLError[]; +} + +interface UptimeGraphQLProps { + implementsCustomErrorState?: boolean; + lastRefresh?: number; + variables: OperationVariables; +} + +/** + * This HOC abstracts the task of querying our GraphQL endpoint, + * which eliminates the need for a lot of boilerplate code in the other components. + * + * @type T - the expected result's type + * @type P - any props the wrapped component will require + * @param WrappedComponent - the consuming component + * @param query - the graphQL query + */ +export function withUptimeGraphQL(WrappedComponent: any, query: any) { + type Props = UptimeGraphQLProps & WithApolloClient & P; + + return withApollo((props: Props) => { + const [loading, setLoading] = useState(true); + const [data, setData] = useState(undefined); + const [errors, setErrors] = useState(undefined); + const { client, implementsCustomErrorState, variables, lastRefresh } = props; + const fetch = () => { + setLoading(true); + client.query({ fetchPolicy: 'network-only', query, variables }).then((result: any) => { + setData(result.data); + setLoading(result.loading); + setErrors(result.errors); + }); + }; + useEffect( + () => { + fetch(); + }, + [variables, lastRefresh] + ); + if (!implementsCustomErrorState && errors && errors.length > 0) { + return {formatUptimeGraphQLErrorList(errors)}; + } + return ; + }); +} diff --git a/x-pack/plugins/uptime/public/components/queries/empty_state/empty_state_query.tsx b/x-pack/plugins/uptime/public/components/queries/empty_state/empty_state_query.tsx index 29070d1a6d92f..d9a446230c4e2 100644 --- a/x-pack/plugins/uptime/public/components/queries/empty_state/empty_state_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/empty_state/empty_state_query.tsx @@ -4,49 +4,44 @@ * you may not use this file except in compliance with the Elastic License. */ -import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; import React from 'react'; -import { Query } from 'react-apollo'; +import { formatUptimeGraphQLErrorList } from '../../../lib/helper/format_error_list'; import { UptimeCommonProps } from '../../../uptime_app'; import { EmptyState } from '../../functional/empty_state'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; import { getDocCountQuery } from './get_doc_count'; +interface EmptyStateQueryResult { + data?: { + getDocCount: { + count: number; + }; + }; +} + interface EmptyStateProps { basePath: string; children: JSX.Element[]; } -type Props = EmptyStateProps & UptimeCommonProps; +type Props = EmptyStateProps & UptimeCommonProps & UptimeGraphQLQueryProps; + +export const makeEmptyStateQuery = ({ basePath, children, data, errors, loading }: Props) => { + const count = get(data, 'getDocCount.count', 0); + return ( + + {children} + + ); +}; -export const EmptyStateQuery = ({ - autorefreshInterval, - autorefreshIsPaused, - basePath, - children, -}: Props) => ( - - {({ loading, error, data }) => { - const count = get(data, 'getDocCount.count', 0); - return ( - - ); - }} - +export const EmptyStateQuery = withUptimeGraphQL( + makeEmptyStateQuery, + getDocCountQuery ); diff --git a/x-pack/plugins/uptime/public/components/queries/error_list/error_list_query.tsx b/x-pack/plugins/uptime/public/components/queries/error_list/error_list_query.tsx index 3a2b454f4759e..dd7fe829af0c3 100644 --- a/x-pack/plugins/uptime/public/components/queries/error_list/error_list_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/error_list/error_list_query.tsx @@ -4,40 +4,25 @@ * you may not use this file except in compliance with the Elastic License. */ -import { i18n } from '@kbn/i18n'; import React from 'react'; -import { Query } from 'react-apollo'; +import { ErrorListItem } from '../../../../common/graphql/types'; import { UptimeCommonProps } from '../../../uptime_app'; import { ErrorList } from '../../functional'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; import { getErrorListQuery } from './get_error_list'; -interface ErrorListProps { - filters?: string; +interface ErrorListQueryResult { + errorList?: ErrorListItem[]; } -type Props = ErrorListProps & UptimeCommonProps; +type Props = UptimeCommonProps & UptimeGraphQLQueryProps; -export const ErrorListQuery = ({ - autorefreshInterval, - autorefreshIsPaused, - dateRangeStart, - dateRangeEnd, - filters, -}: Props) => ( - - {({ loading, error, data }) => { - if (error) { - return i18n.translate('xpack.uptime.errorList.errorMessage', { - values: { message: error.message }, - defaultMessage: 'Error {message}', - }); - } - const { errorList } = data; - return ; - }} - +export const makeErrorListQuery = ({ data, loading }: Props) => { + const errorList: ErrorListItem[] | undefined = data ? data.errorList : undefined; + return ; +}; + +export const ErrorListQuery = withUptimeGraphQL( + makeErrorListQuery, + getErrorListQuery ); diff --git a/x-pack/plugins/uptime/public/components/queries/error_list/get_error_list.ts b/x-pack/plugins/uptime/public/components/queries/error_list/get_error_list.ts index 57773200eafb5..328efe010b2ff 100644 --- a/x-pack/plugins/uptime/public/components/queries/error_list/get_error_list.ts +++ b/x-pack/plugins/uptime/public/components/queries/error_list/get_error_list.ts @@ -19,6 +19,7 @@ query ErrorList($dateRangeStart: String!, $dateRangeEnd: String!, $filters: Stri count statusCode timestamp + name } } `; diff --git a/x-pack/plugins/uptime/public/components/queries/filter_bar/filter_bar_query.tsx b/x-pack/plugins/uptime/public/components/queries/filter_bar/filter_bar_query.tsx index 5b1265ae57403..8242bf63ff90f 100644 --- a/x-pack/plugins/uptime/public/components/queries/filter_bar/filter_bar_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/filter_bar/filter_bar_query.tsx @@ -4,43 +4,35 @@ * you may not use this file except in compliance with the Elastic License. */ -import { i18n } from '@kbn/i18n'; import React from 'react'; -import { Query } from 'react-apollo'; +import { FilterBar as FilterBarType } from '../../../../common/graphql/types'; +import { UptimeSearchBarQueryChangeHandler } from '../../../pages/overview'; import { UptimeCommonProps } from '../../../uptime_app'; import { FilterBar, FilterBarLoading } from '../../functional'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; import { getFilterBarQuery } from './get_filter_bar'; +interface FilterBarQueryResult { + filterBar?: FilterBarType; +} + interface FilterBarProps { - updateQuery: (query: object | undefined) => void; + currentQuery?: object; + updateQuery: UptimeSearchBarQueryChangeHandler; } -type Props = FilterBarProps & UptimeCommonProps; +type Props = FilterBarProps & UptimeCommonProps & UptimeGraphQLQueryProps; + +export const makeFilterBarQuery = ({ currentQuery, data, updateQuery }: Props) => { + if (data && data.filterBar) { + return ( + + ); + } + return ; +}; -export const FilterBarQuery = ({ - autorefreshInterval, - autorefreshIsPaused, - dateRangeStart, - dateRangeEnd, - updateQuery, -}: Props) => ( - - {({ loading, error, data }) => { - if (loading) { - return ; - } - if (error) { - return i18n.translate('xpack.uptime.filterBar.errorMessage', { - values: { message: error.message }, - defaultMessage: 'Error {message}', - }); - } - const { filterBar } = data; - return ; - }} - +export const FilterBarQuery = withUptimeGraphQL( + makeFilterBarQuery, + getFilterBarQuery ); diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts.ts b/x-pack/plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts.ts index 7fffec4440703..03d7800ca9aff 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts.ts +++ b/x-pack/plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts.ts @@ -34,6 +34,6 @@ query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId } `; -export const createGetMonitorChartsQuery = gql` +export const getMonitorChartsQuery = gql` ${getMonitorChartsQueryString} `; diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts_query.tsx b/x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts_query.tsx index 53442c3fd6b4b..275b0f1deea27 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/monitor_charts/monitor_charts_query.tsx @@ -6,67 +6,55 @@ import { i18n } from '@kbn/i18n'; import React from 'react'; -import { Query } from 'react-apollo'; import { MonitorChart } from '../../../../common/graphql/types'; import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper'; import { UptimeCommonProps } from '../../../uptime_app'; import { MonitorCharts } from '../../functional'; -import { createGetMonitorChartsQuery } from './get_monitor_charts'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; +import { getMonitorChartsQuery } from './get_monitor_charts'; + +interface MonitorChartsQueryResult { + monitorChartsData?: MonitorChart; +} interface MonitorChartsProps { monitorId: string; } -type Props = MonitorChartsProps & UptimeCommonProps; +type Props = MonitorChartsProps & + UptimeCommonProps & + UptimeGraphQLQueryProps; -export const MonitorChartsQuery = ({ - colors: { primary, secondary, danger }, - dateRangeStart, - dateRangeEnd, - monitorId, - autorefreshIsPaused, - autorefreshInterval, -}: Props) => { - return ( - - {({ loading, error, data }) => { - if (loading) { - return i18n.translate('xpack.uptime.monitorCharts.loadingMessage', { - defaultMessage: 'Loading…', - }); - } - if (error) { - return i18n.translate('xpack.uptime.monitorCharts.errorMessage', { - values: { message: error.message }, - defaultMessage: 'Error {message}', - }); - } +const makeMonitorCharts = ({ colors: { success, range, mean, danger }, data }: Props) => { + if (data && data.monitorChartsData) { + const { + monitorChartsData, + monitorChartsData: { durationMaxValue, statusMaxCount }, + } = data; - const { - monitorChartsData, - monitorChartsData: { durationMaxValue, statusMaxCount }, - }: { monitorChartsData: MonitorChart } = data; + const durationMax = microsToMillis(durationMaxValue); + // These limits provide domain sizes for the charts + const checkDomainLimits = [0, statusMaxCount]; + const durationDomainLimits = [0, durationMax ? durationMax : 0]; - const durationMax = microsToMillis(durationMaxValue); - // These limits provide domain sizes for the charts - const checkDomainLimits = [0, statusMaxCount]; - const durationDomainLimits = [0, durationMax ? durationMax : 0]; - - return ( - - ); - }} - - ); + return ( + + ); + } + return i18n.translate('xpack.uptime.monitorCharts.loadingMessage', { + defaultMessage: 'Loading…', + }); }; + +export const MonitorChartsQuery = withUptimeGraphQL( + makeMonitorCharts, + getMonitorChartsQuery +); diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_list/monitor_list_query.tsx b/x-pack/plugins/uptime/public/components/queries/monitor_list/monitor_list_query.tsx index 74509dae81023..194e53a4ec7f0 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_list/monitor_list_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/monitor_list/monitor_list_query.tsx @@ -4,50 +4,37 @@ * you may not use this file except in compliance with the Elastic License. */ -import { i18n } from '@kbn/i18n'; import { get } from 'lodash'; import React from 'react'; -import { Query } from 'react-apollo'; import { LatestMonitor } from '../../../../common/graphql/types'; import { UptimeCommonProps } from '../../../uptime_app'; import { MonitorList } from '../../functional/monitor_list'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; import { getMonitorListQuery } from './get_monitor_list'; -interface MonitorListProps { - filters?: string; +interface MonitorListQueryResult { + // TODO: clean up this ugly result data shape, there should be no nesting + monitorStatus?: { + monitors: LatestMonitor[]; + }; } -type Props = MonitorListProps & UptimeCommonProps; +type Props = UptimeCommonProps & UptimeGraphQLQueryProps; -export const MonitorListQuery = ({ - autorefreshInterval, - autorefreshIsPaused, - colors: { primary, danger }, - dateRangeStart, - dateRangeEnd, - filters, -}: Props) => ( - - {({ loading, error, data }) => { - if (error) { - return i18n.translate('xpack.uptime.monitorList.errorMessage', { - values: { message: error.message }, - defaultMessage: 'Error {message}', - }); - } - const monitors: LatestMonitor[] | undefined = get(data, 'monitorStatus.monitors', undefined); - return ( - - ); - }} - +const makeMonitorListQuery = ({ colors: { success, danger }, data, loading }: Props) => { + const monitors: LatestMonitor[] | undefined = get(data, 'monitorStatus.monitors'); + + return ( + + ); +}; + +export const MonitorListQuery = withUptimeGraphQL( + makeMonitorListQuery, + getMonitorListQuery ); diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_page_title/get_monitor_page_title.ts b/x-pack/plugins/uptime/public/components/queries/monitor_page_title/get_monitor_page_title.ts index 5d5446ffa6992..a54af690c37c7 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_page_title/get_monitor_page_title.ts +++ b/x-pack/plugins/uptime/public/components/queries/monitor_page_title/get_monitor_page_title.ts @@ -6,7 +6,7 @@ import gql from 'graphql-tag'; -export const getMonitorPageTitle = gql` +export const getMonitorPageTitleQuery = gql` query MonitorPageTitle($monitorId: String!) { monitorPageTitle: getMonitorPageTitle(monitorId: $monitorId) { id diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_page_title/monitor_page_title_query.tsx b/x-pack/plugins/uptime/public/components/queries/monitor_page_title/monitor_page_title_query.tsx index dcbe79cfaa27a..5c36793dfc465 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_page_title/monitor_page_title_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/monitor_page_title/monitor_page_title_query.tsx @@ -6,37 +6,33 @@ import { EuiLoadingSpinner } from '@elastic/eui'; import React from 'react'; -import { Query } from 'react-apollo'; import { MonitorPageTitle as TitleType } from '../../../../common/graphql/types'; import { UptimeCommonProps } from '../../../uptime_app'; import { MonitorPageTitle } from '../../functional'; -import { getMonitorPageTitle } from './get_monitor_page_title'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; +import { getMonitorPageTitleQuery } from './get_monitor_page_title'; + +interface MonitorPageTitleQueryResult { + monitorPageTitle?: TitleType; +} interface MonitorPageTitleProps { monitorId: string; } -type Props = MonitorPageTitleProps & UptimeCommonProps; +type Props = MonitorPageTitleProps & + UptimeCommonProps & + UptimeGraphQLQueryProps; + +export const makeMonitorPageTitleQuery = ({ data }: Props) => { + if (data && data.monitorPageTitle) { + const { monitorPageTitle } = data; + return ; + } + return ; +}; -export const MonitorPageTitleQuery = ({ - autorefreshInterval, - autorefreshIsPaused, - monitorId, -}: Props) => ( - - {({ loading, error, data }) => { - if (loading) { - return ; - } - if (error) { - return error; - } - const monitorPageTitle: TitleType = data.monitorPageTitle; - return ; - }} - -); +export const MonitorPageTitleQuery = withUptimeGraphQL< + MonitorPageTitleQueryResult, + MonitorPageTitleProps +>(makeMonitorPageTitleQuery, getMonitorPageTitleQuery); diff --git a/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar_query.tsx b/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar_query.tsx index d6e86111313c4..7b40d5960e614 100644 --- a/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/monitor_status_bar/monitor_status_bar_query.tsx @@ -5,70 +5,53 @@ */ import { i18n } from '@kbn/i18n'; -import { ApolloError } from 'apollo-client'; import { get } from 'lodash'; import React from 'react'; -import { Query } from 'react-apollo'; import { Ping } from '../../../../common/graphql/types'; import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper'; import { UptimeCommonProps } from '../../../uptime_app'; import { EmptyStatusBar, MonitorStatusBar } from '../../functional'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; import { getMonitorStatusBarQuery } from './get_monitor_status_bar'; -interface MonitorStatusBarProps { - monitorId: string; +interface MonitorStatusBarQueryResult { + monitorStatus?: Ping[]; } -interface MonitorStatusBarQueryParams { - loading: boolean; - error?: ApolloError | any; - data?: { monitorStatus: Ping[] }; +interface MonitorStatusBarProps { + monitorId: string; } -type Props = MonitorStatusBarProps & UptimeCommonProps; +type Props = MonitorStatusBarProps & + UptimeCommonProps & + UptimeGraphQLQueryProps; -export const MonitorStatusBarQuery = ({ - dateRangeStart, - dateRangeEnd, - monitorId, - autorefreshIsPaused, - autorefreshInterval, -}: Props) => ( - - {({ loading, error, data }: MonitorStatusBarQueryParams) => { - if (loading) { - return ( - - ); - } - if (error) { - return i18n.translate('xpack.uptime.monitorStatusBar.errorMessage', { - values: { message: error.message }, - defaultMessage: 'Error {message}', - }); - } +const makeMonitorStatusBar = ({ monitorId, data }: Props) => { + if (data && data.monitorStatus) { + const { monitorStatus } = data; + if (!monitorStatus.length) { + return ; + } + const { monitor, timestamp, url } = monitorStatus[0]; + const status = get(monitor, 'status', undefined); + const duration = microsToMillis(get(monitor, 'duration.us', null)); + const full = get(url, 'full', undefined); - const monitorStatus: Ping[] = get(data, 'monitorStatus'); - if (!monitorStatus || !monitorStatus.length) { - return ; - } - const { monitor, timestamp, url } = monitorStatus[0]; - const status = get(monitor, 'status', undefined); - const duration = microsToMillis(get(monitor, 'duration.us', null)); - const full = get(url, 'full', undefined); + return ( + + ); + } + return ( + + ); +}; - return ( - - ); - }} - -); +export const MonitorStatusBarQuery = withUptimeGraphQL< + MonitorStatusBarQueryResult, + MonitorStatusBarProps +>(makeMonitorStatusBar, getMonitorStatusBarQuery); diff --git a/x-pack/plugins/uptime/public/components/queries/ping_list/ping_list_query.tsx b/x-pack/plugins/uptime/public/components/queries/ping_list/ping_list_query.tsx index 69d8295bd6675..f06aeaf38b06f 100644 --- a/x-pack/plugins/uptime/public/components/queries/ping_list/ping_list_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/ping_list/ping_list_query.tsx @@ -6,34 +6,41 @@ import { EuiComboBoxOptionProps } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { get } from 'lodash'; import React from 'react'; -import { Query } from 'react-apollo'; import { UMPingSortDirectionArg } from '../../../../common/domain_types'; +import { PingResults } from '../../../../common/graphql/types'; import { UptimeCommonProps } from '../../../uptime_app'; import { PingList } from '../../functional'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; import { getPingsQuery } from './get_pings'; -const DEFAULT_MAX_SEARCH_SIZE = 100; +interface PingListQueryResult { + allPings?: PingResults; +} interface PingListProps { monitorId?: string; + selectedOption?: EuiComboBoxOptionProps; sort?: UMPingSortDirectionArg; size?: number; + onStatusSelectionChange: (selectedOptions: EuiComboBoxOptionProps[]) => void; } -type Props = PingListProps & UptimeCommonProps; +type Props = PingListProps & + UptimeCommonProps & + UptimeGraphQLQueryProps & + PingListProps; interface PingListState { statusOptions: EuiComboBoxOptionProps[]; - selectedOption: EuiComboBoxOptionProps; - maxSearchSize: number; } -export class PingListQuery extends React.Component { +export class Query extends React.Component { constructor(props: Props) { super(props); - const statusOptions = [ + const statusOptions: EuiComboBoxOptionProps[] = [ { label: i18n.translate('xpack.uptime.pingList.statusOptions.allStatusOptionLabel', { defaultMessage: 'All', @@ -55,74 +62,26 @@ export class PingListQuery extends React.Component { ]; this.state = { statusOptions, - selectedOption: statusOptions[2], - maxSearchSize: DEFAULT_MAX_SEARCH_SIZE, }; + this.props.onStatusSelectionChange([this.state.statusOptions[2]]); } + public render() { - const { - monitorId, - dateRangeStart, - dateRangeEnd, - autorefreshIsPaused, - autorefreshInterval, - sort, - size, - } = this.props; - const { selectedOption } = this.state; + const { loading, data } = this.props; + const allPings: PingResults | undefined = get(data, 'allPings', undefined); return ( - - {({ loading, error, data }) => { - if (error) { - return i18n.translate('xpack.uptime.pingList.errorMessage', { - values: { message: error.message }, - defaultMessage: 'Error {message}', - }); - } - const { allPings } = data; - return ( - - ); - }} - + ); } - - private onSearchSizeBlur = (e: React.FocusEvent) => { - const sanitizedValue = parseInt(e.target.value, 10); - if (!isNaN(sanitizedValue)) { - this.setState({ - maxSearchSize: sanitizedValue >= 10000 ? 10000 : sanitizedValue, - }); - } - }; - - private onSelectedOptionChange = (selectedOptions: EuiComboBoxOptionProps[]) => { - if (selectedOptions[0]) { - this.setState({ selectedOption: selectedOptions[0] }); - } - }; } + +export const PingListQuery = withUptimeGraphQL( + Query, + getPingsQuery +); diff --git a/x-pack/plugins/uptime/public/components/queries/snapshot/snapshot_query.tsx b/x-pack/plugins/uptime/public/components/queries/snapshot/snapshot_query.tsx index c00be54952362..18ebea9594a5a 100644 --- a/x-pack/plugins/uptime/public/components/queries/snapshot/snapshot_query.tsx +++ b/x-pack/plugins/uptime/public/components/queries/snapshot/snapshot_query.tsx @@ -4,82 +4,28 @@ * you may not use this file except in compliance with the Elastic License. */ -import { i18n } from '@kbn/i18n'; import React from 'react'; -import { Query } from 'react-apollo'; import { Snapshot as SnapshotType } from '../../../../common/graphql/types'; import { UptimeCommonProps } from '../../../uptime_app'; import { Snapshot, SnapshotLoading } from '../../functional'; +import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order'; import { getSnapshotQuery } from './get_snapshot'; -interface SnapshotQueryProps { - filters?: string; +interface SnapshotQueryResult { + snapshot?: SnapshotType; } -interface SnapshotQueryState { - windowWidth: number; -} - -type Props = SnapshotQueryProps & UptimeCommonProps; - -export class SnapshotQuery extends React.Component { - constructor(props: Props) { - super(props); - this.state = { - windowWidth: window.innerWidth, - }; - } - - public componentDidMount() { - window.addEventListener('resize', this.updateWindowSize); - } +type Props = UptimeCommonProps & UptimeGraphQLQueryProps; - public componentWillUnmount() { - window.removeEventListener('resize', this.updateWindowSize); +const Query = (props: Props) => { + const { + colors: { success, danger }, + data, + } = props; + if (data && data.snapshot) { + return ; } + return ; +}; - public render() { - const { - autorefreshIsPaused, - autorefreshInterval, - colors: { primary, danger }, - dateRangeStart, - dateRangeEnd, - filters, - } = this.props; - - return ( - - {({ loading, error, data }) => { - if (loading) { - return ; - } - if (error) { - return i18n.translate('xpack.uptime.snapshot.errorMessage', { - values: { message: error.message }, - defaultMessage: 'Error {message}', - }); - } - const { snapshot }: { snapshot: SnapshotType } = data; - - return ( - - ); - }} - - ); - } - - private updateWindowSize = () => { - this.setState({ windowWidth: window.innerWidth }); - }; -} +export const SnapshotQuery = withUptimeGraphQL(Query, getSnapshotQuery); diff --git a/x-pack/plugins/uptime/public/lib/adapters/framework/kibana_framework_adapter.ts b/x-pack/plugins/uptime/public/lib/adapters/framework/kibana_framework_adapter.ts index d3ef8cf4b7fbe..29630cc4ba9f8 100644 --- a/x-pack/plugins/uptime/public/lib/adapters/framework/kibana_framework_adapter.ts +++ b/x-pack/plugins/uptime/public/lib/adapters/framework/kibana_framework_adapter.ts @@ -114,10 +114,10 @@ export class UMKibanaFrameworkAdapter implements UMFrameworkAdapter { renderComponent({ basePath, darkMode, - updateBreadcrumbs: chrome.breadcrumbs.set, + setBreadcrumbs: chrome.breadcrumbs.set, kibanaBreadcrumbs, routerBasename, - graphQLClient, + client: graphQLClient, initialAutorefreshIsPaused: autorefreshIsPaused, initialAutorefreshInterval: autorefreshInterval, initialDateRangeStart: dateRangeStart, diff --git a/x-pack/plugins/uptime/public/lib/helper/__test__/__snapshots__/format_error_string.test.ts.snap b/x-pack/plugins/uptime/public/lib/helper/__test__/__snapshots__/format_error_string.test.ts.snap new file mode 100644 index 0000000000000..8519157e4039e --- /dev/null +++ b/x-pack/plugins/uptime/public/lib/helper/__test__/__snapshots__/format_error_string.test.ts.snap @@ -0,0 +1,7 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`formatErrorString returns a formatted string containing each error 1`] = ` +"Error: foo is bar +Error: bar is not foo +" +`; diff --git a/x-pack/plugins/uptime/public/lib/helper/__test__/format_error_string.test.ts b/x-pack/plugins/uptime/public/lib/helper/__test__/format_error_string.test.ts new file mode 100644 index 0000000000000..ba437c05cbe2b --- /dev/null +++ b/x-pack/plugins/uptime/public/lib/helper/__test__/format_error_string.test.ts @@ -0,0 +1,41 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { formatUptimeGraphQLErrorList } from '../format_error_list'; + +describe('formatErrorString', () => { + it('returns an empty string for empty array', () => { + const result = formatUptimeGraphQLErrorList([]); + expect(result).toEqual(''); + }); + it('returns a formatted string containing each error', () => { + const result = formatUptimeGraphQLErrorList([ + { + message: 'foo is bar', + locations: undefined, + path: undefined, + nodes: undefined, + source: undefined, + positions: undefined, + originalError: undefined, + extensions: undefined, + name: 'test error', + }, + { + message: 'bar is not foo', + locations: undefined, + path: undefined, + nodes: undefined, + source: undefined, + positions: undefined, + originalError: undefined, + extensions: undefined, + name: 'test error', + }, + ]); + expect(result).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/uptime/public/lib/helper/format_error_list.ts b/x-pack/plugins/uptime/public/lib/helper/format_error_list.ts new file mode 100644 index 0000000000000..a23122c5eead5 --- /dev/null +++ b/x-pack/plugins/uptime/public/lib/helper/format_error_list.ts @@ -0,0 +1,20 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { i18n } from '@kbn/i18n'; +import { GraphQLError } from 'graphql'; + +export const formatUptimeGraphQLErrorList = (errors: GraphQLError[]) => + errors.reduce( + (errorString, error) => + errorString.concat( + `${i18n.translate('xpack.uptime.errorMessage', { + values: { message: error.message }, + defaultMessage: 'Error: {message}', + })}\n` + ), + '' + ); diff --git a/x-pack/plugins/uptime/public/pages/monitor.tsx b/x-pack/plugins/uptime/public/pages/monitor.tsx index 09a276d580c02..25d4c3df0fdea 100644 --- a/x-pack/plugins/uptime/public/pages/monitor.tsx +++ b/x-pack/plugins/uptime/public/pages/monitor.tsx @@ -5,11 +5,14 @@ */ import { + EuiComboBoxOptionProps, // @ts-ignore No typings for EuiSpacer EuiSpacer, // @ts-ignore No typings for EuiSuperSelect EuiSuperSelect, } from '@elastic/eui'; +import { ApolloQueryResult, OperationVariables, QueryOptions } from 'apollo-client'; +import gql from 'graphql-tag'; import React, { Fragment } from 'react'; import { getMonitorPageBreadcrumb } from '../breadcrumbs'; import { @@ -18,41 +21,107 @@ import { MonitorStatusBarQuery, PingListQuery, } from '../components/queries'; -import { UMUpdateBreadcrumbs } from '../lib/lib'; import { UptimeCommonProps } from '../uptime_app'; interface MonitorPageProps { - updateBreadcrumbs: UMUpdateBreadcrumbs; history: { push: any }; location: { pathname: string }; match: { params: { id: string } }; + // this is the query function provided by Apollo's Client API + query: ( + options: QueryOptions + ) => Promise>; } type Props = MonitorPageProps & UptimeCommonProps; -export class MonitorPage extends React.Component { +interface MonitorPageState { + monitorId: string; + selectedPingListOption?: EuiComboBoxOptionProps; +} + +export class MonitorPage extends React.Component { constructor(props: Props) { super(props); + + // TODO: this is a hack because the id field's characters mess up react router's + // inner params parsing, when we add a synthetic ID for monitors this problem should go away + this.state = { + monitorId: this.props.location.pathname.replace(/^(\/monitor\/)/, ''), + }; } - public componentWillMount() { - this.props.updateBreadcrumbs(getMonitorPageBreadcrumb()); + public componentDidMount() { + const { query, setBreadcrumbs, setHeadingText } = this.props; + const { monitorId } = this.state; + + query({ + query: gql` + query MonitorPageTitle($monitorId: String!) { + monitorPageTitle: getMonitorPageTitle(monitorId: $monitorId) { + id + url + name + } + } + `, + variables: { monitorId }, + }).then((result: any) => { + const { name, url, id } = result.data.monitorPageTitle; + const heading: string = name || url || id; + setBreadcrumbs(getMonitorPageBreadcrumb(heading)); + setHeadingText(heading); + }); } public render() { - // TODO: this is a hack because the id field's characters mess up react router's - // inner params parsing, when we add a synthetic ID for monitors this problem should go away - const id = this.props.location.pathname.replace(/^(\/monitor\/)/, ''); + const { dateRangeStart, dateRangeEnd } = this.props; + const { monitorId } = this.state; + return ( - - - - - - - + + + + + + + ); } + + private onPingListStatusSelectionChange = (selectedOptions: EuiComboBoxOptionProps[]) => { + if (selectedOptions[0]) { + this.setState({ selectedPingListOption: selectedOptions[0] }, () => this.props.refreshApp()); + } + }; } diff --git a/x-pack/plugins/uptime/public/pages/overview.tsx b/x-pack/plugins/uptime/public/pages/overview.tsx index b654353fcf8de..761f305120d8f 100644 --- a/x-pack/plugins/uptime/public/pages/overview.tsx +++ b/x-pack/plugins/uptime/public/pages/overview.tsx @@ -4,7 +4,9 @@ * you may not use this file except in compliance with the Elastic License. */ -import { EuiSpacer } from '@elastic/eui'; +// @ts-ignore EuiSearchBar missing +import { EuiSearchBar, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import React, { Fragment } from 'react'; import { getOverviewPageBreadcrumbs } from '../breadcrumbs'; import { @@ -25,9 +27,12 @@ interface OverviewPageProps { type Props = OverviewPageProps & UptimeCommonProps; interface OverviewPageState { + currentFilterObj?: object; currentFilterQuery?: string; } +export type UptimeSearchBarQueryChangeHandler = ({ query }: { query?: { text: string } }) => void; + export class OverviewPage extends React.Component { constructor(props: Props) { super(props); @@ -38,25 +43,63 @@ export class OverviewPage extends React.Component { public componentWillMount() { this.props.setBreadcrumbs(getOverviewPageBreadcrumbs()); + this.props.setHeadingText( + i18n.translate('xpack.uptime.overviewPage.headerText', { + defaultMessage: 'Overview', + description: `The text that will be displayed in the app's heading when the Overview page loads.`, + }) + ); } public render() { + const commonVariables = { + dateRangeStart: this.props.dateRangeStart, + dateRangeEnd: this.props.dateRangeEnd, + filters: this.state.currentFilterQuery, + }; return ( - + { - this.setState({ currentFilterQuery: query ? JSON.stringify(query) : query }); - }} + currentQuery={this.state.currentFilterObj} + updateQuery={this.onFilterQueryChange} + variables={commonVariables} /> - - - - - + + + + + + ); } + + private onFilterQueryChange: UptimeSearchBarQueryChangeHandler = ({ + query, + }: { + query?: { text: string }; + }) => { + try { + let esQuery; + if (query && query.text) { + esQuery = EuiSearchBar.Query.toESQuery(query); + } + this.setState( + { + currentFilterObj: query, + currentFilterQuery: esQuery ? JSON.stringify(esQuery) : esQuery, + }, + () => this.props.refreshApp() + ); + } catch (e) { + this.setState({ currentFilterQuery: undefined }); + } + }; } diff --git a/x-pack/plugins/uptime/public/uptime_app.tsx b/x-pack/plugins/uptime/public/uptime_app.tsx index 90cc368939a93..fbaf27632f97d 100644 --- a/x-pack/plugins/uptime/public/uptime_app.tsx +++ b/x-pack/plugins/uptime/public/uptime_app.tsx @@ -5,25 +5,25 @@ */ import { - EuiHeader, + EuiFlexGroup, + EuiFlexItem, // @ts-ignore missing typings for EuiHeaderLink EuiHeaderLink, // @ts-ignore missing typings for EuiHeaderLinks - EuiHeaderLinks, - // @ts-ignore missing typings for EuiHeaderLogo EuiHeaderLogo, - EuiHeaderSection, - // @ts-ignore missing typings for EuiHeaderSectionItem + // @ts-ignore missing typings for EuiHeaderLogo EuiHeaderSectionItem, + // @ts-ignore missing typings for EuiHeaderSectionItem EuiPage, - EuiPageContent, + EuiSpacer, // @ts-ignore missing typings for EuiSuperDatePicker EuiSuperDatePicker, + EuiTitle, } from '@elastic/eui'; import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json'; import euiLightVars from '@elastic/eui/dist/eui_theme_light.json'; -import { i18n } from '@kbn/i18n'; -import { FormattedMessage } from '@kbn/i18n/react'; +import { NormalizedCacheObject } from 'apollo-cache-inmemory'; +import ApolloClient from 'apollo-client'; import React from 'react'; import { ApolloProvider } from 'react-apollo'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; @@ -34,17 +34,23 @@ import { MonitorPage, OverviewPage } from './pages'; interface UptimeAppColors { danger: string; - primary: string; - secondary: string; + success: string; + range: string; + mean: string; } // TODO: these props are global to this app, we should put them in a context export interface UptimeCommonProps { autorefreshIsPaused: boolean; autorefreshInterval: number; + client: ApolloClient; + colors: UptimeAppColors; dateRangeStart: string; dateRangeEnd: string; - colors: UptimeAppColors; + lastRefresh?: number; + refreshApp: () => void; + setBreadcrumbs: UMUpdateBreadcrumbs; + setHeadingText: (text: string) => void; } export interface UptimePersistedState { @@ -58,14 +64,14 @@ export interface UptimeAppProps { // TODO: if we add a context to the Uptime UI, this should be included in it basePath: string; darkMode: boolean; - graphQLClient: UMGraphQLClient; + client: UMGraphQLClient; initialDateRangeStart: string; initialDateRangeEnd: string; initialAutorefreshInterval: number; initialAutorefreshIsPaused: boolean; kibanaBreadcrumbs: UMBreadcrumb[]; routerBasename: string; - updateBreadcrumbs: UMUpdateBreadcrumbs; + setBreadcrumbs: UMUpdateBreadcrumbs; persistState(state: UptimePersistedState): void; renderGlobalHelpControls(): void; } @@ -77,6 +83,8 @@ interface UptimeAppState { colors: UptimeAppColors; dateRangeStart: string; dateRangeEnd: string; + headingText?: string; + lastRefresh?: number; } // TODO: when EUI exports types for this, this should be replaced @@ -102,23 +110,25 @@ class Application extends React.Component { initialDateRangeStart: dateRangeStart, initialDateRangeEnd: dateRangeEnd, kibanaBreadcrumbs, - updateBreadcrumbs, + setBreadcrumbs, } = props; - this.setBreadcrumbs = updateBreadcrumbs; + this.setBreadcrumbs = setBreadcrumbs; let colors: UptimeAppColors; if (darkMode) { colors = { - primary: euiDarkVars.euiColorVis1, - secondary: euiDarkVars.euiColorVis0, - danger: euiDarkVars.euiColorVis9, + success: euiDarkVars.euiColorSuccess, + range: euiDarkVars.euiFocusBackgroundColor, + mean: euiDarkVars.euiColorPrimary, + danger: euiDarkVars.euiColorDanger, }; } else { colors = { - primary: euiLightVars.euiColorVis1, - secondary: euiLightVars.euiColorVis0, - danger: euiLightVars.euiColorVis9, + success: euiLightVars.euiColorSuccess, + range: euiLightVars.euiFocusBackgroundColor, + mean: euiLightVars.euiColorPrimary, + danger: euiLightVars.euiColorDanger, }; } @@ -141,44 +151,22 @@ class Application extends React.Component { } public render() { - const { basePath, routerBasename, graphQLClient } = this.props; + const { basePath, routerBasename, client } = this.props; return ( - - - - {/* - // @ts-ignore TODO no typings for grow prop */} - - - - - - - - - -
+ + +
+ + + +

{this.state.headingText}

+
+
+ + { + // @ts-ignore onRefresh is not defined on EuiSuperDatePicker's type yet { { dateRangeStart: start, dateRangeEnd: end }, this.persistState ); + this.refreshApp(); }} + // @ts-ignore onRefresh is not defined on EuiSuperDatePicker's type yet + onRefresh={() => this.refreshApp()} onRefreshChange={({ isPaused, refreshInterval, @@ -203,13 +194,11 @@ class Application extends React.Component { this.persistState ); }} - showUpdateButton={false} /> -
- - - - + } + + + { )} /> @@ -228,13 +219,16 @@ class Application extends React.Component { render={props => ( )} /> - +
@@ -242,6 +236,10 @@ class Application extends React.Component { ); } + private setHeadingText = (headingText: string): void => { + this.setState({ headingText }); + }; + private persistState = (): void => { const { autorefreshIsPaused, autorefreshInterval, dateRangeStart, dateRangeEnd } = this.state; this.props.persistState({ @@ -251,6 +249,13 @@ class Application extends React.Component { dateRangeEnd, }); }; + + private refreshApp = () => { + this.setState(state => ({ + ...state, + lastRefresh: Date.now(), + })); + }; } export const UptimeApp = (props: UptimeAppProps) => ; diff --git a/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts b/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts index eb8109841dee6..d799889956be6 100644 --- a/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts +++ b/x-pack/plugins/uptime/server/graphql/monitors/schema.gql.ts @@ -96,9 +96,9 @@ export const monitorsSchema = gql` "Information from the latest document." ping: Ping "Buckets of recent up count status data." - upSeries: [MonitorSeriesPoint] + upSeries: [MonitorSeriesPoint!] "Buckets of recent down count status data." - downSeries: [MonitorSeriesPoint] + downSeries: [MonitorSeriesPoint!] } type LatestMonitorsResult { @@ -112,6 +112,7 @@ export const monitorsSchema = gql` count: Int statusCode: String timestamp: String + name: String } type MonitorPageTitle { diff --git a/x-pack/plugins/uptime/server/graphql/pings/schema.gql.ts b/x-pack/plugins/uptime/server/graphql/pings/schema.gql.ts index d43f890b2e2bb..8ff7a5040068c 100644 --- a/x-pack/plugins/uptime/server/graphql/pings/schema.gql.ts +++ b/x-pack/plugins/uptime/server/graphql/pings/schema.gql.ts @@ -207,7 +207,7 @@ export const pingsSchema = gql` "The timestamp of the ping's creation" timestamp: String! "Milliseconds from the timestamp to the current time" - millisFromNow: Int + millisFromNow: UnsignedInteger "The agent that recorded the ping" beat: Beat docker: Docker diff --git a/x-pack/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts b/x-pack/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts index 8fda903ea26cf..209c6e0642f29 100644 --- a/x-pack/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/monitors/elasticsearch_monitors_adapter.ts @@ -483,6 +483,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { const errorMessage = get(source, 'error.message', null); const statusCode = get(source, 'http.response.status_code', null); const timestamp = get(source, '@timestamp', null); + const name = get(source, 'monitor.name', null); errorsList.push({ latestMessage: errorMessage, monitorId, @@ -490,6 +491,7 @@ export class ElasticsearchMonitorsAdapter implements UMMonitorsAdapter { count, statusCode, timestamp, + name: name === '' ? null : name, }); }); } diff --git a/x-pack/plugins/uptime/server/lib/adapters/pings/__tests__/__snapshots__/elasticsearch_pings_adapter.test.ts.snap b/x-pack/plugins/uptime/server/lib/adapters/pings/__tests__/__snapshots__/elasticsearch_pings_adapter.test.ts.snap new file mode 100644 index 0000000000000..a7526739c95ac --- /dev/null +++ b/x-pack/plugins/uptime/server/lib/adapters/pings/__tests__/__snapshots__/elasticsearch_pings_adapter.test.ts.snap @@ -0,0 +1,82 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ElasticsearchPingsAdapter class getPingHistogram handles simple_text_query without issues 1`] = ` +Array [ + Object { + "downCount": 1, + "key": 1, + "upCount": 2, + "x": 2, + "x0": 1, + "y": 1, + }, + Object { + "downCount": 2, + "key": 2, + "upCount": 1, + "x": 3, + "x0": 2, + "y": 1, + }, +] +`; + +exports[`ElasticsearchPingsAdapter class getPingHistogram handles status + additional user queries 1`] = ` +Array [ + Object { + "downCount": 1, + "key": 1, + "upCount": 0, + "x": 2, + "x0": 1, + "y": 1, + }, + Object { + "downCount": 2, + "key": 2, + "upCount": 0, + "x": 3, + "x0": 2, + "y": 1, + }, +] +`; + +exports[`ElasticsearchPingsAdapter class getPingHistogram returns a down-filtered array for when filtered by down status 1`] = ` +Array [ + Object { + "downCount": 1, + "key": 1, + "upCount": 0, + "x": 2, + "x0": 1, + "y": 1, + }, +] +`; + +exports[`ElasticsearchPingsAdapter class getPingHistogram returns a down-filtered array for when filtered by up status 1`] = ` +Array [ + Object { + "downCount": 0, + "key": 1, + "upCount": 2, + "x": 2, + "x0": 1, + "y": 1, + }, +] +`; + +exports[`ElasticsearchPingsAdapter class getPingHistogram returns expected result for no status filter 1`] = ` +Array [ + Object { + "downCount": 1, + "key": 1, + "upCount": 2, + "x": 2, + "x0": 1, + "y": 1, + }, +] +`; diff --git a/x-pack/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts b/x-pack/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts index 0de453e2027c8..f1500e69a9335 100644 --- a/x-pack/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/pings/__tests__/elasticsearch_pings_adapter.test.ts @@ -55,6 +55,296 @@ describe('ElasticsearchPingsAdapter class', () => { }; }); + describe('getPingHistogram', () => { + it('returns an empty array for <= 1 bucket', async () => { + expect.assertions(2); + const search = jest.fn(); + search.mockReturnValue({ + aggregations: { + timeseries: { + buckets: [ + { + key: 1, + bucket_total: { + value: 2, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + ], + }, + }, + }); + const pingDatabase = { search, count: jest.fn() }; + const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); + const result = await pingAdapter.getPingHistogram(serverRequest, '1234', '5678', null); + expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(result).toEqual([]); + }); + + it('returns expected result for no status filter', async () => { + expect.assertions(2); + const search = jest.fn(); + search.mockReturnValue({ + aggregations: { + timeseries: { + buckets: [ + { + key: 1, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + { + key: 2, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + ], + }, + }, + }); + const pingDatabase = { search, count: jest.fn() }; + const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); + const result = await pingAdapter.getPingHistogram(serverRequest, '1234', '5678', null); + + expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(result).toMatchSnapshot(); + }); + + it('handles status + additional user queries', async () => { + expect.assertions(2); + const search = jest.fn(); + search.mockReturnValue({ + aggregations: { + timeseries: { + buckets: [ + { + key: 1, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + { + key: 2, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 2, + }, + }, + }, + { + key: 3, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + ], + }, + }, + }); + const searchFilter = { + bool: { + must: [ + { match: { 'monitor.status': { query: 'down', operator: 'and' } } }, + { match: { 'monitor.id': { query: 'auto-http-0X89BB0F9A6C81D178', operator: 'and' } } }, + { match: { 'monitor.name': { query: 'my-new-test-site-name', operator: 'and' } } }, + ], + }, + }; + const pingDatabase = { search, count: jest.fn() }; + const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); + const result = await pingAdapter.getPingHistogram( + serverRequest, + '1234', + '5678', + JSON.stringify(searchFilter) + ); + + expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(result).toMatchSnapshot(); + }); + + it('handles simple_text_query without issues', async () => { + expect.assertions(2); + const search = jest.fn(); + search.mockReturnValue({ + aggregations: { + timeseries: { + buckets: [ + { + key: 1, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + { + key: 2, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 2, + }, + }, + }, + { + key: 3, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + ], + }, + }, + }); + const searchFilter = `{"bool":{"must":[{"simple_query_string":{"query":"http"}}]}}`; + const pingDatabase = { search, count: jest.fn() }; + const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); + const result = await pingAdapter.getPingHistogram( + serverRequest, + '1234', + '5678', + searchFilter + ); + + expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(result).toMatchSnapshot(); + }); + + it('returns a down-filtered array for when filtered by down status', async () => { + expect.assertions(2); + const search = jest.fn(); + search.mockReturnValue({ + aggregations: { + timeseries: { + buckets: [ + { + key: 1, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + { + key: 2, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + ], + }, + }, + }); + const searchFilter = `{"bool":{"must":[{"match":{"monitor.status":{"query":"down","operator":"and"}}}]}}`; + const pingDatabase = { search, count: jest.fn() }; + const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); + const result = await pingAdapter.getPingHistogram( + serverRequest, + '1234', + '5678', + searchFilter + ); + + expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(result).toMatchSnapshot(); + }); + + it('returns a down-filtered array for when filtered by up status', async () => { + expect.assertions(2); + const search = jest.fn(); + search.mockReturnValue({ + aggregations: { + timeseries: { + buckets: [ + { + key: 1, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + { + key: 2, + bucket_total: { + value: 3, + }, + down: { + bucket_count: { + value: 1, + }, + }, + }, + ], + }, + }, + }); + const searchFilter = `{"bool":{"must":[{"match":{"monitor.status":{"query":"up","operator":"and"}}}]}}`; + const pingDatabase = { search, count: jest.fn() }; + const pingAdapter = new ElasticsearchPingsAdapter(pingDatabase); + const result = await pingAdapter.getPingHistogram( + serverRequest, + '1234', + '5678', + searchFilter + ); + + expect(pingDatabase.search).toHaveBeenCalledTimes(1); + expect(result).toMatchSnapshot(); + }); + }); + describe('getDocCount', () => { it('returns data in appropriate shape', async () => { const { count } = await adapter.getDocCount(serverRequest); @@ -75,7 +365,7 @@ describe('ElasticsearchPingsAdapter class', () => { filter: [{ range: { '@timestamp': { gte: 'now-1h', lte: 'now' } } }], }, }, - sort: [{ '@timestamp': { order: 'asc' } }], + sort: [{ '@timestamp': { order: 'desc' } }], size: 12, }, }; @@ -104,8 +394,8 @@ describe('ElasticsearchPingsAdapter class', () => { it('creates appropriate sort and size parameters', async () => { database.search = getAllSearchMock; - await adapter.getAll(serverRequest, 'now-1h', 'now', undefined, undefined, 'asc', 12); + set(expectedGetAllParams, 'body.sort[0]', { '@timestamp': { order: 'asc' } }); expect(database.search).toHaveBeenCalledTimes(1); expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); @@ -114,7 +404,7 @@ describe('ElasticsearchPingsAdapter class', () => { it('omits the sort param when no sort passed', async () => { database.search = getAllSearchMock; await adapter.getAll(serverRequest, 'now-1h', 'now', undefined, undefined, undefined, 12); - delete expectedGetAllParams.body.sort; + expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); }); @@ -123,6 +413,7 @@ describe('ElasticsearchPingsAdapter class', () => { await adapter.getAll(serverRequest, 'now-1h', 'now', undefined, undefined, 'desc'); delete expectedGetAllParams.body.size; set(expectedGetAllParams, 'body.sort[0].@timestamp.order', 'desc'); + expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); }); @@ -130,8 +421,8 @@ describe('ElasticsearchPingsAdapter class', () => { database.search = getAllSearchMock; await adapter.getAll(serverRequest, 'now-1h', 'now', 'testmonitorid'); delete expectedGetAllParams.body.size; - delete expectedGetAllParams.body.sort; expectedGetAllParams.body.query.bool.filter.push({ term: { 'monitor.id': 'testmonitorid' } }); + expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); }); @@ -139,8 +430,8 @@ describe('ElasticsearchPingsAdapter class', () => { database.search = getAllSearchMock; await adapter.getAll(serverRequest, 'now-1h', 'now', undefined, 'down'); delete expectedGetAllParams.body.size; - delete expectedGetAllParams.body.sort; expectedGetAllParams.body.query.bool.filter.push({ term: { 'monitor.status': 'down' } }); + expect(database.search).toHaveBeenCalledWith(serverRequest, expectedGetAllParams); }); }); diff --git a/x-pack/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts b/x-pack/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts index 2d0f659264bbe..545ffda8bc3ee 100644 --- a/x-pack/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts +++ b/x-pack/plugins/uptime/server/lib/adapters/pings/elasticsearch_pings_adapter.ts @@ -8,8 +8,7 @@ import { get } from 'lodash'; import moment from 'moment'; import { INDEX_NAMES } from '../../../../common/constants'; import { DocCount, HistogramDataPoint, Ping, PingResults } from '../../../../common/graphql/types'; -import { formatEsBucketsForHistogram } from '../../helper'; -import { getFilterFromMust } from '../../helper/get_filter_from_must'; +import { formatEsBucketsForHistogram, getFilteredQueryAndStatusFilter } from '../../helper'; import { DatabaseAdapter, HistogramQueryResult } from '../database'; import { UMPingsAdapter } from './adapter_types'; @@ -36,10 +35,10 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { dateRangeEnd: string, monitorId?: string | null, status?: string | null, - sort?: string | null, + sort: string | null = 'desc', size?: number | null ): Promise { - const sortParam = sort ? { sort: [{ '@timestamp': { order: sort } }] } : undefined; + const sortParam = { sort: [{ '@timestamp': { order: sort } }] }; const sizeParam = size ? { size } : undefined; const filter: any[] = [{ range: { '@timestamp': { gte: dateRangeStart, lte: dateRangeEnd } } }]; if (monitorId) { @@ -165,7 +164,11 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { dateRangeEnd: string, filters?: string | null ): Promise { - const query = getFilterFromMust(dateRangeStart, dateRangeEnd, filters); + const { statusFilter, query } = getFilteredQueryAndStatusFilter( + dateRangeStart, + dateRangeEnd, + filters + ); const params = { index: INDEX_NAMES.HEARTBEAT, body: { @@ -212,8 +215,8 @@ export class ElasticsearchPingsAdapter implements UMPingsAdapter { const downCount: number = get(bucket, 'down.bucket_count.value'); return { key, - downCount, - upCount: total - downCount, + downCount: statusFilter && statusFilter !== 'down' ? 0 : downCount, + upCount: statusFilter && statusFilter !== 'up' ? 0 : total - downCount, y: 1, }; }); diff --git a/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filtered_query_and_status.test.ts.snap b/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filtered_query_and_status.test.ts.snap index 777f86068ef86..4c5b9f9e754a5 100644 --- a/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filtered_query_and_status.test.ts.snap +++ b/x-pack/plugins/uptime/server/lib/helper/__test__/__snapshots__/get_filtered_query_and_status.test.ts.snap @@ -1,5 +1,42 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`getFilteredQueryAndStatusFilter handles simple_query_string 1`] = ` +Object { + "query": Object { + "bool": Object { + "filter": Array [ + Object { + "simple_query_string": Object { + "fields": Array [ + "monitor.id", + "monitor.url", + "monitor.type", + "monitor.status", + "monitor.name", + "url.full", + "url.path", + "url.scheme", + "url.domain", + "error.type", + ], + "query": "http", + }, + }, + Object { + "range": Object { + "@timestamp": Object { + "gte": "startRange", + "lte": "endRange", + }, + }, + }, + ], + }, + }, + "statusFilter": undefined, +} +`; + exports[`getFilteredQueryAndStatusFilter returns a range + id filter when status filter is absent 1`] = ` Object { "query": Object { diff --git a/x-pack/plugins/uptime/server/lib/helper/__test__/get_filtered_query_and_status.test.ts b/x-pack/plugins/uptime/server/lib/helper/__test__/get_filtered_query_and_status.test.ts index 7598b575cf657..89fba9b773cc0 100644 --- a/x-pack/plugins/uptime/server/lib/helper/__test__/get_filtered_query_and_status.test.ts +++ b/x-pack/plugins/uptime/server/lib/helper/__test__/get_filtered_query_and_status.test.ts @@ -39,4 +39,10 @@ describe('getFilteredQueryAndStatusFilter', () => { const result = getFilteredQueryAndStatusFilter(dateRangeStart, dateRangeEnd, filters); expect(result).toMatchSnapshot(); }); + + it('handles simple_query_string', () => { + filters = `{"bool":{"must":[{"simple_query_string":{"query":"http"}}]}}`; + const result = getFilteredQueryAndStatusFilter(dateRangeStart, dateRangeEnd, filters); + expect(result).toMatchSnapshot(); + }); }); diff --git a/x-pack/plugins/uptime/server/lib/helper/get_filtered_query.ts b/x-pack/plugins/uptime/server/lib/helper/get_filtered_query.ts index 3222f6a0dfd80..980804331f665 100644 --- a/x-pack/plugins/uptime/server/lib/helper/get_filtered_query.ts +++ b/x-pack/plugins/uptime/server/lib/helper/get_filtered_query.ts @@ -5,6 +5,7 @@ */ import { get, set } from 'lodash'; +import { QUERY } from '../../../common/constants'; export const getFilteredQuery = ( dateRangeStart: string, @@ -19,7 +20,16 @@ export const getFilteredQuery = ( filtersObj = filters; } if (get(filtersObj, 'bool.must', undefined)) { - const userFilters = get(filtersObj, 'bool.must', []); + const userFilters = get(filtersObj, 'bool.must', []).map((filter: any) => + filter.simple_query_string + ? { + simple_query_string: { + ...filter.simple_query_string, + fields: QUERY.SIMPLE_QUERY_STRING_FIELDS, + }, + } + : filter + ); delete filtersObj.bool.must; filtersObj.bool.filter = [...userFilters]; } diff --git a/x-pack/plugins/uptime/server/lib/helper/get_filtered_query_and_status.ts b/x-pack/plugins/uptime/server/lib/helper/get_filtered_query_and_status.ts index ca8a03f130241..79f47c7582408 100644 --- a/x-pack/plugins/uptime/server/lib/helper/get_filtered_query_and_status.ts +++ b/x-pack/plugins/uptime/server/lib/helper/get_filtered_query_and_status.ts @@ -14,7 +14,9 @@ import { getFilteredQuery } from './get_filtered_query'; const getMonitorsListFilteredQuery = (filters: any): string | undefined => { const must = get(filters, 'bool.must', []); if (must && must.length) { - const statusFilter = filters.bool.must.filter((filter: any) => filter.match['monitor.status']); + const statusFilter = filters.bool.must.filter( + (filter: any) => filter.match && filter.match['monitor.status'] + ); if (statusFilter.length) { return statusFilter[0].match['monitor.status'].query; } @@ -42,7 +44,10 @@ export const getFilteredQueryAndStatusFilter = ( filterObject = JSON.parse(filters); nonStatusFiters = getFilteredQuery(dateRangeStart, dateRangeEnd, { bool: { - must: filterObject.bool.must.filter((filter: any) => !filter.match['monitor.status']), + must: filterObject.bool.must.filter( + (filter: any) => + (filter.match && !filter.match['monitor.status']) || filter.simple_query_string + ), }, }); statusFilter = getMonitorsListFilteredQuery(filterObject); diff --git a/x-pack/test/api_integration/apis/uptime/get_all_pings.js b/x-pack/test/api_integration/apis/uptime/get_all_pings.js index d2c7cd3b3f5c3..ccb4f4584ca11 100644 --- a/x-pack/test/api_integration/apis/uptime/get_all_pings.js +++ b/x-pack/test/api_integration/apis/uptime/get_all_pings.js @@ -16,8 +16,8 @@ export default function ({ getService }) { describe('get_all_pings', () => { const archive = 'uptime/pings'; - before(() => esArchiver.load(archive)); - after(() => esArchiver.unload(archive)); + before('load heartbeat data', async () => await esArchiver.load(archive)); + after('unload heartbeat data', async () => await esArchiver.unload(archive)); it('should get all pings stored in index', async () => { const { body: apiResponse } = await supertest diff --git a/x-pack/test/api_integration/apis/uptime/graphql/error_list.js b/x-pack/test/api_integration/apis/uptime/graphql/error_list.js index 862cfefec4df0..1efa04678e5b2 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/error_list.js +++ b/x-pack/test/api_integration/apis/uptime/graphql/error_list.js @@ -71,7 +71,7 @@ export default function ({ getService }) { expect(data).to.eql(errorListFilteredByPort); }); - it('returns an error list filtered by port/scheme', async () => { + it('returns an error list filtered by port/type', async () => { const getErrorListQuery = { operationName: 'ErrorList', query: getErrorListQueryString, diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list.json index c21b764c51c21..30dcd12623f50 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list.json +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list.json @@ -6,7 +6,8 @@ "type": "io", "count": 843, "statusCode": null, - "timestamp": "2019-01-28T18:43:15.077Z" + "timestamp": "2019-01-28T18:43:15.077Z", + "name": null }, { "latestMessage": "dial tcp 127.0.0.1:9200: connect: connection refused", @@ -14,7 +15,8 @@ "type": "io", "count": 748, "statusCode": null, - "timestamp": "2019-01-28T17:59:34.075Z" + "timestamp": "2019-01-28T17:59:34.075Z", + "name": null }, { "latestMessage": "lookup www.reddit.com: no such host", @@ -22,7 +24,8 @@ "type": "io", "count": 1, "statusCode": null, - "timestamp": "2019-01-28T18:03:10.077Z" + "timestamp": "2019-01-28T18:03:10.077Z", + "name": null }, { "latestMessage": "received status code 301 expecting 200", @@ -30,7 +33,8 @@ "type": "validate", "count": 645, "statusCode": "301", - "timestamp": "2019-01-28T18:43:07.078Z" + "timestamp": "2019-01-28T18:43:07.078Z", + "name": null } ] } diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_id.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_id.json index 8fc0ff94bea81..7a26dd39a0078 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_id.json +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_id.json @@ -6,7 +6,8 @@ "type": "io", "count": 843, "statusCode": null, - "timestamp": "2019-01-28T18:43:15.077Z" + "timestamp": "2019-01-28T18:43:15.077Z", + "name": null } ] } diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_port.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_port.json index 94e1f4fbdfbf5..eb5d0fe721d3a 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_port.json +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_port.json @@ -6,7 +6,8 @@ "type": "io", "count": 748, "statusCode": null, - "timestamp": "2019-01-28T17:59:34.075Z" + "timestamp": "2019-01-28T17:59:34.075Z", + "name": null } ] } diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_port_and_type.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_port_and_type.json index 8fc0ff94bea81..7a26dd39a0078 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_port_and_type.json +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/error_list_filtered_by_port_and_type.json @@ -6,7 +6,8 @@ "type": "io", "count": 843, "statusCode": null, - "timestamp": "2019-01-28T18:43:15.077Z" + "timestamp": "2019-01-28T18:43:15.077Z", + "name": null } ] } diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list.json index 4398d60f22c39..c5bbefb5dd05a 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list.json +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list.json @@ -3,45 +3,42 @@ "total": 9231, "pings": [ { - "timestamp": "2019-01-28T17:47:08.078Z", + "timestamp": "2019-01-28T18:43:16.078Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1430 }, + "duration": { "us": 3328 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:09.075Z", + "timestamp": "2019-01-28T18:43:15.077Z", "http": null, "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", + "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", "type": "io" }, "monitor": { - "duration": { "us": 1370 }, - "id": "auto-tcp-0X81440A68E839814C", + "duration": { "us": 3331 }, + "id": "auto-http-0X3675F89EF0612091", "ip": "127.0.0.1", "name": "", "scheme": null, "status": "down", - "type": "tcp" + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:06.077Z", + "timestamp": "2019-01-28T18:43:15.077Z", "http": null, "error": null, "monitor": { - "duration": { "us": 1452 }, + "duration": { "us": 3292 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", @@ -51,98 +48,83 @@ } }, { - "timestamp": "2019-01-28T17:47:07.075Z", - "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:15.077Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 1094 }, - "id": "auto-tcp-0X81440A68E839814C", - "ip": "127.0.0.1", + "duration": { "us": 118727 }, + "id": "auto-http-0X970CBD2F2102BFA8", + "ip": "172.217.12.132", "name": "", "scheme": null, - "status": "down", - "type": "tcp" + "status": "up", + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:07.074Z", - "http": null, - "error": { - "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:15.077Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 1597 }, - "id": "auto-http-0X3675F89EF0612091", - "ip": "127.0.0.1", + "duration": { "us": 132169 }, + "id": "auto-http-0X131221E73F825974", + "ip": "172.217.12.132", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "http" } }, { - "timestamp": "2019-01-28T17:47:18.080Z", - "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:15.077Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 1699 }, - "id": "auto-tcp-0X81440A68E839814C", - "ip": "127.0.0.1", + "duration": { "us": 247244 }, + "id": "auto-http-0X9CB71300ABD5A2A8", + "ip": "192.30.253.112", "name": "", "scheme": null, - "status": "down", - "type": "tcp" + "status": "up", + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:19.076Z", + "timestamp": "2019-01-28T18:43:14.080Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 5384 }, + "duration": { "us": 2080 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:19.076Z", + "timestamp": "2019-01-28T18:43:13.075Z", "http": null, - "error": { - "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 5397 }, - "id": "auto-http-0X3675F89EF0612091", + "duration": { "us": 1921 }, + "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", - "type": "http" + "status": "up", + "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:19.077Z", - "http": { "response": { "status_code": 200 } }, + "timestamp": "2019-01-28T18:43:13.074Z", + "http": { "response": { "status_code": 301 } }, "error": null, "monitor": { - "duration": { "us": 127511 }, - "id": "auto-http-0X131221E73F825974", - "ip": "172.217.7.4", + "duration": { "us": 299586 }, + "id": "auto-http-0XD9AE729FC1C1E04A", + "ip": "151.101.249.140", "name": "", "scheme": null, "status": "up", @@ -150,13 +132,13 @@ } }, { - "timestamp": "2019-01-28T17:47:19.077Z", + "timestamp": "2019-01-28T18:43:13.074Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 287543 }, - "id": "auto-http-0X9CB71300ABD5A2A8", - "ip": "192.30.253.112", + "duration": { "us": 850870 }, + "id": "auto-http-0XDD2D4E60FD4A61C3", + "ip": "151.101.250.217", "name": "", "scheme": null, "status": "up", diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list_count.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list_count.json index f2a68a7b1bfdf..a20456c18a0e3 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list_count.json +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list_count.json @@ -3,45 +3,42 @@ "total": 9231, "pings": [ { - "timestamp": "2019-01-28T17:47:08.078Z", + "timestamp": "2019-01-28T18:43:16.078Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1430 }, + "duration": { "us": 3328 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:09.075Z", + "timestamp": "2019-01-28T18:43:15.077Z", "http": null, "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", + "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", "type": "io" }, "monitor": { - "duration": { "us": 1370 }, - "id": "auto-tcp-0X81440A68E839814C", + "duration": { "us": 3331 }, + "id": "auto-http-0X3675F89EF0612091", "ip": "127.0.0.1", "name": "", "scheme": null, "status": "down", - "type": "tcp" + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:06.077Z", + "timestamp": "2019-01-28T18:43:15.077Z", "http": null, "error": null, "monitor": { - "duration": { "us": 1452 }, + "duration": { "us": 3292 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", @@ -51,98 +48,83 @@ } }, { - "timestamp": "2019-01-28T17:47:07.075Z", - "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:15.077Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 1094 }, - "id": "auto-tcp-0X81440A68E839814C", - "ip": "127.0.0.1", + "duration": { "us": 118727 }, + "id": "auto-http-0X970CBD2F2102BFA8", + "ip": "172.217.12.132", "name": "", "scheme": null, - "status": "down", - "type": "tcp" + "status": "up", + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:07.074Z", - "http": null, - "error": { - "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:15.077Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 1597 }, - "id": "auto-http-0X3675F89EF0612091", - "ip": "127.0.0.1", + "duration": { "us": 132169 }, + "id": "auto-http-0X131221E73F825974", + "ip": "172.217.12.132", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "http" } }, { - "timestamp": "2019-01-28T17:47:18.080Z", - "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:15.077Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 1699 }, - "id": "auto-tcp-0X81440A68E839814C", - "ip": "127.0.0.1", + "duration": { "us": 247244 }, + "id": "auto-http-0X9CB71300ABD5A2A8", + "ip": "192.30.253.112", "name": "", "scheme": null, - "status": "down", - "type": "tcp" + "status": "up", + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:19.076Z", + "timestamp": "2019-01-28T18:43:14.080Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 5384 }, + "duration": { "us": 2080 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:19.076Z", + "timestamp": "2019-01-28T18:43:13.075Z", "http": null, - "error": { - "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 5397 }, - "id": "auto-http-0X3675F89EF0612091", + "duration": { "us": 1921 }, + "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", - "type": "http" + "status": "up", + "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:19.077Z", - "http": { "response": { "status_code": 200 } }, + "timestamp": "2019-01-28T18:43:13.074Z", + "http": { "response": { "status_code": 301 } }, "error": null, "monitor": { - "duration": { "us": 127511 }, - "id": "auto-http-0X131221E73F825974", - "ip": "172.217.7.4", + "duration": { "us": 299586 }, + "id": "auto-http-0XD9AE729FC1C1E04A", + "ip": "151.101.249.140", "name": "", "scheme": null, "status": "up", @@ -150,13 +132,13 @@ } }, { - "timestamp": "2019-01-28T17:47:19.077Z", + "timestamp": "2019-01-28T18:43:13.074Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 287543 }, - "id": "auto-http-0X9CB71300ABD5A2A8", - "ip": "192.30.253.112", + "duration": { "us": 850870 }, + "id": "auto-http-0XDD2D4E60FD4A61C3", + "ip": "151.101.250.217", "name": "", "scheme": null, "status": "up", @@ -164,58 +146,58 @@ } }, { - "timestamp": "2019-01-28T17:47:19.076Z", - "http": { "response": { "status_code": 301 } }, + "timestamp": "2019-01-28T18:43:12.075Z", + "http": null, "error": null, "monitor": { - "duration": { "us": 357805 }, - "id": "auto-http-0XD9AE729FC1C1E04A", - "ip": "151.101.209.140", + "duration": { "us": 1771 }, + "id": "auto-tcp-0X81440A68E839814C", + "ip": "127.0.0.1", "name": "", "scheme": null, "status": "up", - "type": "http" + "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:19.076Z", - "http": { "response": { "status_code": 200 } }, + "timestamp": "2019-01-28T18:43:11.075Z", + "http": null, "error": null, "monitor": { - "duration": { "us": 850839 }, - "id": "auto-http-0XDD2D4E60FD4A61C3", - "ip": "151.101.250.217", + "duration": { "us": 2226 }, + "id": "auto-tcp-0X81440A68E839814C", + "ip": "127.0.0.1", "name": "", "scheme": null, "status": "up", - "type": "http" + "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:20.077Z", + "timestamp": "2019-01-28T18:43:11.074Z", "http": null, "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", + "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", "type": "io" }, "monitor": { - "duration": { "us": 2278 }, - "id": "auto-tcp-0X81440A68E839814C", + "duration": { "us": 2369 }, + "id": "auto-http-0X3675F89EF0612091", "ip": "127.0.0.1", "name": "", "scheme": null, "status": "down", - "type": "tcp" + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:20.077Z", + "timestamp": "2019-01-28T18:43:11.074Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 76702 }, - "id": "auto-http-0X970CBD2F2102BFA8", - "ip": "172.217.7.4", + "duration": { "us": 148937 }, + "id": "auto-http-0X131221E73F825974", + "ip": "172.217.12.132", "name": "", "scheme": null, "status": "up", @@ -223,146 +205,114 @@ } }, { - "timestamp": "2019-01-28T17:47:19.077Z", - "http": { "response": { "status_code": 301 } }, - "error": { "message": "received status code 301 expecting 200", "type": "validate" }, + "timestamp": "2019-01-28T18:43:11.074Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 1629848 }, - "id": "auto-http-0XA8096548ECEB85B7", - "ip": "198.71.248.67", + "duration": { "us": 235473 }, + "id": "auto-http-0X9CB71300ABD5A2A8", + "ip": "192.30.253.112", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "http" } }, { - "timestamp": "2019-01-28T17:47:21.076Z", + "timestamp": "2019-01-28T18:43:10.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, - "monitor": { - "duration": { "us": 1757 }, - "id": "auto-tcp-0X81440A68E839814C", - "ip": "127.0.0.1", - "name": "", - "scheme": null, - "status": "down", - "type": "tcp" - } - }, - { - "timestamp": "2019-01-28T17:47:22.075Z", - "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1040 }, + "duration": { "us": 1076 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:23.074Z", - "http": null, - "error": { - "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:10.074Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 4578 }, - "id": "auto-http-0X3675F89EF0612091", - "ip": "127.0.0.1", + "duration": { "us": 1032917 }, + "id": "auto-http-0X970CBD2F2102BFA8", + "ip": "172.217.12.132", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "http" } }, { - "timestamp": "2019-01-28T17:47:23.075Z", + "timestamp": "2019-01-28T18:43:09.079Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 4171 }, + "duration": { "us": 1824 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:24.077Z", + "timestamp": "2019-01-28T18:43:08.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1343 }, + "duration": { "us": 1404 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:25.075Z", + "timestamp": "2019-01-28T18:43:07.078Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 647 }, + "duration": { "us": 3353 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:26.075Z", + "timestamp": "2019-01-28T18:43:07.078Z", "http": null, "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", + "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", "type": "io" }, "monitor": { - "duration": { "us": 1227 }, - "id": "auto-tcp-0X81440A68E839814C", + "duration": { "us": 3509 }, + "id": "auto-http-0X3675F89EF0612091", "ip": "127.0.0.1", "name": "", "scheme": null, "status": "down", - "type": "tcp" + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:23.074Z", + "timestamp": "2019-01-28T18:43:07.078Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 3077816 }, + "duration": { "us": 2836762 }, "id": "auto-http-0X131221E73F825974", - "ip": "172.217.7.4", + "ip": "172.217.12.132", "name": "", "scheme": null, "status": "up", @@ -370,13 +320,13 @@ } }, { - "timestamp": "2019-01-28T17:47:25.074Z", + "timestamp": "2019-01-28T18:43:07.078Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 1090949 }, - "id": "auto-http-0X970CBD2F2102BFA8", - "ip": "172.217.7.4", + "duration": { "us": 3991372 }, + "id": "auto-http-0X9CB71300ABD5A2A8", + "ip": "192.30.253.112", "name": "", "scheme": null, "status": "up", @@ -384,13 +334,13 @@ } }, { - "timestamp": "2019-01-28T17:47:22.074Z", + "timestamp": "2019-01-28T18:43:07.078Z", "http": { "response": { "status_code": 301 } }, "error": null, "monitor": { - "duration": { "us": 4166351 }, + "duration": { "us": 4058776 }, "id": "auto-http-0XD9AE729FC1C1E04A", - "ip": "151.101.209.140", + "ip": "151.101.249.140", "name": "", "scheme": null, "status": "up", @@ -398,13 +348,13 @@ } }, { - "timestamp": "2019-01-28T17:47:23.074Z", + "timestamp": "2019-01-28T18:43:07.078Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 3286549 }, - "id": "auto-http-0X9CB71300ABD5A2A8", - "ip": "192.30.253.113", + "duration": { "us": 4274310 }, + "id": "auto-http-0XDD2D4E60FD4A61C3", + "ip": "151.101.250.217", "name": "", "scheme": null, "status": "up", @@ -412,75 +362,55 @@ } }, { - "timestamp": "2019-01-28T17:47:22.073Z", - "http": { "response": { "status_code": 200 } }, - "error": null, + "timestamp": "2019-01-28T18:43:07.078Z", + "http": { "response": { "status_code": 301 } }, + "error": { "message": "received status code 301 expecting 200", "type": "validate" }, "monitor": { - "duration": { "us": 4717236 }, - "id": "auto-http-0XDD2D4E60FD4A61C3", - "ip": "151.101.250.217", + "duration": { "us": 4751074 }, + "id": "auto-http-0XA8096548ECEB85B7", + "ip": "198.71.248.67", "name": "", "scheme": null, - "status": "up", + "status": "down", "type": "http" } }, { - "timestamp": "2019-01-28T17:47:27.075Z", + "timestamp": "2019-01-28T18:43:06.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1449 }, + "duration": { "us": 1861 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:27.074Z", + "timestamp": "2019-01-28T18:43:05.076Z", "http": null, - "error": { - "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", - "type": "io" - }, - "monitor": { - "duration": { "us": 1769 }, - "id": "auto-http-0X3675F89EF0612091", - "ip": "127.0.0.1", - "name": "", - "scheme": null, - "status": "down", - "type": "http" - } - }, - { - "timestamp": "2019-01-28T17:47:27.074Z", - "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 112937 }, - "id": "auto-http-0X131221E73F825974", - "ip": "172.217.7.4", + "duration": { "us": 2476 }, + "id": "auto-tcp-0X81440A68E839814C", + "ip": "127.0.0.1", "name": "", "scheme": null, "status": "up", - "type": "http" + "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:27.074Z", + "timestamp": "2019-01-28T18:43:05.076Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 281296 }, - "id": "auto-http-0X9CB71300ABD5A2A8", - "ip": "192.30.253.113", + "duration": { "us": 109030 }, + "id": "auto-http-0X970CBD2F2102BFA8", + "ip": "172.217.12.132", "name": "", "scheme": null, "status": "up", @@ -488,44 +418,27 @@ } }, { - "timestamp": "2019-01-28T17:47:23.074Z", - "http": { "response": { "status_code": 301 } }, - "error": { "message": "received status code 301 expecting 200", "type": "validate" }, - "monitor": { - "duration": { "us": 4414658 }, - "id": "auto-http-0XA8096548ECEB85B7", - "ip": "198.71.248.67", - "name": "", - "scheme": null, - "status": "down", - "type": "http" - } - }, - { - "timestamp": "2019-01-28T17:47:28.075Z", + "timestamp": "2019-01-28T18:43:04.077Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 780 }, + "duration": { "us": 3512 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:28.074Z", + "timestamp": "2019-01-28T18:43:04.077Z", "http": { "response": { "status_code": 301 } }, "error": null, "monitor": { - "duration": { "us": 297465 }, + "duration": { "us": 257046 }, "id": "auto-http-0XD9AE729FC1C1E04A", - "ip": "151.101.209.140", + "ip": "151.101.249.140", "name": "", "scheme": null, "status": "up", @@ -533,11 +446,11 @@ } }, { - "timestamp": "2019-01-28T17:47:28.073Z", + "timestamp": "2019-01-28T18:43:04.077Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 786082 }, + "duration": { "us": 443840 }, "id": "auto-http-0XDD2D4E60FD4A61C3", "ip": "151.101.250.217", "name": "", @@ -547,47 +460,44 @@ } }, { - "timestamp": "2019-01-28T17:47:29.078Z", + "timestamp": "2019-01-28T18:43:03.077Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1006 }, + "duration": { "us": 3158 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:30.078Z", + "timestamp": "2019-01-28T18:43:03.077Z", "http": null, "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", + "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", "type": "io" }, "monitor": { - "duration": { "us": 1572 }, - "id": "auto-tcp-0X81440A68E839814C", + "duration": { "us": 3183 }, + "id": "auto-http-0X3675F89EF0612091", "ip": "127.0.0.1", "name": "", "scheme": null, "status": "down", - "type": "tcp" + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:30.078Z", + "timestamp": "2019-01-28T18:43:03.077Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 80485 }, - "id": "auto-http-0X970CBD2F2102BFA8", - "ip": "172.217.7.4", + "duration": { "us": 213987 }, + "id": "auto-http-0X131221E73F825974", + "ip": "172.217.12.132", "name": "", "scheme": null, "status": "up", @@ -595,33 +505,27 @@ } }, { - "timestamp": "2019-01-28T17:47:31.075Z", - "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:03.077Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 3263 }, - "id": "auto-tcp-0X81440A68E839814C", - "ip": "127.0.0.1", + "duration": { "us": 263080 }, + "id": "auto-http-0X9CB71300ABD5A2A8", + "ip": "192.30.253.112", "name": "", "scheme": null, - "status": "down", - "type": "tcp" + "status": "up", + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:31.074Z", - "http": null, - "error": { - "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", - "type": "io" - }, + "timestamp": "2019-01-28T18:43:03.077Z", + "http": { "response": { "status_code": 301 } }, + "error": { "message": "received status code 301 expecting 200", "type": "validate" }, "monitor": { - "duration": { "us": 4109 }, - "id": "auto-http-0X3675F89EF0612091", - "ip": "127.0.0.1", + "duration": { "us": 1396605 }, + "id": "auto-http-0XA8096548ECEB85B7", + "ip": "198.71.248.67", "name": "", "scheme": null, "status": "down", @@ -629,41 +533,41 @@ } }, { - "timestamp": "2019-01-28T17:47:31.074Z", - "http": { "response": { "status_code": 200 } }, + "timestamp": "2019-01-28T18:43:02.080Z", + "http": null, "error": null, "monitor": { - "duration": { "us": 129148 }, - "id": "auto-http-0X131221E73F825974", - "ip": "172.217.7.4", + "duration": { "us": 1889 }, + "id": "auto-tcp-0X81440A68E839814C", + "ip": "127.0.0.1", "name": "", "scheme": null, "status": "up", - "type": "http" + "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:31.074Z", - "http": { "response": { "status_code": 200 } }, + "timestamp": "2019-01-28T18:43:01.077Z", + "http": null, "error": null, "monitor": { - "duration": { "us": 196839 }, - "id": "auto-http-0X9CB71300ABD5A2A8", - "ip": "192.30.253.113", + "duration": { "us": 3191 }, + "id": "auto-tcp-0X81440A68E839814C", + "ip": "127.0.0.1", "name": "", "scheme": null, "status": "up", - "type": "http" + "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:31.074Z", + "timestamp": "2019-01-28T18:43:01.077Z", "http": { "response": { "status_code": 301 } }, "error": null, "monitor": { - "duration": { "us": 362680 }, + "duration": { "us": 248880 }, "id": "auto-http-0XD9AE729FC1C1E04A", - "ip": "151.101.209.140", + "ip": "151.101.249.140", "name": "", "scheme": null, "status": "up", @@ -671,11 +575,11 @@ } }, { - "timestamp": "2019-01-28T17:47:31.073Z", + "timestamp": "2019-01-28T18:43:01.077Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 987186 }, + "duration": { "us": 541379 }, "id": "auto-http-0XDD2D4E60FD4A61C3", "ip": "151.101.250.217", "name": "", @@ -685,78 +589,72 @@ } }, { - "timestamp": "2019-01-28T17:47:32.076Z", + "timestamp": "2019-01-28T18:43:00.078Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1731 }, + "duration": { "us": 2449 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:31.073Z", - "http": { "response": { "status_code": 301 } }, - "error": { "message": "received status code 301 expecting 200", "type": "validate" }, + "timestamp": "2019-01-28T18:43:00.078Z", + "http": { "response": { "status_code": 200 } }, + "error": null, "monitor": { - "duration": { "us": 1512820 }, - "id": "auto-http-0XA8096548ECEB85B7", - "ip": "198.71.248.67", + "duration": { "us": 120545 }, + "id": "auto-http-0X970CBD2F2102BFA8", + "ip": "172.217.12.132", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "http" } }, { - "timestamp": "2019-01-28T17:47:33.075Z", + "timestamp": "2019-01-28T18:42:59.075Z", "http": null, "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", + "message": "Get http://localhost:12349/: dial tcp 127.0.0.1:12349: connect: connection refused", "type": "io" }, "monitor": { - "duration": { "us": 1489 }, - "id": "auto-tcp-0X81440A68E839814C", + "duration": { "us": 4736 }, + "id": "auto-http-0X3675F89EF0612091", "ip": "127.0.0.1", "name": "", "scheme": null, "status": "down", - "type": "tcp" + "type": "http" } }, { - "timestamp": "2019-01-28T17:47:34.075Z", + "timestamp": "2019-01-28T18:42:59.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 2608 }, + "duration": { "us": 4617 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:34.075Z", - "http": { "response": { "status_code": 301 } }, + "timestamp": "2019-01-28T18:42:59.075Z", + "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 317978 }, - "id": "auto-http-0XD9AE729FC1C1E04A", - "ip": "151.101.209.140", + "duration": { "us": 137745 }, + "id": "auto-http-0X131221E73F825974", + "ip": "172.217.12.132", "name": "", "scheme": null, "status": "up", @@ -764,13 +662,55 @@ } }, { - "timestamp": "2019-01-28T17:47:34.075Z", + "timestamp": "2019-01-28T18:42:59.075Z", "http": { "response": { "status_code": 200 } }, "error": null, "monitor": { - "duration": { "us": 752672 }, - "id": "auto-http-0XDD2D4E60FD4A61C3", - "ip": "151.101.250.217", + "duration": { "us": 204668 }, + "id": "auto-http-0X9CB71300ABD5A2A8", + "ip": "192.30.253.112", + "name": "", + "scheme": null, + "status": "up", + "type": "http" + } + }, + { + "timestamp": "2019-01-28T18:42:59.075Z", + "http": { "response": { "status_code": 301 } }, + "error": { "message": "received status code 301 expecting 200", "type": "validate" }, + "monitor": { + "duration": { "us": 1911427 }, + "id": "auto-http-0XA8096548ECEB85B7", + "ip": "198.71.248.67", + "name": "", + "scheme": null, + "status": "down", + "type": "http" + } + }, + { + "timestamp": "2019-01-28T18:42:58.075Z", + "http": null, + "error": null, + "monitor": { + "duration": { "us": 1945 }, + "id": "auto-tcp-0X81440A68E839814C", + "ip": "127.0.0.1", + "name": "", + "scheme": null, + "status": "up", + "type": "tcp" + } + }, + { + "timestamp": "2019-01-28T18:42:58.074Z", + "http": { "response": { "status_code": 301 } }, + "error": null, + "monitor": { + "duration": { "us": 269254 }, + "id": "auto-http-0XD9AE729FC1C1E04A", + "ip": "151.101.249.140", "name": "", "scheme": null, "status": "up", diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list_monitor_id.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list_monitor_id.json index ad6f23b5d1182..93a713bb6160f 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list_monitor_id.json +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/ping_list_monitor_id.json @@ -3,45 +3,39 @@ "total": 3371, "pings": [ { - "timestamp": "2019-01-28T17:47:08.078Z", + "timestamp": "2019-01-28T18:43:16.078Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1430 }, + "duration": { "us": 3328 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:09.075Z", + "timestamp": "2019-01-28T18:43:15.077Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1370 }, + "duration": { "us": 3292 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:06.077Z", + "timestamp": "2019-01-28T18:43:14.080Z", "http": null, "error": null, "monitor": { - "duration": { "us": 1452 }, + "duration": { "us": 2080 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", @@ -51,206 +45,170 @@ } }, { - "timestamp": "2019-01-28T17:47:07.075Z", + "timestamp": "2019-01-28T18:43:13.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1094 }, + "duration": { "us": 1921 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:18.080Z", + "timestamp": "2019-01-28T18:43:12.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1699 }, + "duration": { "us": 1771 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:19.076Z", + "timestamp": "2019-01-28T18:43:11.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 5384 }, + "duration": { "us": 2226 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:20.077Z", + "timestamp": "2019-01-28T18:43:10.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 2278 }, + "duration": { "us": 1076 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:21.076Z", + "timestamp": "2019-01-28T18:43:09.079Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1757 }, + "duration": { "us": 1824 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:22.075Z", + "timestamp": "2019-01-28T18:43:08.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1040 }, + "duration": { "us": 1404 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:23.075Z", + "timestamp": "2019-01-28T18:43:07.078Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 4171 }, + "duration": { "us": 3353 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:24.077Z", + "timestamp": "2019-01-28T18:43:06.075Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1343 }, + "duration": { "us": 1861 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:25.075Z", + "timestamp": "2019-01-28T18:43:05.076Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 647 }, + "duration": { "us": 2476 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:26.075Z", + "timestamp": "2019-01-28T18:43:04.077Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1227 }, + "duration": { "us": 3512 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:27.075Z", + "timestamp": "2019-01-28T18:43:03.077Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 1449 }, + "duration": { "us": 3158 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } }, { - "timestamp": "2019-01-28T17:47:28.075Z", + "timestamp": "2019-01-28T18:43:02.080Z", "http": null, - "error": { - "message": "dial tcp 127.0.0.1:9200: connect: connection refused", - "type": "io" - }, + "error": null, "monitor": { - "duration": { "us": 780 }, + "duration": { "us": 1889 }, "id": "auto-tcp-0X81440A68E839814C", "ip": "127.0.0.1", "name": "", "scheme": null, - "status": "down", + "status": "up", "type": "tcp" } } diff --git a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_filtered_by_up.json b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_filtered_by_up.json index c2065ff4659c9..904cf96425841 100644 --- a/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_filtered_by_up.json +++ b/x-pack/test/api_integration/apis/uptime/graphql/fixtures/snapshot_filtered_by_up.json @@ -4,10 +4,10 @@ "down": 0, "total": 8, "histogram": [ - { "upCount": 8, "downCount": 0, "x": 1548697920000, "x0": 1548697620000, "y": 1 }, + { "upCount": 7, "downCount": 0, "x": 1548697920000, "x0": 1548697620000, "y": 1 }, { "upCount": 7, "downCount": 0, "x": 1548698220000, "x0": 1548697920000, "y": 1 }, - { "upCount": 8, "downCount": 0, "x": 1548698520000, "x0": 1548698220000, "y": 1 }, - { "upCount": 8, "downCount": 0, "x": 1548698820000, "x0": 1548698520000, "y": 1 }, + { "upCount": 7, "downCount": 0, "x": 1548698520000, "x0": 1548698220000, "y": 1 }, + { "upCount": 7, "downCount": 0, "x": 1548698820000, "x0": 1548698520000, "y": 1 }, { "upCount": 8, "downCount": 0, "x": 1548699120000, "x0": 1548698820000, "y": 1 }, { "upCount": 8, "downCount": 0, "x": 1548699420000, "x0": 1548699120000, "y": 1 }, { "upCount": 8, "downCount": 0, "x": 1548699720000, "x0": 1548699420000, "y": 1 }, diff --git a/x-pack/test/functional/apps/uptime/monitor.ts b/x-pack/test/functional/apps/uptime/monitor.ts index 7e1cd40d41796..e293dbb04027b 100644 --- a/x-pack/test/functional/apps/uptime/monitor.ts +++ b/x-pack/test/functional/apps/uptime/monitor.ts @@ -20,8 +20,9 @@ export default ({ getPageObjects, getService }: KibanaFunctionalTestDefaultProvi it('loads and displays uptime data based on date range', async () => { await pageObjects.uptime.loadDataAndGoToMonitorPage( '2019-01-28 12:40:08.078', + '2019-01-29 12:40:08.078', 'auto-http-0X131221E73F825974', - 'https://www.google.com/' + 'auto-http-0X131221E73F825974' ); }); }); diff --git a/x-pack/test/functional/apps/uptime/overview.ts b/x-pack/test/functional/apps/uptime/overview.ts index 5379dd9fd68da..b4101db709b31 100644 --- a/x-pack/test/functional/apps/uptime/overview.ts +++ b/x-pack/test/functional/apps/uptime/overview.ts @@ -14,6 +14,7 @@ export default ({ getPageObjects }: KibanaFunctionalTestDefaultProviders) => { it('loads and displays uptime data based on date range', async () => { await pageObjects.uptime.goToUptimeOverviewAndLoadData( '2019-01-28 12:40:08.078', + '2019-01-29 12:40:08.078', 'monitor-page-link-auto-http-0X131221E73F825974' ); }); diff --git a/x-pack/test/functional/page_objects/uptime_page.ts b/x-pack/test/functional/page_objects/uptime_page.ts index d0ad3259247fd..85133b4dd1a5f 100644 --- a/x-pack/test/functional/page_objects/uptime_page.ts +++ b/x-pack/test/functional/page_objects/uptime_page.ts @@ -16,20 +16,22 @@ export const UptimePageProvider = ({ return new class UptimePage { public async goToUptimeOverviewAndLoadData( datePickerStartValue: string, + datePickerEndValue: string, monitorIdToCheck: string ) { await pageObjects.common.navigateToApp('uptime'); - await pageObjects.timePicker.setAbsoluteStart(datePickerStartValue); + await pageObjects.timePicker.setAbsoluteRange(datePickerStartValue, datePickerEndValue); await uptimeService.monitorIdExists(monitorIdToCheck); } public async loadDataAndGoToMonitorPage( datePickerStartValue: string, + datePickerEndValue: string, monitorId: string, monitorName: string ) { await pageObjects.common.navigateToApp('uptime'); - await pageObjects.timePicker.setAbsoluteStart(datePickerStartValue); + await pageObjects.timePicker.setAbsoluteRange(datePickerStartValue, datePickerEndValue); await uptimeService.navigateToMonitorWithId(monitorId); if ((await uptimeService.getMonitorNameDisplayedOnPageTitle()) !== monitorName) { throw new Error('Expected monitor name not found');