[Synthetics] Monitor error overview page (#149503)

Fixes https://github.com/elastic/kibana/issues/145375
This commit is contained in:
Shahzad 2023-01-26 10:11:09 +01:00 committed by GitHub
parent f838a30c5a
commit 4e3b0a4a0e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 111 additions and 65 deletions

View file

@ -0,0 +1,17 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
export const CLIENT_DEFAULTS_SYNTHETICS = {
/**
* The beginning of the default date range is 15m ago.
*/
DATE_RANGE_START: 'now-24h',
/**
* The end of the default date range is now.
*/
DATE_RANGE_END: 'now',
};

View file

@ -21,7 +21,7 @@ describe('SyntheticsDatePicker component', () => {
it('renders properly with mock data', async () => {
const { findByText } = render(<SyntheticsDatePicker />);
expect(await findByText('Last 15 minutes')).toBeInTheDocument();
expect(await findByText('Last 24 hours')).toBeInTheDocument();
expect(await findByText('Refresh')).toBeInTheDocument();
});

View file

@ -14,7 +14,7 @@ describe('ActionMenuContent', () => {
const { getByRole, getByText } = render(<ActionMenuContent />);
const settingsAnchor = getByRole('link', { name: 'Navigate to the Uptime settings page' });
expect(settingsAnchor.getAttribute('href')).toBe('/settings');
expect(settingsAnchor.getAttribute('href')).toBe('/settings?dateRangeStart=now-24h');
expect(getByText('Settings'));
});

View file

@ -35,7 +35,7 @@ export const ErrorsTabContent = ({
<>
<EuiFlexGroup gutterSize="m">
<EuiFlexItem grow={1}>
<PanelWithTitle title={OVERVIEW_LABEL}>
<PanelWithTitle title={OVERVIEW_LABEL} titleLeftAlign>
<EuiFlexGroup>
<EuiFlexItem>
{monitorId && (
@ -61,11 +61,7 @@ export const ErrorsTabContent = ({
<ErrorsList errorStates={errorStates} loading={loading} />
</PanelWithTitle>
</EuiFlexItem>
<EuiFlexItem grow={1}>
<PanelWithTitle title={FAILED_TESTS_BY_STEPS_LABEL}>
<FailedTestsByStep time={time} />
</PanelWithTitle>
</EuiFlexItem>
<FailedTestsByStep time={time} />
</EuiFlexGroup>
</>
);
@ -82,7 +78,3 @@ const OVERVIEW_LABEL = i18n.translate('xpack.synthetics.errors.overview', {
const FAILED_TESTS_LABEL = i18n.translate('xpack.synthetics.errors.failedTests', {
defaultMessage: 'Failed tests',
});
const FAILED_TESTS_BY_STEPS_LABEL = i18n.translate('xpack.synthetics.errors.failedTests.byStep', {
defaultMessage: 'Failed tests by step',
});

View file

@ -9,6 +9,9 @@ import React from 'react';
import { useKibana } from '@kbn/kibana-react-plugin/public';
import { useParams } from 'react-router-dom';
import { i18n } from '@kbn/i18n';
import moment from 'moment';
import { EuiFlexGroup, EuiFlexItem, EuiHealth, EuiText } from '@elastic/eui';
import { useUrlParams } from '../../../hooks';
import { useMonitorQueryId } from '../hooks/use_monitor_query_id';
import { ClientPluginsStart } from '../../../../../plugin';
@ -21,28 +24,48 @@ export const MonitorFailedTests = ({ time }: { time: { to: string; from: string
const { errorStateId } = useParams<{ errorStateId: string }>();
const [, updateUrl] = useUrlParams();
if (!monitorId && !errorStateId) {
return null;
}
return (
<ExploratoryViewEmbeddable
customHeight={'120px'}
reportType="heatmap"
axisTitlesVisibility={{ x: false, yRight: false, yLeft: false }}
legendIsVisible={false}
attributes={[
{
time,
reportDefinitions: {
...(monitorId ? { 'monitor.id': [monitorId] } : { 'state.id': [errorStateId] }),
<>
<ExploratoryViewEmbeddable
customHeight={'120px'}
reportType="heatmap"
axisTitlesVisibility={{ x: false, yRight: false, yLeft: false }}
legendIsVisible={false}
attributes={[
{
time,
reportDefinitions: {
...(monitorId ? { 'monitor.id': [monitorId] } : { 'state.id': [errorStateId] }),
},
dataType: 'synthetics',
selectedMetricField: 'failed_tests',
name: FAILED_TESTS_LABEL,
},
dataType: 'synthetics',
selectedMetricField: 'failed_tests',
name: FAILED_TESTS_LABEL,
},
]}
/>
]}
onBrushEnd={({ range }) => {
updateUrl({
dateRangeStart: moment(range[0]).toISOString(),
dateRangeEnd: moment(range[1]).toISOString(),
});
}}
/>
<EuiFlexGroup>
<EuiFlexItem grow style={{ marginLeft: 10 }}>
<EuiHealth color="danger">{FAILED_TESTS_LABEL}</EuiHealth>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiText color="subdued" size="s">
{BRUSH_LABEL}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
</>
);
};
@ -52,3 +75,7 @@ export const FAILED_TESTS_LABEL = i18n.translate(
defaultMessage: 'Failed tests',
}
);
export const BRUSH_LABEL = i18n.translate('xpack.synthetics.monitorDetails.summary.brushArea', {
defaultMessage: 'Brush an area for higher fidelity',
});

View file

@ -6,42 +6,56 @@
*/
import React, { Fragment } from 'react';
import { EuiProgress, EuiSpacer, EuiLoadingContent } from '@elastic/eui';
import { EuiProgress, EuiSpacer, EuiFlexItem, EuiLoadingContent } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { PanelWithTitle } from '../../common/components/panel_with_title';
import { useSelectedMonitor } from '../hooks/use_selected_monitor';
import { useFailedTestByStep } from '../hooks/use_failed_tests_by_step';
export const FailedTestsByStep = ({ time }: { time: { to: string; from: string } }) => {
const { failedSteps, loading } = useFailedTestByStep(time);
const { monitor } = useSelectedMonitor();
if (monitor?.type !== 'browser') {
return null;
}
if (loading && !failedSteps) {
return <EuiLoadingContent lines={3} />;
}
return (
<>
<EuiSpacer size="m" />
<div>
{failedSteps?.map((item) => (
<Fragment key={item.name}>
<EuiProgress
valueText={
<span>
{i18n.translate('xpack.synthetics.monitorDetails.summary.failedTests.count', {
defaultMessage: 'Failed {count}',
values: { count: item.count },
})}
</span>
}
max={100}
color="danger"
size="l"
value={item.percent}
label={`${item.index}. ${item.name}`}
/>
<EuiSpacer size="s" />
</Fragment>
))}
</div>
</>
<EuiFlexItem grow={1}>
<PanelWithTitle title={FAILED_TESTS_BY_STEPS_LABEL}>
<EuiSpacer size="m" />
<div>
{failedSteps?.map((item) => (
<Fragment key={item.name}>
<EuiProgress
valueText={
<span>
{i18n.translate('xpack.synthetics.monitorDetails.summary.failedTests.count', {
defaultMessage: 'Failed {count}',
values: { count: item.count },
})}
</span>
}
max={100}
color="danger"
size="l"
value={item.percent}
label={`${item.index}. ${item.name}`}
/>
<EuiSpacer size="s" />
</Fragment>
))}
</div>
</PanelWithTitle>
</EuiFlexItem>
);
};
const FAILED_TESTS_BY_STEPS_LABEL = i18n.translate('xpack.synthetics.errors.failedTests.byStep', {
defaultMessage: 'Failed tests by step',
});

View file

@ -8,6 +8,7 @@
import DateMath from '@kbn/datemath';
import { getSupportedUrlParams } from './get_supported_url_params';
import { CLIENT_DEFAULTS } from '../../../../../common/constants';
import { CLIENT_DEFAULTS_SYNTHETICS } from '../../../../../common/constants/synthetics/client_defaults';
describe('getSupportedUrlParams', () => {
let dateMathSpy: any;
@ -51,15 +52,9 @@ describe('getSupportedUrlParams', () => {
});
it('returns default values', () => {
const {
AUTOREFRESH_INTERVAL,
AUTOREFRESH_IS_PAUSED,
DATE_RANGE_START,
DATE_RANGE_END,
FILTERS,
SEARCH,
STATUS_FILTER,
} = CLIENT_DEFAULTS;
const { AUTOREFRESH_INTERVAL, AUTOREFRESH_IS_PAUSED, FILTERS, SEARCH, STATUS_FILTER } =
CLIENT_DEFAULTS;
const { DATE_RANGE_START, DATE_RANGE_END } = CLIENT_DEFAULTS_SYNTHETICS;
const result = getSupportedUrlParams({});
expect(result).toEqual({
absoluteDateRangeStart: MOCK_DATE_VALUE,

View file

@ -5,6 +5,7 @@
* 2.0.
*/
import { CLIENT_DEFAULTS_SYNTHETICS } from '../../../../../common/constants/synthetics/client_defaults';
import { parseIsPaused } from './parse_is_paused';
import { parseUrlInt } from './parse_url_int';
import { CLIENT_DEFAULTS } from '../../../../../common/constants';
@ -37,13 +38,13 @@ const {
ABSOLUTE_DATE_RANGE_END,
AUTOREFRESH_INTERVAL,
AUTOREFRESH_IS_PAUSED,
DATE_RANGE_START,
DATE_RANGE_END,
SEARCH,
FILTERS,
STATUS_FILTER,
} = CLIENT_DEFAULTS;
const { DATE_RANGE_START, DATE_RANGE_END } = CLIENT_DEFAULTS_SYNTHETICS;
/**
* Gets the current URL values for the application. If no item is present
* for the URL, a default value is supplied.