diff --git a/x-pack/plugins/observability/e2e/journeys/step_duration.journey.ts b/x-pack/plugins/observability/e2e/journeys/step_duration.journey.ts index 06e2351c16950..1e24fbb120f53 100644 --- a/x-pack/plugins/observability/e2e/journeys/step_duration.journey.ts +++ b/x-pack/plugins/observability/e2e/journeys/step_duration.journey.ts @@ -6,6 +6,7 @@ */ import { journey, step, before, after } from '@elastic/synthetics'; +import moment from 'moment'; import { recordVideo } from '../record_video'; import { createExploratoryViewUrl } from '../../public/components/shared/exploratory_view/configurations/exploratory_view_url'; import { loginToKibana, TIMEOUT_60_SEC, waitForLoadingToFinish } from '../utils'; @@ -28,8 +29,8 @@ journey('Exploratory view', async ({ page, params }) => { { dataType: 'synthetics', time: { - from: 'now-10y', - to: 'now', + from: moment().subtract(10, 'y').toISOString(), + to: moment().toISOString(), }, name: 'synthetics-series-1', breakdown: 'monitor.type', diff --git a/x-pack/plugins/observability/public/components/shared/exploratory_view/lens_embeddable.tsx b/x-pack/plugins/observability/public/components/shared/exploratory_view/lens_embeddable.tsx index e9311b03da7c9..833085e314a9d 100644 --- a/x-pack/plugins/observability/public/components/shared/exploratory_view/lens_embeddable.tsx +++ b/x-pack/plugins/observability/public/components/shared/exploratory_view/lens_embeddable.tsx @@ -22,6 +22,9 @@ interface Props { lensAttributes: TypedLensByValueInput['attributes']; setChartTimeRangeContext: Dispatch>; } +const EXECUTION_CONTEXT = { + type: 'observability_exploratory_view', +}; export function LensEmbeddable(props: Props) { const { lensAttributes, setChartTimeRangeContext } = props; @@ -92,9 +95,7 @@ export function LensEmbeddable(props: Props) { attributes={lensAttributes} onLoad={onLensLoad} onBrushEnd={onBrushEnd} - executionContext={{ - type: 'observability_exploratory_view', - }} + executionContext={EXECUTION_CONTEXT} /> {isSaveOpen && lensAttributes && ( { @@ -106,7 +108,7 @@ export const useEsSearch = , + data: rawResponse as ESSearchResponse, loading: Boolean(loading), }; }; diff --git a/x-pack/plugins/synthetics/e2e/page_objects/synthetics/synthetics_app.tsx b/x-pack/plugins/synthetics/e2e/page_objects/synthetics/synthetics_app.tsx index f9e57b952961c..a41dea3b617d4 100644 --- a/x-pack/plugins/synthetics/e2e/page_objects/synthetics/synthetics_app.tsx +++ b/x-pack/plugins/synthetics/e2e/page_objects/synthetics/synthetics_app.tsx @@ -89,15 +89,9 @@ export function syntheticsAppPageProvider({ page, kibanaUrl }: { page: Page; kib }, async navigateToAddMonitor() { - if (await page.isVisible('text=select a different monitor type', { timeout: 0 })) { - await page.click('text=select a different monitor type'); - } else if (await page.isVisible('text=Create monitor', { timeout: 0 })) { - await page.click('text=Create monitor'); - } else { - await page.goto(addMonitor, { - waitUntil: 'networkidle', - }); - } + await page.goto(addMonitor, { + waitUntil: 'networkidle', + }); }, async ensureIsOnMonitorConfigPage() { diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_failed_tests_by_step.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_failed_tests_by_step.tsx new file mode 100644 index 0000000000000..5997d7969bc9f --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/hooks/use_failed_tests_by_step.tsx @@ -0,0 +1,92 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { useEsSearch } from '@kbn/observability-plugin/public'; +import { useParams } from 'react-router-dom'; +import { useMemo } from 'react'; +import { createEsQuery } from '../../../../../../common/utils/es_search'; +import { Ping } from '../../../../../../common/runtime_types'; +import { STEP_END_FILTER } from '../../../../../../common/constants/data_filters'; +import { SYNTHETICS_INDEX_PATTERN } from '../../../../../../common/constants'; +import { useSyntheticsRefreshContext } from '../../../contexts'; + +export function useFailedTestByStep({ to, from }: { to: string; from: string }) { + const { lastRefresh } = useSyntheticsRefreshContext(); + + const { monitorId } = useParams<{ monitorId: string }>(); + + const params = createEsQuery({ + index: SYNTHETICS_INDEX_PATTERN, + body: { + size: 0, + track_total_hits: true, + query: { + bool: { + filter: [ + { + range: { + '@timestamp': { + lte: to, + gte: from, + }, + }, + }, + STEP_END_FILTER, + { + term: { + 'synthetics.step.status': 'failed', + }, + }, + { + term: { + config_id: monitorId, + }, + }, + ], + }, + }, + aggs: { + steps: { + terms: { + field: 'synthetics.step.name.keyword', + size: 1000, + }, + aggs: { + doc: { + top_hits: { + size: 1, + }, + }, + }, + }, + }, + }, + }); + + const { data, loading } = useEsSearch(params, [lastRefresh, monitorId], { + name: `getFailedTestsByStep/${monitorId}`, + }); + + return useMemo(() => { + const total = data?.hits.total.value; + + const failedSteps = data?.aggregations?.steps.buckets.map(({ key, doc_count: count, doc }) => { + const index = doc.hits.hits?.[0]._source?.synthetics?.step?.index; + return { + index, + count, + name: key, + percent: (count / total) * 100, + }; + }); + + return { + failedSteps, + loading, + }; + }, [data, loading]); +} diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_list.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_list.tsx index 7533b7307d616..bcba2d7dd27b7 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_list.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_list.tsx @@ -19,12 +19,12 @@ import { useHistory, useParams } from 'react-router-dom'; import moment from 'moment'; import { ErrorDetailsLink } from '../../common/links/error_details_link'; import { useSelectedLocation } from '../hooks/use_selected_location'; -import { useKibanaDateFormat } from '../../../../../hooks/use_kibana_date_format'; import { Ping, PingState } from '../../../../../../common/runtime_types'; import { useErrorFailedStep } from '../hooks/use_error_failed_step'; import { formatTestDuration, formatTestRunAt, + useDateFormatForTest, } from '../../../utils/monitor_test_result/test_time_formats'; export const ErrorsList = ({ @@ -46,7 +46,7 @@ export const ErrorsList = ({ const history = useHistory(); - const format = useKibanaDateFormat(); + const format = useDateFormatForTest(); const selectedLocation = useSelectedLocation(); diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_tab_content.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_tab_content.tsx index d7b1c3357f606..87077c11eb5db 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_tab_content.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/errors_tab_content.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FailedTestsByStep } from './failed_tests_by_step'; import { PingState } from '../../../../../../common/runtime_types'; import { PanelWithTitle } from '../../common/components/panel_with_title'; import { MonitorErrorsCount } from '../monitor_summary/monitor_errors_count'; @@ -61,7 +62,9 @@ export const ErrorsTabContent = ({ - + + + diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_by_step.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_by_step.tsx new file mode 100644 index 0000000000000..3f5b278fd3927 --- /dev/null +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/monitor_details/monitor_errors/failed_tests_by_step.tsx @@ -0,0 +1,47 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import React, { Fragment } from 'react'; +import { EuiProgress, EuiSpacer, EuiLoadingContent } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { useFailedTestByStep } from '../hooks/use_failed_tests_by_step'; + +export const FailedTestsByStep = ({ time }: { time: { to: string; from: string } }) => { + const { failedSteps, loading } = useFailedTestByStep(time); + + if (loading && !failedSteps) { + return ; + } + + return ( + <> + +
+ {failedSteps?.map((item) => ( + + + {i18n.translate('xpack.synthetics.monitorDetails.summary.failedTests.count', { + defaultMessage: 'Failed {count}', + values: { count: item.count }, + })} + + } + max={100} + color="danger" + size="l" + value={item.percent} + label={`${item.index}. ${item.name}`} + /> + + + ))} +
+ + ); +}; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/utils/monitor_test_result/test_time_formats.ts b/x-pack/plugins/synthetics/public/apps/synthetics/utils/monitor_test_result/test_time_formats.ts index 09404a75e5906..fcf07f1cf8714 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/utils/monitor_test_result/test_time_formats.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/utils/monitor_test_result/test_time_formats.ts @@ -36,13 +36,20 @@ export function formatTestRunAt(timestamp: string, format: string) { return stampedMoment.format(format); } -export function useFormatTestRunAt(timestamp?: string) { +export function useDateFormatForTest() { let format = useKibanaDateFormat(); - if (!timestamp) { - return ''; - } + if (format.endsWith('.SSS')) { format = format.replace('.SSS', ''); } + return format; +} + +export function useFormatTestRunAt(timestamp?: string) { + const format = useDateFormatForTest(); + + if (!timestamp) { + return ''; + } return formatTestRunAt(timestamp, format); } diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/test_now_mode/browser/browser_test_results.test.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/test_now_mode/browser/browser_test_results.test.tsx index 2a31d54097d5f..6b66fbb68cc3e 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/test_now_mode/browser/browser_test_results.test.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/test_now_mode/browser/browser_test_results.test.tsx @@ -58,7 +58,7 @@ describe('BrowserTestRunResult', function () { size: 1000, }, }, - {} + { legacyHitsTotal: false } ); }); diff --git a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/test_now_mode/simple/simple_test_results.test.tsx b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/test_now_mode/simple/simple_test_results.test.tsx index c0bab63b1c11d..44441513e2a11 100644 --- a/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/test_now_mode/simple/simple_test_results.test.tsx +++ b/x-pack/plugins/synthetics/public/legacy_uptime/components/monitor_management/test_now_mode/simple/simple_test_results.test.tsx @@ -43,7 +43,7 @@ describe('SimpleTestResults', function () { size: 1000, }, }, - {} + { legacyHitsTotal: false } ); }); diff --git a/x-pack/plugins/ux/e2e/journeys/utils.ts b/x-pack/plugins/ux/e2e/journeys/utils.ts index f8773834ea54b..9370a9441b0cd 100644 --- a/x-pack/plugins/ux/e2e/journeys/utils.ts +++ b/x-pack/plugins/ux/e2e/journeys/utils.ts @@ -8,11 +8,14 @@ import { expect, Page } from '@elastic/synthetics'; export async function waitForLoadingToFinish({ page }: { page: Page }) { - while (true) { + let retries = 50; + while (retries) { + retries--; if ((await page.$(byTestId('kbnLoadingMessage'))) === null) break; await page.waitForTimeout(2 * 1000); } - while (true) { + retries = 50; + while (retries) { if ((await page.$(byTestId('globalLoadingIndicator'))) === null) break; await page.waitForTimeout(2 * 1000); } diff --git a/x-pack/plugins/ux/public/hooks/use_client_metrics_query.ts b/x-pack/plugins/ux/public/hooks/use_client_metrics_query.ts index 9ad7af4eb360a..f92b0d9e0d167 100644 --- a/x-pack/plugins/ux/public/hooks/use_client_metrics_query.ts +++ b/x-pack/plugins/ux/public/hooks/use_client_metrics_query.ts @@ -48,7 +48,7 @@ export function useClientMetricsQuery() { const backendValue = backEnd.values[pkey] ?? 0; return { - pageViews: { value: (esQueryResponse.hits.total as any as number) ?? 0 }, + pageViews: { value: esQueryResponse.hits.total.value ?? 0 }, totalPageLoadDuration: { value: totalPageLoadDurationValueMs }, backEnd: { value: backendValue }, frontEnd: { value: totalPageLoadDurationValueMs - backendValue }, diff --git a/x-pack/plugins/ux/public/hooks/use_js_errors_query.tsx b/x-pack/plugins/ux/public/hooks/use_js_errors_query.tsx index b6ae1debb0c43..42cb153b59487 100644 --- a/x-pack/plugins/ux/public/hooks/use_js_errors_query.tsx +++ b/x-pack/plugins/ux/public/hooks/use_js_errors_query.tsx @@ -63,9 +63,9 @@ export function useJsErrorsQuery(pagination: { return { totalErrorPages: totalErrorPages?.value ?? 0, - totalErrors: esQueryResponse.hits.total ?? 0, + totalErrors: esQueryResponse.hits.total.value ?? 0, totalErrorGroups: totalErrorGroups?.value ?? 0, - items: errors?.buckets.map(({ sample, key, impactedPages }: any) => { + items: errors?.buckets.map(({ sample, key, impactedPages }) => { return { count: impactedPages.pageCount.value, errorGroupId: key, diff --git a/x-pack/plugins/ux/public/services/data/has_rum_data_query.ts b/x-pack/plugins/ux/public/services/data/has_rum_data_query.ts index f2ee851cb0f3b..91710cecf0c88 100644 --- a/x-pack/plugins/ux/public/services/data/has_rum_data_query.ts +++ b/x-pack/plugins/ux/public/services/data/has_rum_data_query.ts @@ -22,8 +22,7 @@ export function formatHasRumResult( if (!esResult) return esResult; return { indices, - // @ts-ignore total.value is undefined by the returned type, total is a `number` - hasData: esResult.hits.total > 0, + hasData: esResult.hits.total.value > 0, serviceName: esResult.aggregations?.services?.mostTraffic?.buckets?.[0]?.key, };