[Uptime] Details page map handle geo information missing (#54483)
* update API * update query * hide layer control and added loc tags * update test * remove unused comment * update API * remove capitalization * style fix * update types * added location status number on details page * useref instead of createRef * update interface * update import * removed redundant file * fix header for empty data * refactor for most recent check * remove redundant code * remone unused translation * update status bar * update styling * update snaps * added API tests * fix types * fixing integration tests and a typo * remove unused translations * update tests * fixed PR feedback * update feedback * update messaging * update snap * added timestamp in front of tags * update missing * update locs * update geo info missing * use formatted message * update snaps * updated types * update test * fix test * update tests * update more skipped tests * update test * update warning message Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
2ac0c91c7a
commit
f547b76312
|
@ -0,0 +1,7 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
export const UNNAMED_LOCATION = 'Unnamed-location';
|
|
@ -11,3 +11,4 @@ export { INDEX_NAMES } from './index_names';
|
|||
export * from './capabilities';
|
||||
export { PLUGIN } from './plugin';
|
||||
export { QUERY, STATES } from './query';
|
||||
export * from './constants';
|
||||
|
|
|
@ -0,0 +1,203 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LocationMap component doesnt shows warning if geo is provided 1`] = `
|
||||
<EuiErrorBoundary>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<LocationStatusTags
|
||||
locations={
|
||||
Array [
|
||||
Object {
|
||||
"geo": Object {
|
||||
"location": Object {
|
||||
"lat": "40.730610",
|
||||
"lon": " -73.935242",
|
||||
},
|
||||
"name": "New York",
|
||||
},
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 4,
|
||||
},
|
||||
"timestamp": "2020-01-13T22:50:06.536Z",
|
||||
},
|
||||
Object {
|
||||
"geo": Object {
|
||||
"location": Object {
|
||||
"lat": "52.487448",
|
||||
"lon": " 13.394798",
|
||||
},
|
||||
"name": "Tokyo",
|
||||
},
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 4,
|
||||
},
|
||||
"timestamp": "2020-01-13T22:50:04.354Z",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={true}
|
||||
>
|
||||
<styled.div>
|
||||
<EmbeddedMap
|
||||
downPoints={Array []}
|
||||
upPoints={
|
||||
Array [
|
||||
Object {
|
||||
"lat": "40.730610",
|
||||
"lon": " -73.935242",
|
||||
},
|
||||
Object {
|
||||
"lat": "52.487448",
|
||||
"lon": " 13.394798",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</styled.div>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiErrorBoundary>
|
||||
`;
|
||||
|
||||
exports[`LocationMap component renders correctly against snapshot 1`] = `
|
||||
<EuiErrorBoundary>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<LocationStatusTags
|
||||
locations={
|
||||
Array [
|
||||
Object {
|
||||
"geo": Object {
|
||||
"location": Object {
|
||||
"lat": "40.730610",
|
||||
"lon": " -73.935242",
|
||||
},
|
||||
"name": "New York",
|
||||
},
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 4,
|
||||
},
|
||||
"timestamp": "2020-01-13T22:50:06.536Z",
|
||||
},
|
||||
Object {
|
||||
"geo": Object {
|
||||
"location": Object {
|
||||
"lat": "52.487448",
|
||||
"lon": " 13.394798",
|
||||
},
|
||||
"name": "Tokyo",
|
||||
},
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 4,
|
||||
},
|
||||
"timestamp": "2020-01-13T22:50:04.354Z",
|
||||
},
|
||||
Object {
|
||||
"geo": Object {
|
||||
"name": "Unnamed-location",
|
||||
},
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 4,
|
||||
},
|
||||
"timestamp": "2020-01-13T22:50:02.753Z",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={true}
|
||||
>
|
||||
<LocationMissingWarning />
|
||||
<styled.div>
|
||||
<EmbeddedMap
|
||||
downPoints={Array []}
|
||||
upPoints={
|
||||
Array [
|
||||
Object {
|
||||
"lat": "40.730610",
|
||||
"lon": " -73.935242",
|
||||
},
|
||||
Object {
|
||||
"lat": "52.487448",
|
||||
"lon": " 13.394798",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</styled.div>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiErrorBoundary>
|
||||
`;
|
||||
|
||||
exports[`LocationMap component shows warning if geo information is missing 1`] = `
|
||||
<EuiErrorBoundary>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
>
|
||||
<LocationStatusTags
|
||||
locations={
|
||||
Array [
|
||||
Object {
|
||||
"geo": Object {
|
||||
"location": Object {
|
||||
"lat": "52.487448",
|
||||
"lon": " 13.394798",
|
||||
},
|
||||
"name": "Tokyo",
|
||||
},
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 4,
|
||||
},
|
||||
"timestamp": "2020-01-13T22:50:04.354Z",
|
||||
},
|
||||
Object {
|
||||
"geo": Object {
|
||||
"name": "Unnamed-location",
|
||||
},
|
||||
"summary": Object {
|
||||
"down": 0,
|
||||
"up": 4,
|
||||
},
|
||||
"timestamp": "2020-01-13T22:50:02.753Z",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem
|
||||
grow={true}
|
||||
>
|
||||
<LocationMissingWarning />
|
||||
<styled.div>
|
||||
<EmbeddedMap
|
||||
downPoints={Array []}
|
||||
upPoints={
|
||||
Array [
|
||||
Object {
|
||||
"lat": "52.487448",
|
||||
"lon": " 13.394798",
|
||||
},
|
||||
]
|
||||
}
|
||||
/>
|
||||
</styled.div>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiErrorBoundary>
|
||||
`;
|
|
@ -0,0 +1,123 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LocationMissingWarning component renders correctly against snapshot 1`] = `
|
||||
<div
|
||||
class="euiFlexGroup euiFlexGroup--directionRow euiFlexGroup--responsive"
|
||||
>
|
||||
<div
|
||||
class="euiFlexItem euiFlexItem--flexGrowZero"
|
||||
style="margin-left:auto;margin-right:20px"
|
||||
>
|
||||
<div
|
||||
class="euiPopover euiPopover--anchorDownCenter"
|
||||
id="popover"
|
||||
>
|
||||
<div
|
||||
class="euiPopover__anchor"
|
||||
>
|
||||
<button
|
||||
class="euiButton euiButton--warning euiButton--small"
|
||||
type="button"
|
||||
>
|
||||
<span
|
||||
class="euiButton__content"
|
||||
>
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
class="euiIcon euiIcon--medium euiIcon-isLoading euiButton__icon"
|
||||
focusable="false"
|
||||
height="16"
|
||||
role="img"
|
||||
viewBox="0 0 16 16"
|
||||
width="16"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
/>
|
||||
<span
|
||||
class="euiButton__text"
|
||||
>
|
||||
Geo Information Missing
|
||||
</span>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
exports[`LocationMissingWarning component shallow render correctly against snapshot 1`] = `
|
||||
<EuiFlexGroup
|
||||
gutterSize="none"
|
||||
>
|
||||
<EuiFlexItem
|
||||
grow={false}
|
||||
style={
|
||||
Object {
|
||||
"marginLeft": "auto",
|
||||
"marginRight": 20,
|
||||
}
|
||||
}
|
||||
>
|
||||
<EuiPopover
|
||||
anchorPosition="downCenter"
|
||||
button={
|
||||
<EuiButton
|
||||
color="warning"
|
||||
iconType="alert"
|
||||
onClick={[Function]}
|
||||
size="s"
|
||||
>
|
||||
Geo Information Missing
|
||||
</EuiButton>
|
||||
}
|
||||
closePopover={[Function]}
|
||||
display="inlineBlock"
|
||||
hasArrow={true}
|
||||
id="popover"
|
||||
isOpen={false}
|
||||
ownFocus={false}
|
||||
panelPaddingSize="m"
|
||||
>
|
||||
<EuiText
|
||||
style={
|
||||
Object {
|
||||
"width": "350px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Important geo location configuration is missing. You can use the {codeBlock} field to create distinctive geographic regions for your uptime checks."
|
||||
id="xpack.uptime.locationMap.locations.missing.message"
|
||||
values={
|
||||
Object {
|
||||
"codeBlock": <EuiCode>
|
||||
observer.geo.??
|
||||
</EuiCode>,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer
|
||||
size="xs"
|
||||
/>
|
||||
<EuiText
|
||||
style={
|
||||
Object {
|
||||
"width": "350px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Get more information in our documentation."
|
||||
id="xpack.uptime.locationMap.locations.missing.message1"
|
||||
values={Object {}}
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="xs"
|
||||
/>
|
||||
<LocationLink />
|
||||
</EuiText>
|
||||
</EuiPopover>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
`;
|
|
@ -1,5 +1,82 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`LocationStatusTags component renders properly against props 1`] = `
|
||||
<Fragment>
|
||||
<styled.div>
|
||||
<span>
|
||||
<styled.div
|
||||
key="0"
|
||||
>
|
||||
<EuiBadge
|
||||
color="#bd271e"
|
||||
>
|
||||
<EuiText
|
||||
size="m"
|
||||
>
|
||||
<styled.div>
|
||||
Berlin
|
||||
</styled.div>
|
||||
</EuiText>
|
||||
</EuiBadge>
|
||||
<styled.span>
|
||||
<EuiText
|
||||
color="subdued"
|
||||
>
|
||||
1 Mon ago
|
||||
</EuiText>
|
||||
</styled.span>
|
||||
</styled.div>
|
||||
</span>
|
||||
<span>
|
||||
<styled.div
|
||||
key="0"
|
||||
>
|
||||
<EuiBadge
|
||||
color="#d3dae6"
|
||||
>
|
||||
<EuiText
|
||||
size="m"
|
||||
>
|
||||
<styled.div>
|
||||
Berlin
|
||||
</styled.div>
|
||||
</EuiText>
|
||||
</EuiBadge>
|
||||
<styled.span>
|
||||
<EuiText
|
||||
color="subdued"
|
||||
>
|
||||
1 Mon ago
|
||||
</EuiText>
|
||||
</styled.span>
|
||||
</styled.div>
|
||||
<styled.div
|
||||
key="1"
|
||||
>
|
||||
<EuiBadge
|
||||
color="#d3dae6"
|
||||
>
|
||||
<EuiText
|
||||
size="m"
|
||||
>
|
||||
<styled.div>
|
||||
Islamabad
|
||||
</styled.div>
|
||||
</EuiText>
|
||||
</EuiBadge>
|
||||
<styled.span>
|
||||
<EuiText
|
||||
color="subdued"
|
||||
>
|
||||
1 Mon ago
|
||||
</EuiText>
|
||||
</styled.span>
|
||||
</styled.div>
|
||||
</span>
|
||||
</styled.div>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
exports[`LocationStatusTags component renders when all locations are down 1`] = `
|
||||
.c3 {
|
||||
display: inline-block;
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { LocationMap } from '../location_map';
|
||||
import { MonitorLocations } from '../../../../../common/runtime_types';
|
||||
import { LocationMissingWarning } from '../location_missing';
|
||||
|
||||
// Note For shallow test, we need absolute time strings
|
||||
describe('LocationMap component', () => {
|
||||
let monitorLocations: MonitorLocations;
|
||||
|
||||
beforeEach(() => {
|
||||
monitorLocations = {
|
||||
monitorId: 'wapo',
|
||||
locations: [
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'New York', location: { lat: '40.730610', lon: ' -73.935242' } },
|
||||
timestamp: '2020-01-13T22:50:06.536Z',
|
||||
},
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'Tokyo', location: { lat: '52.487448', lon: ' 13.394798' } },
|
||||
timestamp: '2020-01-13T22:50:04.354Z',
|
||||
},
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'Unnamed-location' },
|
||||
timestamp: '2020-01-13T22:50:02.753Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
it('renders correctly against snapshot', () => {
|
||||
const component = shallowWithIntl(<LocationMap monitorLocations={monitorLocations} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('shows warning if geo information is missing', () => {
|
||||
monitorLocations = {
|
||||
monitorId: 'wapo',
|
||||
locations: [
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'Tokyo', location: { lat: '52.487448', lon: ' 13.394798' } },
|
||||
timestamp: '2020-01-13T22:50:04.354Z',
|
||||
},
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'Unnamed-location' },
|
||||
timestamp: '2020-01-13T22:50:02.753Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
const component = shallowWithIntl(<LocationMap monitorLocations={monitorLocations} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
||||
const warningComponent = component.find(LocationMissingWarning);
|
||||
expect(warningComponent).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('doesnt shows warning if geo is provided', () => {
|
||||
monitorLocations = {
|
||||
monitorId: 'wapo',
|
||||
locations: [
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'New York', location: { lat: '40.730610', lon: ' -73.935242' } },
|
||||
timestamp: '2020-01-13T22:50:06.536Z',
|
||||
},
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'Tokyo', location: { lat: '52.487448', lon: ' 13.394798' } },
|
||||
timestamp: '2020-01-13T22:50:04.354Z',
|
||||
},
|
||||
],
|
||||
};
|
||||
const component = shallowWithIntl(<LocationMap monitorLocations={monitorLocations} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
|
||||
const warningComponent = component.find(LocationMissingWarning);
|
||||
expect(warningComponent).toHaveLength(0);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { LocationMissingWarning } from '../location_missing';
|
||||
|
||||
describe('LocationMissingWarning component', () => {
|
||||
it('shallow render correctly against snapshot', () => {
|
||||
const component = shallowWithIntl(<LocationMissingWarning />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders correctly against snapshot', () => {
|
||||
const component = renderWithIntl(<LocationMissingWarning />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
});
|
|
@ -6,13 +6,41 @@
|
|||
|
||||
import React from 'react';
|
||||
import moment from 'moment';
|
||||
import { renderWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
|
||||
import { MonitorLocation } from '../../../../../common/runtime_types/monitor';
|
||||
import { LocationStatusTags } from '../';
|
||||
|
||||
describe('LocationStatusTags component', () => {
|
||||
let monitorLocations: MonitorLocation[];
|
||||
|
||||
it('renders properly against props', () => {
|
||||
monitorLocations = [
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'Islamabad', location: { lat: '52.487448', lon: ' 13.394798' } },
|
||||
timestamp: moment()
|
||||
.subtract('5', 'w')
|
||||
.toISOString(),
|
||||
},
|
||||
{
|
||||
summary: { up: 4, down: 0 },
|
||||
geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } },
|
||||
timestamp: moment()
|
||||
.subtract('5', 'w')
|
||||
.toISOString(),
|
||||
},
|
||||
{
|
||||
summary: { up: 0, down: 2 },
|
||||
geo: { name: 'Berlin', location: { lat: '52.487448', lon: ' 13.394798' } },
|
||||
timestamp: moment()
|
||||
.subtract('5', 'w')
|
||||
.toISOString(),
|
||||
},
|
||||
];
|
||||
const component = shallowWithIntl(<LocationStatusTags locations={monitorLocations} />);
|
||||
expect(component).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('renders when there are many location', () => {
|
||||
monitorLocations = [
|
||||
{
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
|
||||
import React from 'react';
|
||||
import styled from 'styled-components';
|
||||
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
|
||||
import { EuiFlexGroup, EuiFlexItem, EuiErrorBoundary } from '@elastic/eui';
|
||||
import { LocationStatusTags } from './location_status_tags';
|
||||
import { EmbeddedMap, LocationPoint } from './embeddables/embedded_map';
|
||||
import { MonitorLocations } from '../../../../common/runtime_types';
|
||||
import { UNNAMED_LOCATION } from '../../../../common/constants';
|
||||
import { LocationMissingWarning } from './location_missing';
|
||||
|
||||
// These height/width values are used to make sure map is in center of panel
|
||||
// And to make sure, it doesn't take too much space
|
||||
|
@ -27,25 +29,34 @@ export const LocationMap = ({ monitorLocations }: LocationMapProps) => {
|
|||
const upPoints: LocationPoint[] = [];
|
||||
const downPoints: LocationPoint[] = [];
|
||||
|
||||
let isGeoInfoMissing = false;
|
||||
|
||||
if (monitorLocations?.locations) {
|
||||
monitorLocations.locations.forEach((item: any) => {
|
||||
if (item.summary.down === 0) {
|
||||
upPoints.push(item.geo.location);
|
||||
} else {
|
||||
downPoints.push(item.geo.location);
|
||||
if (item.geo?.name !== UNNAMED_LOCATION) {
|
||||
if (item.summary.down === 0) {
|
||||
upPoints.push(item.geo.location);
|
||||
} else {
|
||||
downPoints.push(item.geo.location);
|
||||
}
|
||||
} else if (item.geo?.name === UNNAMED_LOCATION) {
|
||||
isGeoInfoMissing = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
return (
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<LocationStatusTags locations={monitorLocations?.locations || []} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={true}>
|
||||
<MapPanel>
|
||||
<EmbeddedMap upPoints={upPoints} downPoints={downPoints} />
|
||||
</MapPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiErrorBoundary>
|
||||
<EuiFlexGroup>
|
||||
<EuiFlexItem grow={false}>
|
||||
<LocationStatusTags locations={monitorLocations?.locations || []} />
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem grow={true}>
|
||||
{isGeoInfoMissing && <LocationMissingWarning />}
|
||||
<MapPanel>
|
||||
<EmbeddedMap upPoints={upPoints} downPoints={downPoints} />
|
||||
</MapPanel>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
</EuiErrorBoundary>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useState } from 'react';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiPopover,
|
||||
EuiSpacer,
|
||||
EuiText,
|
||||
EuiCode,
|
||||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { LocationLink } from '../monitor_list/monitor_list_drawer';
|
||||
|
||||
export const LocationMissingWarning = () => {
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||
|
||||
const togglePopover = () => {
|
||||
setIsPopoverOpen(!isPopoverOpen);
|
||||
};
|
||||
|
||||
const button = (
|
||||
<EuiButton iconType="alert" size="s" color="warning" onClick={togglePopover}>
|
||||
Geo Information Missing
|
||||
</EuiButton>
|
||||
);
|
||||
|
||||
return (
|
||||
<EuiFlexGroup gutterSize="none">
|
||||
<EuiFlexItem grow={false} style={{ marginLeft: 'auto', marginRight: 20 }}>
|
||||
<EuiPopover
|
||||
id="popover"
|
||||
button={button}
|
||||
isOpen={isPopoverOpen}
|
||||
closePopover={togglePopover}
|
||||
>
|
||||
<EuiText style={{ width: '350px' }}>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.locationMap.locations.missing.message"
|
||||
defaultMessage="Important geo location configuration is missing.
|
||||
You can use the {codeBlock} field to create distinctive geographic regions for
|
||||
your uptime checks."
|
||||
values={{ codeBlock: <EuiCode>observer.geo.??</EuiCode> }}
|
||||
/>
|
||||
</EuiText>
|
||||
<EuiSpacer size="xs" />
|
||||
<EuiText style={{ width: '350px' }}>
|
||||
<FormattedMessage
|
||||
id="xpack.uptime.locationMap.locations.missing.message1"
|
||||
defaultMessage="Get more information in our documentation."
|
||||
/>
|
||||
<EuiSpacer size="xs" />
|
||||
<LocationLink />
|
||||
</EuiText>
|
||||
</EuiPopover>
|
||||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
|
@ -25,6 +25,7 @@ const BadgeItem = styled.div`
|
|||
margin-bottom: 5px;
|
||||
`;
|
||||
|
||||
// Set height so that it remains within panel, enough height to display 7 locations tags
|
||||
const TagContainer = styled.div`
|
||||
padding: 10px;
|
||||
max-height: 229px;
|
||||
|
@ -65,7 +66,7 @@ export const LocationStatusTags = ({ locations }: Props) => {
|
|||
return a.timestamp < b.timestamp ? 1 : b.timestamp < a.timestamp ? -1 : 0;
|
||||
});
|
||||
|
||||
moment.locale('en', {
|
||||
moment.updateLocale('en', {
|
||||
relativeTime: {
|
||||
future: 'in %s',
|
||||
past: '%s ago',
|
||||
|
|
|
@ -14,6 +14,25 @@ exports[`MonitorStatusList component renders checks 1`] = `
|
|||
locationNames={Set {}}
|
||||
status="up"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Some heartbeat instances do not have a location defined. {link} to your heartbeat configuration."
|
||||
id="xpack.uptime.monitorList.drawer.missingLocation"
|
||||
values={
|
||||
Object {
|
||||
"link": <LocationLink />,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
||||
|
@ -31,5 +50,24 @@ exports[`MonitorStatusList component renders null in place of child status with
|
|||
locationNames={Set {}}
|
||||
status="up"
|
||||
/>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
<EuiCallOut
|
||||
color="warning"
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Some heartbeat instances do not have a location defined. {link} to your heartbeat configuration."
|
||||
id="xpack.uptime.monitorList.drawer.missingLocation"
|
||||
values={
|
||||
Object {
|
||||
"link": <LocationLink />,
|
||||
}
|
||||
}
|
||||
/>
|
||||
</EuiCallOut>
|
||||
<EuiSpacer
|
||||
size="s"
|
||||
/>
|
||||
</Fragment>
|
||||
`;
|
||||
|
|
|
@ -11,6 +11,7 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import { Check } from '../../../../../common/graphql/types';
|
||||
import { LocationLink } from './location_link';
|
||||
import { MonitorStatusRow } from './monitor_status_row';
|
||||
import { UNNAMED_LOCATION } from '../../../../../common/constants';
|
||||
|
||||
interface MonitorStatusListProps {
|
||||
/**
|
||||
|
@ -21,7 +22,6 @@ interface MonitorStatusListProps {
|
|||
|
||||
export const UP = 'up';
|
||||
export const DOWN = 'down';
|
||||
export const UNNAMED_LOCATION = 'unnamed-location';
|
||||
|
||||
export const MonitorStatusList = ({ checks }: MonitorStatusListProps) => {
|
||||
const upChecks: Set<string> = new Set();
|
||||
|
|
|
@ -8,7 +8,8 @@ import React, { useContext } from 'react';
|
|||
import { EuiHealth, EuiSpacer } from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { UptimeSettingsContext } from '../../../../contexts';
|
||||
import { UNNAMED_LOCATION, UP } from './monitor_status_list';
|
||||
import { UP } from './monitor_status_list';
|
||||
import { UNNAMED_LOCATION } from '../../../../../common/constants';
|
||||
|
||||
interface MonitorStatusRowProps {
|
||||
/**
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { INDEX_NAMES } from '../../../../common/constants';
|
||||
import { INDEX_NAMES, UNNAMED_LOCATION } from '../../../../common/constants';
|
||||
import { MonitorChart, LocationDurationLine } from '../../../../common/graphql/types';
|
||||
import { getHistogramIntervalFormatted } from '../../helper';
|
||||
import { MonitorError, MonitorLocation } from '../../../../common/runtime_types';
|
||||
|
@ -347,28 +347,32 @@ export const elasticsearchMonitorsAdapter: UMMonitorsAdapter = {
|
|||
const locations = result?.aggregations?.location?.buckets ?? [];
|
||||
|
||||
const getGeo = (locGeo: any) => {
|
||||
const { name, location } = locGeo;
|
||||
const latLon = location.trim().split(',');
|
||||
return {
|
||||
name,
|
||||
location: {
|
||||
lat: latLon[0],
|
||||
lon: latLon[1],
|
||||
},
|
||||
};
|
||||
if (locGeo) {
|
||||
const { name, location } = locGeo;
|
||||
const latLon = location.trim().split(',');
|
||||
return {
|
||||
name,
|
||||
location: {
|
||||
lat: latLon[0],
|
||||
lon: latLon[1],
|
||||
},
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
name: UNNAMED_LOCATION,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
const monLocs: MonitorLocation[] = [];
|
||||
locations.forEach((loc: any) => {
|
||||
if (loc?.key !== '__location_missing__') {
|
||||
const mostRecentLocation = loc.most_recent.hits.hits[0]._source;
|
||||
const location: MonitorLocation = {
|
||||
summary: mostRecentLocation?.summary,
|
||||
geo: getGeo(mostRecentLocation?.observer?.geo),
|
||||
timestamp: mostRecentLocation['@timestamp'],
|
||||
};
|
||||
monLocs.push(location);
|
||||
}
|
||||
const mostRecentLocation = loc.most_recent.hits.hits[0]._source;
|
||||
const location: MonitorLocation = {
|
||||
summary: mostRecentLocation?.summary,
|
||||
geo: getGeo(mostRecentLocation?.observer?.geo),
|
||||
timestamp: mostRecentLocation['@timestamp'],
|
||||
};
|
||||
monLocs.push(location);
|
||||
});
|
||||
|
||||
return {
|
||||
|
|
Loading…
Reference in a new issue