[8.8] [Synthetics] Show error step as active if it is the most recent step (#156568) (#156882)

# Backport

This will backport the following commits from `main` to `8.8`:
- [[Synthetics] Show error step as active if it is the most recent step
(#156568)](https://github.com/elastic/kibana/pull/156568)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Justin
Kambic","email":"jk@elastic.co"},"sourceCommit":{"committedDate":"2023-05-05T15:46:30Z","message":"[Synthetics]
Show error step as active if it is the most recent step
(#156568)\n\nCo-authored-by: Shahzad
<shahzad31comp@gmail.com>","sha":"49e521233f4da205d2a559d7701e4ccc1a2e8a07","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","Team:uptime","release_note:skip","v8.8.0","v8.9.0"],"number":156568,"url":"https://github.com/elastic/kibana/pull/156568","mergeCommit":{"message":"[Synthetics]
Show error step as active if it is the most recent step
(#156568)\n\nCo-authored-by: Shahzad
<shahzad31comp@gmail.com>","sha":"49e521233f4da205d2a559d7701e4ccc1a2e8a07"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"8.8","label":"v8.8.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/156568","number":156568,"mergeCommit":{"message":"[Synthetics]
Show error step as active if it is the most recent step
(#156568)\n\nCo-authored-by: Shahzad
<shahzad31comp@gmail.com>","sha":"49e521233f4da205d2a559d7701e4ccc1a2e8a07"}}]}]
BACKPORT-->

Co-authored-by: Justin Kambic <jk@elastic.co>
This commit is contained in:
Kibana Machine 2023-05-05 12:54:10 -04:00 committed by GitHub
parent 0ccbf5acf7
commit 55344bb14d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 93 additions and 18 deletions

View file

@ -0,0 +1,65 @@
/*
* 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 * as useMonitorErrors from '../hooks/use_monitor_errors';
import { isErrorActive } from './errors_list';
describe('isErrorActive', () => {
let isActiveSpy: jest.SpyInstance;
beforeEach(() => {
isActiveSpy = jest.spyOn(useMonitorErrors, 'isActiveState').mockReturnValue(true);
});
const item = {
'@timestamp': '2023-05-04T00:00:00.000Z',
timestamp: '2023-05-04T00:00:00.000Z',
docId: 'SGIQ6IcBTfgfaiALCdZ8',
error: { message: 'Encountered an error and made this unhelpful message.' },
state: {
duration_ms: '415801',
checks: 8,
ends: null,
started_at: '2023-05-04T18:32:41.111671462Z',
id: 'foo',
up: 8,
down: 0,
status: 'up',
},
monitor: {
id: 'foo',
status: 'up',
type: 'browser',
check_group: 'f01850cc-eaaa-11ed-887d-caddd792d648',
timespan: { gte: '2023-05-04T00:00:00.000Z', lt: '2023-05-04T01:00:00.000Z' },
},
};
const lastErrorId = 'foo';
const latestPingStatus = 'down';
it('returns true if error is active', () => {
const result = isErrorActive(item, lastErrorId, latestPingStatus);
expect(result).toBe(true);
});
it('returns false if error is not active', () => {
isActiveSpy.mockReturnValue(false);
expect(
isErrorActive(
{ ...item, '@timestamp': '2023-05-04T02:00:00.000Z' },
lastErrorId,
latestPingStatus
)
).toBe(false);
});
it('returns false if `lastErrorId` does not match `item.state.id`', () => {
expect(isErrorActive(item, 'bar', latestPingStatus)).toBe(false);
});
it('returns false if latestPingStatus is `up`', () => {
expect(isErrorActive(item, lastErrorId, 'up')).toBe(false);
});
});

View file

@ -23,12 +23,19 @@ import { useSelectedLocation } from '../hooks/use_selected_location';
import { Ping, PingState } from '../../../../../../common/runtime_types';
import { useErrorFailedStep } from '../hooks/use_error_failed_step';
import { isActiveState } from '../hooks/use_monitor_errors';
import { useMonitorLatestPing } from '../hooks/use_monitor_latest_ping';
import {
formatTestDuration,
formatTestRunAt,
useDateFormatForTest,
} from '../../../utils/monitor_test_result/test_time_formats';
export function isErrorActive(item: PingState, lastErrorId?: string, latestPingStatus?: string) {
// if the error is the most recent, `isActiveState`, and the monitor
// is not yet back up, label the error as active
return isActiveState(item) && lastErrorId === item.state.id && latestPingStatus !== 'up';
}
export const ErrorsList = ({
errorStates,
loading,
@ -54,7 +61,12 @@ export const ErrorsList = ({
const selectedLocation = location;
const lastTestRun = errorStates?.sort((a, b) => {
const { latestPing } = useMonitorLatestPing({
monitorId: configId,
locationLabel: selectedLocation?.label,
});
const lastErrorTestRun = errorStates?.sort((a, b) => {
return moment(b.state.started_at).valueOf() - moment(a.state.started_at).valueOf();
})?.[0];
@ -67,7 +79,7 @@ export const ErrorsList = ({
sortable: (a: PingState) => {
return moment(a.state.started_at).valueOf();
},
render: (value: string, item: PingState) => {
render: (_value: string, item: PingState) => {
const link = (
<ErrorDetailsLink
configId={configId}
@ -76,23 +88,21 @@ export const ErrorsList = ({
locationId={selectedLocation?.id}
/>
);
const isActive = isActiveState(item);
if (!isActive || lastTestRun.state.id !== item.state.id) {
return link;
if (isErrorActive(item, lastErrorTestRun?.state.id, latestPing?.monitor.status)) {
return (
<EuiFlexGroup gutterSize="m" alignItems="center" wrap={true}>
<EuiFlexItem grow={false} className="eui-textNoWrap">
{link}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiBadge iconType="clock" iconSide="right" css={{ maxWidth: 'max-content' }}>
{ACTIVE_LABEL}
</EuiBadge>
</EuiFlexItem>
</EuiFlexGroup>
);
}
return (
<EuiFlexGroup gutterSize="m" alignItems="center" wrap={true}>
<EuiFlexItem grow={false} className="eui-textNoWrap">
{link}
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiBadge iconType="clock" iconSide="right" css={{ maxWidth: 'max-content' }}>
{ACTIVE_LABEL}
</EuiBadge>
</EuiFlexItem>
</EuiFlexGroup>
);
return link;
},
mobileOptions: {
header: false,