Skip to content

Commit

Permalink
[Uptime] Show troubleshoot guide on missing monitors (#128527)
Browse files Browse the repository at this point in the history
  • Loading branch information
shahzad31 authored Apr 4, 2022
1 parent cab5277 commit e05b216
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
Ping,
MonitorSummary,
} from '../../../../common/runtime_types';
import { MonitorListComponent, noItemsMessage } from './monitor_list';
import { MonitorListComponent } from './monitor_list';
import moment from 'moment';
import { IHttpFetchError, ResponseErrorBody } from '../../../../../../../src/core/public';
import { mockMoment } from '../../../lib/helper/test_helpers';
Expand Down Expand Up @@ -294,24 +294,4 @@ describe('MonitorList component', () => {
});
});
});

describe('noItemsMessage', () => {
it('returns loading message while loading', () => {
expect(noItemsMessage(true)).toEqual(`Loading...`);
});

it('returns loading message when filters are defined and loading', () => {
expect(noItemsMessage(true, 'filters')).toEqual(`Loading...`);
});

it('returns no monitors selected when filters are defined and not loading', () => {
expect(noItemsMessage(false, 'filters')).toEqual(
`No monitors found for selected filter criteria`
);
});

it('returns no data message when no filters and not loading', () => {
expect(noItemsMessage(false)).toEqual(`No uptime monitors found`);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { MonitorTags } from '../../common/monitor_tags';
import { useMonitorHistogram } from './use_monitor_histogram';
import { euiStyled } from '../../../../../../../src/plugins/kibana_react/common';
import { TestNowColumn } from './columns/test_now_col';
import { NoItemsMessage } from './no_items_message';

interface Props extends MonitorListProps {
pageSize: number;
Expand All @@ -46,11 +47,6 @@ interface Props extends MonitorListProps {
refreshedMonitorIds: string[];
}

export const noItemsMessage = (loading: boolean, filters?: string) => {
if (loading) return labels.LOADING;
return !!filters ? labels.NO_MONITOR_ITEM_SELECTED : labels.NO_DATA_MESSAGE;
};

export const MonitorListComponent: ({
filters,
monitorList: { list, error, loading },
Expand Down Expand Up @@ -252,7 +248,7 @@ export const MonitorListComponent: ({
itemId="monitor_id"
itemIdToExpandedRowMap={getExpandedRowMap()}
items={items}
noItemsMessage={noItemsMessage(loading, filters)}
noItemsMessage={<NoItemsMessage loading={loading} filters={filters} />}
columns={columns}
tableLayout={'auto'}
rowProps={
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* 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 from 'react';
import { screen } from '@testing-library/react';
import { render } from '../../../lib/helper/rtl_helpers';
import { NoItemsMessage } from './no_items_message';

describe('NoItemsMessage', () => {
it('returns loading message while loading', () => {
render(<NoItemsMessage loading />);

expect(screen.getByText('Loading...')).toBeInTheDocument();
});

it('returns loading message when filters are defined and loading', () => {
render(<NoItemsMessage loading filters={'es'} />);

expect(screen.getByText('Loading...')).toBeInTheDocument();
});

it('returns no monitors selected when filters are defined and not loading', () => {
render(<NoItemsMessage loading={false} filters={'es'} />);

expect(screen.getByText('No monitors found for selected filter criteria')).toBeInTheDocument();
});

it('returns no data message when no filters and not loading', () => {
render(<NoItemsMessage loading={false} filters={''} />);

expect(screen.getByText('No uptime monitors found')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/*
* 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 from 'react';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { useSelector } from 'react-redux';
import * as labels from './translations';
import { useGetUrlParams } from '../../../hooks';
import { selectPingHistogram } from '../../../state/selectors';
import { TroubleshootPopover } from './troubleshoot_popover';

export const NoItemsMessage = ({ loading, filters }: { loading: boolean; filters?: string }) => {
const { statusFilter } = useGetUrlParams();

const { pingHistogram } = useSelector(selectPingHistogram);

const hasPingsData = pingHistogram?.histogram && pingHistogram.histogram.length > 0;

const clockSyncError = hasPingsData && !statusFilter ? <TroubleshootPopover /> : null;

if (loading) {
return <> {labels.LOADING}</>;
}

if (filters) {
return (
<>
<EuiFlexGroup alignItems="center" gutterSize="xs">
<EuiFlexItem grow={false}>{labels.NO_MONITOR_ITEM_SELECTED}</EuiFlexItem>
<EuiFlexItem grow={false}>{clockSyncError}</EuiFlexItem>
</EuiFlexGroup>
</>
);
}

return (
<>
{labels.NO_DATA_MESSAGE}
{clockSyncError}
</>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*
* 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, { useState } from 'react';
import { i18n } from '@kbn/i18n';
import {
EuiButton,
EuiButtonEmpty,
EuiText,
EuiPopoverTitle,
EuiPopover,
EuiPopoverFooter,
} from '@elastic/eui';
import { useSelector } from 'react-redux';
import { FormattedMessage } from '@kbn/i18n-react';

import { selectPingHistogram } from '../../../state/selectors';
import { useUrlParams } from '../../../hooks';

export const TroubleshootPopover = () => {
const [isPopoverOpen, setIsPopoverOpen] = useState(false);

const onButtonClick = () => setIsPopoverOpen((prevState) => !prevState);
const closePopover = () => setIsPopoverOpen(false);

const { pingHistogram } = useSelector(selectPingHistogram);

const updatedUrlParams = useUrlParams()[1];

const histogram = pingHistogram?.histogram ?? [];

const middleBucketTimestamp = histogram?.[Math.floor(histogram.length / 2)].x;
const firstBucketTimestamp = histogram?.[0].x;

return (
<EuiPopover
button={<EuiButtonEmpty onClick={onButtonClick}>{WHERE_ARE_MY_MONITORS}</EuiButtonEmpty>}
isOpen={isPopoverOpen}
closePopover={closePopover}
anchorPosition="upCenter"
>
<EuiPopoverTitle>{SYSTEM_CLOCK_OUT_OF_SYNC}</EuiPopoverTitle>
<div style={{ width: '300px' }}>
<EuiText size="s">
<p>
<FormattedMessage
id="xpack.uptime.monitorList.noMessage.troubleshoot"
defaultMessage="Try using an absolute date range. If monitors appears afterwards,
there may be an issue with the system clock where Heartbeat or Kibana is installed."
/>
</p>
</EuiText>
</div>
<EuiPopoverFooter>
<EuiButton
fullWidth
iconType="calendar"
size="s"
onClick={() => {
if (middleBucketTimestamp && firstBucketTimestamp) {
updatedUrlParams({
dateRangeStart: new Date(firstBucketTimestamp).toISOString(),
dateRangeEnd: new Date(middleBucketTimestamp).toISOString(),
});
}
}}
>
{APPLY_ABSOLUTE_DATE_RANGE}
</EuiButton>
</EuiPopoverFooter>
</EuiPopover>
);
};

export const APPLY_ABSOLUTE_DATE_RANGE = i18n.translate(
'xpack.uptime.monitorList.troubleshoot.tryDateRange',
{
defaultMessage: 'Apply absolute date range',
}
);

export const WHERE_ARE_MY_MONITORS = i18n.translate(
'xpack.uptime.monitorList.troubleshoot.whereAreMyMonitors',
{
defaultMessage: 'Where are my monitors?',
}
);

export const SYSTEM_CLOCK_OUT_OF_SYNC = i18n.translate(
'xpack.uptime.monitorList.troubleshoot.systemClockOutOfSync',
{
defaultMessage: 'System clock may be out of sync',
}
);
11 changes: 11 additions & 0 deletions x-pack/plugins/uptime/server/lib/requests/search/query_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,17 @@ export class QueryContext {
// only slower, but only marginally so, and prevents people from seeing weird
// behavior.

if (this.dateRangeEnd === 'now') {
return {
range: {
'monitor.timespan': {
gte: 'now-5m',
lte: 'now',
},
},
};
}

const tsEnd = parseRelativeDate(this.dateRangeEnd, { roundUp: true })!;
const tsStart = moment(tsEnd).subtract(5, 'minutes');

Expand Down

0 comments on commit e05b216

Please sign in to comment.