mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Synthetics] Monitor error overview page (#149503)
Fixes https://github.com/elastic/kibana/issues/145375
This commit is contained in:
parent
f838a30c5a
commit
4e3b0a4a0e
8 changed files with 111 additions and 65 deletions
|
@ -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',
|
||||
};
|
|
@ -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();
|
||||
});
|
||||
|
||||
|
|
|
@ -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'));
|
||||
});
|
||||
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
|
|
|
@ -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',
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue