[Uptime] Add new context for uptime (#34006)

* Add new context for uptime.

* Implement Uptime context.

* Convert application class to functional component.

* Fix typings.

* Fix busted types.

* Update unit tests.

* Move query files. Update API/functional tests.

* Fix code formatting.

* Fix improper import syntax.

* Delete obsolete code.

* Add base path to app context.

* Add refresh tracker to app context.

* Clean up code.

* Fix unit conversion defect and add a unit test to check for incorrect values displayed.

* Fix broken code formatting.

* Clean up redundant code.

* Split context into separate contexts for refresh and settings.

* Fix unit test snapshot and props.

* Fix code formatting.
This commit is contained in:
Justin Kambic 2019-04-12 10:30:32 -04:00 committed by GitHub
parent 83b8ff3713
commit 4e3d182058
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
64 changed files with 1613 additions and 1795 deletions

View file

@ -4,5 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
export * from './pings';
export * from './monitors';

View file

@ -45,7 +45,7 @@ exports[`MonitorCharts component renders the component without errors 1`] = `
yDomain={
Array [
0,
75,
6669,
]
}
>

View file

@ -62,20 +62,28 @@ exports[`PingList component renders sorted list without errors 1`] = `
compressed={false}
fullWidth={false}
isClearable={false}
onChange={[MockFunction]}
onChange={[Function]}
options={
Array [
Object {
"label": "All",
"value": "",
},
Object {
"label": "Up",
"value": "up",
},
Object {
"label": "Down",
"value": "down",
},
]
}
selectedOptions={
Array [
Object {
"label": "All",
"value": "",
"label": "Down",
"value": "down",
},
]
}

View file

@ -7,7 +7,7 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { ErrorListItem } from '../../../../common/graphql/types';
import { ErrorList } from '../error_list';
import { ErrorListComponent } from '../error_list';
describe('ErrorList component', () => {
let getErrorListResponse: { errorList: ErrorListItem[] };
@ -57,7 +57,7 @@ describe('ErrorList component', () => {
it('renders the error list without errors', () => {
const { errorList } = getErrorListResponse;
const component = shallowWithIntl(<ErrorList loading={false} errorList={errorList} />);
const component = shallowWithIntl(<ErrorListComponent loading={false} data={{ errorList }} />);
expect(component).toMatchSnapshot();
});
});

View file

@ -6,7 +6,7 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { FilterBar } from '../filter_bar';
import { FilterBarComponent } from '../filter_bar';
describe('FilterBar component', () => {
const data = {
@ -28,10 +28,17 @@ describe('FilterBar component', () => {
schemes: ['tcp', 'http'],
},
};
let currentQuery;
it('renders the component without errors', () => {
currentQuery = undefined;
const component = shallowWithIntl(
<FilterBar filterBar={data.filterBar} updateQuery={jest.fn()} />
<FilterBarComponent
currentQuery={currentQuery}
data={data}
loading={false}
updateQuery={jest.fn()}
/>
);
expect(component).toMatchSnapshot();
});

View file

@ -6,10 +6,11 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { MonitorCharts } from '../monitor_charts';
import { MonitorChartsComponent } from '../monitor_charts';
import { MonitorChart } from '../../../../common/graphql/types';
describe('MonitorCharts component', () => {
const chartResponse = {
const chartResponse: { monitorChartsData: MonitorChart } = {
monitorChartsData: {
durationArea: [
{ x: 1548697620000, yMin: 106421, yMax: 3120392 },
@ -57,11 +58,10 @@ describe('MonitorCharts component', () => {
it('renders the component without errors', () => {
const component = shallowWithIntl(
<MonitorCharts
checkDomainLimits={[0, 75]}
<MonitorChartsComponent
danger="dangerColor"
durationDomainLimits={[0, 75]}
monitorChartsData={chartResponse.monitorChartsData}
data={{ monitorChartsData: chartResponse.monitorChartsData }}
loading={false}
mean="mean"
range="range"
success="success"

View file

@ -6,447 +6,443 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { LatestMonitorsResult } from '../../../../common/graphql/types';
import { MonitorList } from '../monitor_list';
import { LatestMonitor } from '../../../../common/graphql/types';
import { MonitorListComponent } from '../monitor_list';
describe('MonitorList component', () => {
let monitorResult: LatestMonitorsResult;
let monitors: LatestMonitor[];
beforeEach(() => {
monitorResult = {
monitors: [
{
id: { key: 'auto-http-0X131221E73F825974', url: 'https://www.google.com/' },
ping: {
timestamp: '2019-01-28T18:43:15.077Z',
monitor: {
duration: { us: 132169 },
id: 'auto-http-0X131221E73F825974',
ip: '172.217.12.132',
name: '',
status: 'up',
},
url: { full: 'https://www.google.com/' },
monitors = [
{
id: { key: 'auto-http-0X131221E73F825974', url: 'https://www.google.com/' },
ping: {
timestamp: '2019-01-28T18:43:15.077Z',
monitor: {
duration: { us: 132169 },
id: 'auto-http-0X131221E73F825974',
ip: '172.217.12.132',
name: '',
status: 'up',
},
upSeries: [
{ x: 1548697620000, y: 74 },
{ x: 1548697920000, y: 75 },
{ x: 1548698220000, y: 75 },
{ x: 1548698520000, y: 73 },
{ x: 1548698820000, y: 75 },
{ x: 1548699120000, y: 74 },
{ x: 1548699420000, y: 75 },
{ x: 1548699720000, y: 75 },
{ x: 1548700020000, y: 75 },
{ x: 1548700320000, y: 75 },
{ x: 1548700620000, y: 75 },
{ x: 1548700920000, y: 19 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
url: { full: 'https://www.google.com/' },
},
{
id: { key: 'auto-http-0X3675F89EF0612091', url: 'http://localhost:12349/' },
ping: {
timestamp: '2019-01-28T18:43:15.077Z',
monitor: {
duration: { us: 3331 },
id: 'auto-http-0X3675F89EF0612091',
ip: '127.0.0.1',
name: '',
status: 'down',
},
url: { full: 'http://localhost:12349/' },
upSeries: [
{ x: 1548697620000, y: 74 },
{ x: 1548697920000, y: 75 },
{ x: 1548698220000, y: 75 },
{ x: 1548698520000, y: 73 },
{ x: 1548698820000, y: 75 },
{ x: 1548699120000, y: 74 },
{ x: 1548699420000, y: 75 },
{ x: 1548699720000, y: 75 },
{ x: 1548700020000, y: 75 },
{ x: 1548700320000, y: 75 },
{ x: 1548700620000, y: 75 },
{ x: 1548700920000, y: 19 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
},
{
id: { key: 'auto-http-0X3675F89EF0612091', url: 'http://localhost:12349/' },
ping: {
timestamp: '2019-01-28T18:43:15.077Z',
monitor: {
duration: { us: 3331 },
id: 'auto-http-0X3675F89EF0612091',
ip: '127.0.0.1',
name: '',
status: 'down',
},
upSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
downSeries: [
{ x: 1548697620000, y: 74 },
{ x: 1548697920000, y: 75 },
{ x: 1548698220000, y: 75 },
{ x: 1548698520000, y: 75 },
{ x: 1548698820000, y: 75 },
{ x: 1548699120000, y: 75 },
{ x: 1548699420000, y: 75 },
{ x: 1548699720000, y: 75 },
{ x: 1548700020000, y: 75 },
{ x: 1548700320000, y: 75 },
{ x: 1548700620000, y: 75 },
{ x: 1548700920000, y: 19 },
],
url: { full: 'http://localhost:12349/' },
},
{
id: { key: 'auto-http-0X970CBD2F2102BFA8', url: 'http://www.google.com/' },
ping: {
timestamp: '2019-01-28T18:43:15.077Z',
monitor: {
duration: { us: 118727 },
id: 'auto-http-0X970CBD2F2102BFA8',
ip: '172.217.12.132',
name: '',
status: 'up',
},
url: { full: 'http://www.google.com/' },
upSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
downSeries: [
{ x: 1548697620000, y: 74 },
{ x: 1548697920000, y: 75 },
{ x: 1548698220000, y: 75 },
{ x: 1548698520000, y: 75 },
{ x: 1548698820000, y: 75 },
{ x: 1548699120000, y: 75 },
{ x: 1548699420000, y: 75 },
{ x: 1548699720000, y: 75 },
{ x: 1548700020000, y: 75 },
{ x: 1548700320000, y: 75 },
{ x: 1548700620000, y: 75 },
{ x: 1548700920000, y: 19 },
],
},
{
id: { key: 'auto-http-0X970CBD2F2102BFA8', url: 'http://www.google.com/' },
ping: {
timestamp: '2019-01-28T18:43:15.077Z',
monitor: {
duration: { us: 118727 },
id: 'auto-http-0X970CBD2F2102BFA8',
ip: '172.217.12.132',
name: '',
status: 'up',
},
upSeries: [
{ x: 1548697620000, y: 58 },
{ x: 1548697920000, y: 60 },
{ x: 1548698220000, y: 60 },
{ x: 1548698520000, y: 60 },
{ x: 1548698820000, y: 60 },
{ x: 1548699120000, y: 60 },
{ x: 1548699420000, y: 60 },
{ x: 1548699720000, y: 60 },
{ x: 1548700020000, y: 60 },
{ x: 1548700320000, y: 60 },
{ x: 1548700620000, y: 60 },
{ x: 1548700920000, y: 16 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
url: { full: 'http://www.google.com/' },
},
{
id: { key: 'auto-http-0X9CB71300ABD5A2A8', url: 'https://www.github.com/' },
ping: {
timestamp: '2019-01-28T18:43:15.077Z',
monitor: {
duration: { us: 247244 },
id: 'auto-http-0X9CB71300ABD5A2A8',
ip: '192.30.253.112',
name: '',
status: 'up',
},
url: { full: 'https://www.github.com/' },
upSeries: [
{ x: 1548697620000, y: 58 },
{ x: 1548697920000, y: 60 },
{ x: 1548698220000, y: 60 },
{ x: 1548698520000, y: 60 },
{ x: 1548698820000, y: 60 },
{ x: 1548699120000, y: 60 },
{ x: 1548699420000, y: 60 },
{ x: 1548699720000, y: 60 },
{ x: 1548700020000, y: 60 },
{ x: 1548700320000, y: 60 },
{ x: 1548700620000, y: 60 },
{ x: 1548700920000, y: 16 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
},
{
id: { key: 'auto-http-0X9CB71300ABD5A2A8', url: 'https://www.github.com/' },
ping: {
timestamp: '2019-01-28T18:43:15.077Z',
monitor: {
duration: { us: 247244 },
id: 'auto-http-0X9CB71300ABD5A2A8',
ip: '192.30.253.112',
name: '',
status: 'up',
},
upSeries: [
{ x: 1548697620000, y: 69 },
{ x: 1548697920000, y: 70 },
{ x: 1548698220000, y: 68 },
{ x: 1548698520000, y: 69 },
{ x: 1548698820000, y: 69 },
{ x: 1548699120000, y: 69 },
{ x: 1548699420000, y: 70 },
{ x: 1548699720000, y: 70 },
{ x: 1548700020000, y: 70 },
{ x: 1548700320000, y: 69 },
{ x: 1548700620000, y: 70 },
{ x: 1548700920000, y: 18 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
url: { full: 'https://www.github.com/' },
},
{
id: { key: 'auto-http-0XA8096548ECEB85B7', url: 'http://www.example.com/' },
ping: {
timestamp: '2019-01-28T18:43:07.078Z',
monitor: {
duration: { us: 4751074 },
id: 'auto-http-0XA8096548ECEB85B7',
ip: '198.71.248.67',
name: '',
status: 'down',
},
url: { full: 'http://www.example.com/' },
upSeries: [
{ x: 1548697620000, y: 69 },
{ x: 1548697920000, y: 70 },
{ x: 1548698220000, y: 68 },
{ x: 1548698520000, y: 69 },
{ x: 1548698820000, y: 69 },
{ x: 1548699120000, y: 69 },
{ x: 1548699420000, y: 70 },
{ x: 1548699720000, y: 70 },
{ x: 1548700020000, y: 70 },
{ x: 1548700320000, y: 69 },
{ x: 1548700620000, y: 70 },
{ x: 1548700920000, y: 18 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
},
{
id: { key: 'auto-http-0XA8096548ECEB85B7', url: 'http://www.example.com/' },
ping: {
timestamp: '2019-01-28T18:43:07.078Z',
monitor: {
duration: { us: 4751074 },
id: 'auto-http-0XA8096548ECEB85B7',
ip: '198.71.248.67',
name: '',
status: 'down',
},
upSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
downSeries: [
{ x: 1548697620000, y: 57 },
{ x: 1548697920000, y: 60 },
{ x: 1548698220000, y: 61 },
{ x: 1548698520000, y: 56 },
{ x: 1548698820000, y: 45 },
{ x: 1548699120000, y: 49 },
{ x: 1548699420000, y: 60 },
{ x: 1548699720000, y: 60 },
{ x: 1548700020000, y: 64 },
{ x: 1548700320000, y: 59 },
{ x: 1548700620000, y: 60 },
{ x: 1548700920000, y: 14 },
],
url: { full: 'http://www.example.com/' },
},
{
id: { key: 'auto-http-0XC9CDA429418EDC2B', url: 'https://www.wikipedia.org/' },
ping: {
timestamp: '2019-01-28T18:42:55.074Z',
monitor: {
duration: { us: 1164812 },
id: 'auto-http-0XC9CDA429418EDC2B',
ip: '208.80.154.224',
name: '',
status: 'up',
},
url: { full: 'https://www.wikipedia.org/' },
upSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
downSeries: [
{ x: 1548697620000, y: 57 },
{ x: 1548697920000, y: 60 },
{ x: 1548698220000, y: 61 },
{ x: 1548698520000, y: 56 },
{ x: 1548698820000, y: 45 },
{ x: 1548699120000, y: 49 },
{ x: 1548699420000, y: 60 },
{ x: 1548699720000, y: 60 },
{ x: 1548700020000, y: 64 },
{ x: 1548700320000, y: 59 },
{ x: 1548700620000, y: 60 },
{ x: 1548700920000, y: 14 },
],
},
{
id: { key: 'auto-http-0XC9CDA429418EDC2B', url: 'https://www.wikipedia.org/' },
ping: {
timestamp: '2019-01-28T18:42:55.074Z',
monitor: {
duration: { us: 1164812 },
id: 'auto-http-0XC9CDA429418EDC2B',
ip: '208.80.154.224',
name: '',
status: 'up',
},
upSeries: [
{ x: 1548697620000, y: 5 },
{ x: 1548697920000, y: 5 },
{ x: 1548698220000, y: 5 },
{ x: 1548698520000, y: 5 },
{ x: 1548698820000, y: 5 },
{ x: 1548699120000, y: 5 },
{ x: 1548699420000, y: 5 },
{ x: 1548699720000, y: 5 },
{ x: 1548700020000, y: 5 },
{ x: 1548700320000, y: 5 },
{ x: 1548700620000, y: 5 },
{ x: 1548700920000, y: 1 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
url: { full: 'https://www.wikipedia.org/' },
},
{
id: { key: 'auto-http-0XD9AE729FC1C1E04A', url: 'http://www.reddit.com/' },
ping: {
timestamp: '2019-01-28T18:43:13.074Z',
monitor: {
duration: { us: 299586 },
id: 'auto-http-0XD9AE729FC1C1E04A',
ip: '151.101.249.140',
name: '',
status: 'up',
},
url: { full: 'http://www.reddit.com/' },
upSeries: [
{ x: 1548697620000, y: 5 },
{ x: 1548697920000, y: 5 },
{ x: 1548698220000, y: 5 },
{ x: 1548698520000, y: 5 },
{ x: 1548698820000, y: 5 },
{ x: 1548699120000, y: 5 },
{ x: 1548699420000, y: 5 },
{ x: 1548699720000, y: 5 },
{ x: 1548700020000, y: 5 },
{ x: 1548700320000, y: 5 },
{ x: 1548700620000, y: 5 },
{ x: 1548700920000, y: 1 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
},
{
id: { key: 'auto-http-0XD9AE729FC1C1E04A', url: 'http://www.reddit.com/' },
ping: {
timestamp: '2019-01-28T18:43:13.074Z',
monitor: {
duration: { us: 299586 },
id: 'auto-http-0XD9AE729FC1C1E04A',
ip: '151.101.249.140',
name: '',
status: 'up',
},
upSeries: [
{ x: 1548697620000, y: 79 },
{ x: 1548697920000, y: 80 },
{ x: 1548698220000, y: 86 },
{ x: 1548698520000, y: 87 },
{ x: 1548698820000, y: 81 },
{ x: 1548699120000, y: 100 },
{ x: 1548699420000, y: 100 },
{ x: 1548699720000, y: 99 },
{ x: 1548700020000, y: 96 },
{ x: 1548700320000, y: 81 },
{ x: 1548700620000, y: 80 },
{ x: 1548700920000, y: 20 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: 1 },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
url: { full: 'http://www.reddit.com/' },
},
{
id: { key: 'auto-http-0XDD2D4E60FD4A61C3', url: 'https://www.elastic.co' },
ping: {
timestamp: '2019-01-28T18:43:13.074Z',
monitor: {
duration: { us: 850870 },
id: 'auto-http-0XDD2D4E60FD4A61C3',
ip: '151.101.250.217',
name: '',
status: 'up',
},
url: { full: 'https://www.elastic.co' },
upSeries: [
{ x: 1548697620000, y: 79 },
{ x: 1548697920000, y: 80 },
{ x: 1548698220000, y: 86 },
{ x: 1548698520000, y: 87 },
{ x: 1548698820000, y: 81 },
{ x: 1548699120000, y: 100 },
{ x: 1548699420000, y: 100 },
{ x: 1548699720000, y: 99 },
{ x: 1548700020000, y: 96 },
{ x: 1548700320000, y: 81 },
{ x: 1548700620000, y: 80 },
{ x: 1548700920000, y: 20 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: 1 },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
},
{
id: { key: 'auto-http-0XDD2D4E60FD4A61C3', url: 'https://www.elastic.co' },
ping: {
timestamp: '2019-01-28T18:43:13.074Z',
monitor: {
duration: { us: 850870 },
id: 'auto-http-0XDD2D4E60FD4A61C3',
ip: '151.101.250.217',
name: '',
status: 'up',
},
upSeries: [
{ x: 1548697620000, y: 79 },
{ x: 1548697920000, y: 80 },
{ x: 1548698220000, y: 86 },
{ x: 1548698520000, y: 88 },
{ x: 1548698820000, y: 81 },
{ x: 1548699120000, y: 95 },
{ x: 1548699420000, y: 94 },
{ x: 1548699720000, y: 98 },
{ x: 1548700020000, y: 93 },
{ x: 1548700320000, y: 81 },
{ x: 1548700620000, y: 80 },
{ x: 1548700920000, y: 20 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
url: { full: 'https://www.elastic.co' },
},
{
id: { key: 'auto-http-0XE3B163481423197D', url: 'https://news.google.com/' },
ping: {
timestamp: '2019-01-28T18:42:55.074Z',
monitor: {
duration: { us: 2059606 },
id: 'auto-http-0XE3B163481423197D',
ip: '216.58.219.206',
name: '',
status: 'up',
},
url: { full: 'https://news.google.com/' },
upSeries: [
{ x: 1548697620000, y: 79 },
{ x: 1548697920000, y: 80 },
{ x: 1548698220000, y: 86 },
{ x: 1548698520000, y: 88 },
{ x: 1548698820000, y: 81 },
{ x: 1548699120000, y: 95 },
{ x: 1548699420000, y: 94 },
{ x: 1548699720000, y: 98 },
{ x: 1548700020000, y: 93 },
{ x: 1548700320000, y: 81 },
{ x: 1548700620000, y: 80 },
{ x: 1548700920000, y: 20 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
},
{
id: { key: 'auto-http-0XE3B163481423197D', url: 'https://news.google.com/' },
ping: {
timestamp: '2019-01-28T18:42:55.074Z',
monitor: {
duration: { us: 2059606 },
id: 'auto-http-0XE3B163481423197D',
ip: '216.58.219.206',
name: '',
status: 'up',
},
upSeries: [
{ x: 1548697620000, y: 5 },
{ x: 1548697920000, y: 5 },
{ x: 1548698220000, y: 5 },
{ x: 1548698520000, y: 5 },
{ x: 1548698820000, y: 5 },
{ x: 1548699120000, y: 5 },
{ x: 1548699420000, y: 5 },
{ x: 1548699720000, y: 5 },
{ x: 1548700020000, y: 5 },
{ x: 1548700320000, y: 5 },
{ x: 1548700620000, y: 5 },
{ x: 1548700920000, y: 1 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
url: { full: 'https://news.google.com/' },
},
{
id: { key: 'auto-tcp-0X81440A68E839814C', url: 'tcp://localhost:9200' },
ping: {
timestamp: '2019-01-28T18:43:16.078Z',
monitor: {
duration: { us: 3328 },
id: 'auto-tcp-0X81440A68E839814C',
ip: '127.0.0.1',
name: '',
status: 'up',
},
url: { full: 'tcp://localhost:9200' },
upSeries: [
{ x: 1548697620000, y: 5 },
{ x: 1548697920000, y: 5 },
{ x: 1548698220000, y: 5 },
{ x: 1548698520000, y: 5 },
{ x: 1548698820000, y: 5 },
{ x: 1548699120000, y: 5 },
{ x: 1548699420000, y: 5 },
{ x: 1548699720000, y: 5 },
{ x: 1548700020000, y: 5 },
{ x: 1548700320000, y: 5 },
{ x: 1548700620000, y: 5 },
{ x: 1548700920000, y: 1 },
],
downSeries: [
{ x: 1548697620000, y: null },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: null },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
},
{
id: { key: 'auto-tcp-0X81440A68E839814C', url: 'tcp://localhost:9200' },
ping: {
timestamp: '2019-01-28T18:43:16.078Z',
monitor: {
duration: { us: 3328 },
id: 'auto-tcp-0X81440A68E839814C',
ip: '127.0.0.1',
name: '',
status: 'up',
},
upSeries: [
{ x: 1548697620000, y: 1 },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: 145 },
{ x: 1548698520000, y: 300 },
{ x: 1548698820000, y: 300 },
{ x: 1548699120000, y: 300 },
{ x: 1548699420000, y: 300 },
{ x: 1548699720000, y: 300 },
{ x: 1548700020000, y: 300 },
{ x: 1548700320000, y: 300 },
{ x: 1548700620000, y: 300 },
{ x: 1548700920000, y: 77 },
],
downSeries: [
{ x: 1548697620000, y: 293 },
{ x: 1548697920000, y: 300 },
{ x: 1548698220000, y: 155 },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
url: { full: 'tcp://localhost:9200' },
},
],
};
upSeries: [
{ x: 1548697620000, y: 1 },
{ x: 1548697920000, y: null },
{ x: 1548698220000, y: 145 },
{ x: 1548698520000, y: 300 },
{ x: 1548698820000, y: 300 },
{ x: 1548699120000, y: 300 },
{ x: 1548699420000, y: 300 },
{ x: 1548699720000, y: 300 },
{ x: 1548700020000, y: 300 },
{ x: 1548700320000, y: 300 },
{ x: 1548700620000, y: 300 },
{ x: 1548700920000, y: 77 },
],
downSeries: [
{ x: 1548697620000, y: 293 },
{ x: 1548697920000, y: 300 },
{ x: 1548698220000, y: 155 },
{ x: 1548698520000, y: null },
{ x: 1548698820000, y: null },
{ x: 1548699120000, y: null },
{ x: 1548699420000, y: null },
{ x: 1548699720000, y: null },
{ x: 1548700020000, y: null },
{ x: 1548700320000, y: null },
{ x: 1548700620000, y: null },
{ x: 1548700920000, y: null },
],
},
];
});
it('renders a monitor list without errors', () => {
const { monitors } = monitorResult;
const component = shallowWithIntl(
<MonitorList
<MonitorListComponent
dangerColor="red"
successColor="success"
data={{ monitorStatus: { monitors } }}
loading={false}
monitors={monitors || []}
/>
);
expect(component).toMatchSnapshot();

View file

@ -0,0 +1,38 @@
/*
* 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 } from 'test_utils/enzyme_helpers';
import { Ping } from '../../../../common/graphql/types';
import { MonitorStatusBarComponent } from '../monitor_status_bar';
describe('MonitorStatusBar component', () => {
let monitorStatus: Ping[];
beforeEach(() => {
monitorStatus = [
{
timestamp: '1554820772000',
monitor: {
duration: {
us: 1234567,
},
status: 'up',
},
url: {
full: 'https://www.example.com/',
},
},
];
});
it('renders duration in ms, not us', () => {
const component = renderWithIntl(
<MonitorStatusBarComponent loading={false} data={{ monitorStatus }} monitorId="foo" />
);
expect(component.text()).toContain('1235ms');
});
});

View file

@ -7,7 +7,7 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { PingResults } from '../../../../common/graphql/types';
import { PingList } from '../ping_list';
import { PingListComponent } from '../ping_list';
describe('PingList component', () => {
let pingList: { allPings: PingResults };
@ -188,12 +188,11 @@ describe('PingList component', () => {
it('renders sorted list without errors', () => {
const { allPings } = pingList;
const component = shallowWithIntl(
<PingList
<PingListComponent
loading={false}
pingResults={allPings}
selectedOption={{ label: 'All', value: '' }}
selectedOptionChanged={jest.fn()}
statusOptions={[{ label: 'All', value: '' }]}
data={{ allPings }}
onUpdateApp={jest.fn()}
onSelectedStatusUpdate={jest.fn()}
/>
);
expect(component).toMatchSnapshot();

View file

@ -7,7 +7,7 @@
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { Snapshot as SnapshotType } from '../../../../common/graphql/types';
import { Snapshot } from '../snapshot';
import { SnapshotComponent } from '../snapshot';
describe('Snapshot component', () => {
const snapshot: SnapshotType = {
@ -31,7 +31,11 @@ describe('Snapshot component', () => {
it('renders without errors', () => {
const wrapper = shallowWithIntl(
<Snapshot dangerColor="#F050F0" successColor="#000000" snapshot={snapshot} />
<SnapshotComponent
colors={{ danger: '#F050F0', mean: '#001100', range: '#FF00FF', success: '#000000' }}
data={{ snapshot }}
loading={false}
/>
);
expect(wrapper).toMatchSnapshot();
});

View file

@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`EmptyState component doesn't render child components when count is falsey 1`] = `
<EmptyState
<EmptyStateComponent
basePath=""
intl={
Object {
@ -105,6 +105,7 @@ exports[`EmptyState component doesn't render child components when count is fals
"timeZone": null,
}
}
loading={false}
>
<EmptyStateLoading>
<EuiEmptyPrompt
@ -172,7 +173,7 @@ exports[`EmptyState component doesn't render child components when count is fals
</div>
</EuiEmptyPrompt>
</EmptyStateLoading>
</EmptyState>
</EmptyStateComponent>
`;
exports[`EmptyState component renders child components when count is truthy 1`] = `
@ -189,124 +190,16 @@ exports[`EmptyState component renders child components when count is truthy 1`]
</Fragment>
`;
exports[`EmptyState component renders children while loading 1`] = `
<EmptyState
basePath=""
count={1}
intl={
exports[`EmptyState component renders empty state with appropriate base path 1`] = `
<EmptyStateComponent
basePath="foo"
data={
Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {
"date": Object {
"full": Object {
"day": "numeric",
"month": "long",
"weekday": "long",
"year": "numeric",
},
"long": Object {
"day": "numeric",
"month": "long",
"year": "numeric",
},
"medium": Object {
"day": "numeric",
"month": "short",
"year": "numeric",
},
"short": Object {
"day": "numeric",
"month": "numeric",
"year": "2-digit",
},
},
"number": Object {
"currency": Object {
"style": "currency",
},
"percent": Object {
"style": "percent",
},
},
"relative": Object {
"days": Object {
"units": "day",
},
"hours": Object {
"units": "hour",
},
"minutes": Object {
"units": "minute",
},
"months": Object {
"units": "month",
},
"seconds": Object {
"units": "second",
},
"years": Object {
"units": "year",
},
},
"time": Object {
"full": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"long": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"medium": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
},
"short": Object {
"hour": "numeric",
"minute": "numeric",
},
},
"getDocCount": Object {
"count": 0,
},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": Symbol(react.fragment),
"timeZone": null,
}
}
loading={true}
>
<div>
Should appear even while loading...
</div>
</EmptyState>
`;
exports[`EmptyState component renders empty state with appropriate base path 1`] = `
<EmptyState
basePath="foo"
count={0}
intl={
Object {
"defaultFormats": Object {},
@ -629,15 +522,27 @@ exports[`EmptyState component renders empty state with appropriate base path 1`]
</div>
</EuiFlexGroup>
</EmptyIndex>
</EmptyState>
</EmptyStateComponent>
`;
exports[`EmptyState component renders the message when an error occurs 1`] = `
<EmptyState
exports[`EmptyState component renders error message when an error occurs 1`] = `
<EmptyStateComponent
basePath=""
count={1}
error="An error occurred"
errors={
Array [
Object {
"extensions": undefined,
"locations": undefined,
"message": "An error occurred",
"name": "foo",
"nodes": undefined,
"originalError": undefined,
"path": undefined,
"positions": undefined,
"source": undefined,
},
]
}
intl={
Object {
"defaultFormats": Object {},
@ -740,9 +645,11 @@ exports[`EmptyState component renders the message when an error occurs 1`] = `
"timeZone": null,
}
}
loading={false}
>
<EmptyStateError
errorMessage="An error occurred"
errorMessage="Error: An error occurred
"
>
<EuiPanel
grow={true}
@ -755,7 +662,8 @@ exports[`EmptyState component renders the message when an error occurs 1`] = `
<EuiEmptyPrompt
body={
<p>
An error occurred
Error: An error occurred
</p>
}
iconColor="subdued"
@ -811,7 +719,8 @@ exports[`EmptyState component renders the message when an error occurs 1`] = `
className="euiText euiText--medium"
>
<p>
An error occurred
Error: An error occurred
</p>
</div>
</EuiText>
@ -822,5 +731,181 @@ exports[`EmptyState component renders the message when an error occurs 1`] = `
</div>
</EuiPanel>
</EmptyStateError>
</EmptyState>
</EmptyStateComponent>
`;
exports[`EmptyState component renders loading state if no errors or doc count 1`] = `
<EmptyStateComponent
basePath=""
intl={
Object {
"defaultFormats": Object {},
"defaultLocale": "en",
"formatDate": [Function],
"formatHTMLMessage": [Function],
"formatMessage": [Function],
"formatNumber": [Function],
"formatPlural": [Function],
"formatRelative": [Function],
"formatTime": [Function],
"formats": Object {
"date": Object {
"full": Object {
"day": "numeric",
"month": "long",
"weekday": "long",
"year": "numeric",
},
"long": Object {
"day": "numeric",
"month": "long",
"year": "numeric",
},
"medium": Object {
"day": "numeric",
"month": "short",
"year": "numeric",
},
"short": Object {
"day": "numeric",
"month": "numeric",
"year": "2-digit",
},
},
"number": Object {
"currency": Object {
"style": "currency",
},
"percent": Object {
"style": "percent",
},
},
"relative": Object {
"days": Object {
"units": "day",
},
"hours": Object {
"units": "hour",
},
"minutes": Object {
"units": "minute",
},
"months": Object {
"units": "month",
},
"seconds": Object {
"units": "second",
},
"years": Object {
"units": "year",
},
},
"time": Object {
"full": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"long": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
"timeZoneName": "short",
},
"medium": Object {
"hour": "numeric",
"minute": "numeric",
"second": "numeric",
},
"short": Object {
"hour": "numeric",
"minute": "numeric",
},
},
},
"formatters": Object {
"getDateTimeFormat": [Function],
"getMessageFormat": [Function],
"getNumberFormat": [Function],
"getPluralFormat": [Function],
"getRelativeFormat": [Function],
},
"locale": "en",
"messages": Object {},
"now": [Function],
"onError": [Function],
"textComponent": Symbol(react.fragment),
"timeZone": null,
}
}
loading={true}
>
<EmptyStateLoading>
<EuiEmptyPrompt
body={
<React.Fragment>
<EuiLoadingSpinner
size="xl"
/>
<EuiSpacer />
<EuiTitle
size="l"
textTransform="none"
>
<h2>
Loading…
</h2>
</EuiTitle>
</React.Fragment>
}
iconColor="subdued"
>
<div
className="euiEmptyPrompt"
>
<EuiTextColor
color="subdued"
component="span"
>
<span
className="euiTextColor euiTextColor--subdued"
>
<EuiText
grow={true}
size="m"
>
<div
className="euiText euiText--medium"
>
<EuiLoadingSpinner
size="xl"
>
<div
className="euiLoadingSpinner euiLoadingSpinner--xLarge"
/>
</EuiLoadingSpinner>
<EuiSpacer>
<div
className="euiSpacer euiSpacer--l"
/>
</EuiSpacer>
<EuiTitle
size="l"
textTransform="none"
>
<h2
className="euiTitle euiTitle--large"
>
Loading…
</h2>
</EuiTitle>
</div>
</EuiText>
</span>
</EuiTextColor>
</div>
</EuiEmptyPrompt>
</EmptyStateLoading>
</EmptyStateComponent>
`;

View file

@ -6,48 +6,62 @@
import React from 'react';
import { mountWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
import { EmptyState } from '../empty_state';
import { EmptyStateComponent } from '../empty_state';
import { GraphQLError } from 'graphql';
describe('EmptyState component', () => {
it('renders child components when count is truthy', () => {
const component = shallowWithIntl(
<EmptyState basePath="" count={1}>
<EmptyStateComponent basePath="" data={{ getDocCount: { count: 1 } }} loading={false}>
<div>Foo</div>
<div>Bar</div>
<div>Baz</div>
</EmptyState>
</EmptyStateComponent>
);
expect(component).toMatchSnapshot();
});
it(`doesn't render child components when count is falsey`, () => {
const component = mountWithIntl(
<EmptyState basePath="">
<EmptyStateComponent basePath="" data={undefined} loading={false}>
<div>Shouldn't be rendered</div>
</EmptyState>
</EmptyStateComponent>
);
expect(component).toMatchSnapshot();
});
it(`renders the message when an error occurs`, () => {
it(`renders error message when an error occurs`, () => {
const errors: GraphQLError[] = [
{
message: 'An error occurred',
locations: undefined,
path: undefined,
nodes: undefined,
source: undefined,
positions: undefined,
originalError: undefined,
extensions: undefined,
name: 'foo',
},
];
const component = mountWithIntl(
<EmptyState basePath="" error={'An error occurred'} count={1}>
<EmptyStateComponent basePath="" data={undefined} errors={errors} loading={false}>
<div>Shouldn't appear...</div>
</EmptyState>
</EmptyStateComponent>
);
expect(component).toMatchSnapshot();
});
it('renders children while loading', () => {
it('renders loading state if no errors or doc count', () => {
const component = mountWithIntl(
<EmptyState basePath="" count={1} loading={true}>
<EmptyStateComponent basePath="" loading={true}>
<div>Should appear even while loading...</div>
</EmptyState>
</EmptyStateComponent>
);
expect(component).toMatchSnapshot();
});
it('renders empty state with appropriate base path', () => {
const component = mountWithIntl(
<EmptyState basePath="foo" count={0} loading={false}>
<EmptyStateComponent basePath="foo" data={{ getDocCount: { count: 0 } }} loading={false}>
<div>If this is in the snapshot the test should fail</div>
</EmptyState>
</EmptyStateComponent>
);
expect(component).toMatchSnapshot();
});

View file

@ -5,34 +5,50 @@
*/
import React, { Fragment } from 'react';
import { formatUptimeGraphQLErrorList } from '../../../lib/helper/format_error_list';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { docCountQuery } from '../../../queries';
import { EmptyIndex } from './empty_index';
import { EmptyStateError } from './empty_state_error';
import { EmptyStateLoading } from './empty_state_loading';
interface EmptyStateQueryResult {
getDocCount?: {
count: number;
};
}
interface EmptyStateProps {
basePath: string;
children: JSX.Element[] | JSX.Element;
count?: number;
error?: string;
loading?: boolean;
}
export const EmptyState = ({ basePath, children, count, error, loading }: EmptyStateProps) => {
if (error) {
return <EmptyStateError errorMessage={error} />;
type Props = UptimeGraphQLQueryProps<EmptyStateQueryResult> & EmptyStateProps;
export const EmptyStateComponent = ({ basePath, children, data, errors }: Props) => {
if (errors) {
return <EmptyStateError errorMessage={formatUptimeGraphQLErrorList(errors)} />;
}
/**
* We choose to render the children any time the count > 0, even if
* the component is loading. If we render the loading state for this component,
* it will blow away the state of child components and trigger an ugly
* jittery UX any time the components refresh. This way we'll keep the stale
* state displayed during the fetching process.
*/
if (count) {
return <Fragment>{children}</Fragment>;
}
if (count === 0) {
return <EmptyIndex basePath={basePath} />;
if (data && data.getDocCount) {
const { count } = data.getDocCount;
/**
* We choose to render the children any time the count > 0, even if
* the component is loading. If we render the loading state for this component,
* it will blow away the state of child components and trigger an ugly
* jittery UX any time the components refresh. This way we'll keep the stale
* state displayed during the fetching process.
*/
if (count) {
return <Fragment>{children}</Fragment>;
}
if (count === 0) {
return <EmptyIndex basePath={basePath} />;
}
}
return <EmptyStateLoading />;
};
export const EmptyState = withUptimeGraphQL<EmptyStateQueryResult, EmptyStateProps>(
EmptyStateComponent,
docCountQuery
);

View file

@ -20,13 +20,16 @@ import moment from 'moment';
import React from 'react';
import { Link } from 'react-router-dom';
import { ErrorListItem, Ping } from '../../../common/graphql/types';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { errorListQuery } from '../../queries';
interface ErrorListProps {
loading: boolean;
interface ErrorListQueryResult {
errorList?: ErrorListItem[];
}
export const ErrorList = ({ loading, errorList }: ErrorListProps) => (
type Props = UptimeGraphQLQueryProps<ErrorListQueryResult>;
export const ErrorListComponent = ({ data, loading }: Props) => (
<EuiPanel paddingSize="s">
<EuiTitle size="xs">
<h5>
@ -35,7 +38,7 @@ export const ErrorList = ({ loading, errorList }: ErrorListProps) => (
</EuiTitle>
<EuiInMemoryTable
loading={loading}
items={errorList}
items={(data && data.errorList) || undefined}
columns={[
{
field: 'count',
@ -102,3 +105,8 @@ export const ErrorList = ({ loading, errorList }: ErrorListProps) => (
/>
</EuiPanel>
);
export const ErrorList = withUptimeGraphQL<ErrorListQueryResult>(
ErrorListComponent,
errorListQuery
);

View file

@ -10,21 +10,31 @@ import { i18n } from '@kbn/i18n';
import React from 'react';
import { FilterBar as FilterBarType, MonitorKey } from '../../../common/graphql/types';
import { UptimeSearchBarQueryChangeHandler } from '../../pages/overview';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { filterBarQuery } from '../../queries';
import { FilterBarLoading } from './filter_bar_loading';
import { filterBarSearchSchema } from './search_schema';
interface FilterBarQueryResult {
filterBar?: FilterBarType;
}
interface FilterBarProps {
currentQuery?: object;
filterBar: FilterBarType;
updateQuery: UptimeSearchBarQueryChangeHandler;
}
type Props = FilterBarProps & UptimeGraphQLQueryProps<FilterBarQueryResult>;
const SEARCH_THRESHOLD = 2;
export const FilterBar = ({
currentQuery,
filterBar: { names, ports, ids, schemes },
updateQuery,
}: FilterBarProps) => {
export const FilterBarComponent = ({ currentQuery, data, updateQuery }: Props) => {
if (!data || !data.filterBar) {
return <FilterBarLoading />;
}
const {
filterBar: { ids, names, ports, schemes },
} = data;
// TODO: add a factory function + type for these filter options
const filters = [
{
@ -125,3 +135,8 @@ export const FilterBar = ({
/>
);
};
export const FilterBar = withUptimeGraphQL<FilterBarQueryResult, FilterBarProps>(
FilterBarComponent,
filterBarQuery
);

View file

@ -26,115 +26,142 @@ import { FormattedMessage } from '@kbn/i18n/react';
import React, { Fragment } from 'react';
import { MonitorChart } from '../../../common/graphql/types';
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../lib/helper';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { monitorChartsQuery } from '../../queries';
interface MonitorChartsQueryResult {
monitorChartsData?: MonitorChart;
}
interface MonitorChartsProps {
checkDomainLimits: number[];
danger: string;
durationDomainLimits: number[];
monitorChartsData: MonitorChart;
mean: string;
range: string;
success: string;
}
export const MonitorCharts = ({
checkDomainLimits,
danger,
durationDomainLimits,
monitorChartsData: { durationArea, durationLine, status },
mean,
range,
success,
}: MonitorChartsProps) => (
<Fragment>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiPanel paddingSize="s" style={{ height: 248 }}>
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.monitorDuration.titleLabel"
defaultMessage="Monitor duration in milliseconds"
description="The 'ms' is an abbreviation for milliseconds."
/>
</h4>
</EuiTitle>
<EuiSeriesChart
margins={{ left: 64, right: 0, top: 16, bottom: 32 }}
height={200}
xType={EuiSeriesChartUtils.SCALE.TIME}
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
yDomain={durationDomainLimits}
animateData={false}
>
<EuiAreaSeries
color={range}
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel',
{
defaultMessage: 'Duration range',
}
)}
data={durationArea.map(({ x, yMin, yMax }) => ({
x,
y0: microsToMillis(yMin),
y: microsToMillis(yMax),
}))}
curve="curveBasis"
/>
<EuiLineSeries
color={mean}
lineSize={2}
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel',
{
defaultMessage: 'Mean duration',
}
)}
data={durationLine.map(({ x, y }) => ({
x,
y: microsToMillis(y),
}))}
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel paddingSize="s" style={{ height: 248 }}>
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.checkStatus.title"
defaultMessage="Check status"
/>
</h4>
</EuiTitle>
<EuiSeriesChart
margins={{ left: 64, right: 0, top: 16, bottom: 32 }}
height={200}
xType={EuiSeriesChartUtils.SCALE.TIME}
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
stackBy="y"
yDomain={checkDomainLimits}
animateData={false}
>
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.checkStatus.series.upCountLabel', {
defaultMessage: 'Up count',
})}
data={status.map(({ x, up }) => ({ x, y: up || 0 }))}
color={success}
/>
<EuiAreaSeries
name={i18n.translate('xpack.uptime.monitorCharts.checkStatus.series.downCountLabel', {
defaultMessage: 'Down count',
})}
data={status.map(({ x, down }) => ({ x, y: down || 0 }))}
color={danger}
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</Fragment>
type Props = MonitorChartsProps & UptimeGraphQLQueryProps<MonitorChartsQueryResult>;
export const MonitorChartsComponent = ({ danger, data, mean, range, success }: Props) => {
if (data && data.monitorChartsData) {
const {
monitorChartsData: { durationArea, durationLine, status, durationMaxValue, statusMaxCount },
} = data;
const durationMax = microsToMillis(durationMaxValue);
// These limits provide domain sizes for the charts
const checkDomainLimits = [0, statusMaxCount];
const durationDomainLimits = [0, durationMax ? durationMax : 0];
return (
<Fragment>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiPanel paddingSize="s" style={{ height: 248 }}>
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.monitorDuration.titleLabel"
defaultMessage="Monitor duration in milliseconds"
description="The 'ms' is an abbreviation for milliseconds."
/>
</h4>
</EuiTitle>
<EuiSeriesChart
margins={{ left: 64, right: 0, top: 16, bottom: 32 }}
height={200}
xType={EuiSeriesChartUtils.SCALE.TIME}
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
yDomain={durationDomainLimits}
animateData={false}
>
<EuiAreaSeries
color={range}
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.durationRangeLabel',
{
defaultMessage: 'Duration range',
}
)}
data={durationArea.map(({ x, yMin, yMax }) => ({
x,
y0: microsToMillis(yMin),
y: microsToMillis(yMax),
}))}
curve="curveBasis"
/>
<EuiLineSeries
color={mean}
lineSize={2}
name={i18n.translate(
'xpack.uptime.monitorCharts.monitorDuration.series.meanDurationLabel',
{
defaultMessage: 'Mean duration',
}
)}
data={durationLine.map(({ x, y }) => ({
x,
y: microsToMillis(y),
}))}
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel paddingSize="s" style={{ height: 248 }}>
<EuiTitle size="xs">
<h4>
<FormattedMessage
id="xpack.uptime.monitorCharts.checkStatus.title"
defaultMessage="Check status"
/>
</h4>
</EuiTitle>
<EuiSeriesChart
margins={{ left: 64, right: 0, top: 16, bottom: 32 }}
height={200}
xType={EuiSeriesChartUtils.SCALE.TIME}
xCrosshairFormat="YYYY-MM-DD hh:mmZ"
stackBy="y"
yDomain={checkDomainLimits}
animateData={false}
>
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.checkStatus.series.upCountLabel',
{
defaultMessage: 'Up count',
}
)}
data={status.map(({ x, up }) => ({ x, y: up || 0 }))}
color={success}
/>
<EuiAreaSeries
name={i18n.translate(
'xpack.uptime.monitorCharts.checkStatus.series.downCountLabel',
{
defaultMessage: 'Down count',
}
)}
data={status.map(({ x, down }) => ({ x, y: down || 0 }))}
color={danger}
/>
</EuiSeriesChart>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</Fragment>
);
}
return (
<Fragment>
{i18n.translate('xpack.uptime.monitorCharts.loadingMessage', {
defaultMessage: 'Loading…',
})}
</Fragment>
);
};
export const MonitorCharts = withUptimeGraphQL<MonitorChartsQueryResult, MonitorChartsProps>(
MonitorChartsComponent,
monitorChartsQuery
);

View file

@ -28,15 +28,23 @@ import moment from 'moment';
import React from 'react';
import { Link } from 'react-router-dom';
import { LatestMonitor, MonitorSeriesPoint } from '../../../common/graphql/types';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { monitorListQuery } from '../../queries';
import { MonitorSparkline } from './monitor_sparkline';
interface MonitorListProps {
successColor: string;
dangerColor: string;
loading: boolean;
monitors: LatestMonitor[];
interface MonitorListQueryResult {
// TODO: clean up this ugly result data shape, there should be no nesting
monitorStatus?: {
monitors: LatestMonitor[];
};
}
interface MonitorListProps {
dangerColor: string;
}
type Props = UptimeGraphQLQueryProps<MonitorListQueryResult> & MonitorListProps;
const MONITOR_LIST_DEFAULT_PAGINATION = 10;
const monitorListPagination = {
@ -44,7 +52,7 @@ const monitorListPagination = {
pageSizeOptions: [5, 10, 20, 50],
};
export const MonitorList = ({ dangerColor, loading, monitors }: MonitorListProps) => (
export const MonitorListComponent = ({ dangerColor, data, loading }: Props) => (
<EuiPanel paddingSize="s">
<EuiTitle size="xs">
<h5>
@ -129,8 +137,13 @@ export const MonitorList = ({ dangerColor, loading, monitors }: MonitorListProps
},
]}
loading={loading}
items={monitors}
items={(data && data.monitorStatus && data.monitorStatus.monitors) || undefined}
pagination={monitorListPagination}
/>
</EuiPanel>
);
export const MonitorList = withUptimeGraphQL<MonitorListQueryResult, MonitorListProps>(
MonitorListComponent,
monitorListQuery
);

View file

@ -5,17 +5,34 @@
*/
import { EuiTextColor, EuiTitle } from '@elastic/eui';
import { EuiLoadingSpinner } from '@elastic/eui';
import React from 'react';
import { MonitorPageTitle as TitleType } from '../../../common/graphql/types';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { monitorPageTitleQuery } from '../../queries';
interface MonitorPageTitleProps {
pageTitle: TitleType;
interface MonitorPageTitleQueryResult {
monitorPageTitle?: TitleType;
}
export const MonitorPageTitle = ({ pageTitle: { name, url, id } }: MonitorPageTitleProps) => (
<EuiTitle size="xxs">
<EuiTextColor color="subdued">
<h4 data-test-subj="monitor-page-title">{id}</h4>
</EuiTextColor>
</EuiTitle>
);
interface MonitorPageTitleProps {
monitorId: string;
}
type Props = MonitorPageTitleProps & UptimeGraphQLQueryProps<MonitorPageTitleQueryResult>;
export const MonitorPageTitleComponent = ({ data }: Props) =>
data && data.monitorPageTitle ? (
<EuiTitle size="xxs">
<EuiTextColor color="subdued">
<h4 data-test-subj="monitor-page-title">{data.monitorPageTitle.id}</h4>
</EuiTextColor>
</EuiTitle>
) : (
<EuiLoadingSpinner size="xl" />
);
export const MonitorPageTitle = withUptimeGraphQL<
MonitorPageTitleQueryResult,
MonitorPageTitleProps
>(MonitorPageTitleComponent, monitorPageTitleQuery);

View file

@ -7,72 +7,111 @@
import { EuiFlexGroup, EuiFlexItem, EuiHealth, EuiLink, EuiPanel } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { get } from 'lodash';
import moment from 'moment';
import React from 'react';
import { Ping } from '../../../common/graphql/types';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { monitorStatusBarQuery } from '../../queries';
import { EmptyStatusBar } from './empty_status_bar';
import { convertMicrosecondsToMilliseconds } from '../../lib/helper';
interface Props {
duration?: number | null;
url?: string;
status?: string;
timestamp?: string;
interface MonitorStatusBarQueryResult {
monitorStatus?: Ping[];
}
export const MonitorStatusBar = ({ timestamp, url, duration, status }: Props) => (
<EuiPanel>
<EuiFlexGroup gutterSize="l">
<EuiFlexItem grow={false}>
<EuiHealth
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.healthStatusMessageAriaLabel', {
defaultMessage: 'Monitor status',
})}
color={status === 'up' ? 'success' : 'danger'}
style={{ lineHeight: 'inherit' }}
>
{status === 'up'
? i18n.translate('xpack.uptime.monitorStatusBar.healthStatusMessage.upLabel', {
defaultMessage: 'Up',
})
: i18n.translate('xpack.uptime.monitorStatusBar.healthStatusMessage.downLabel', {
defaultMessage: 'Down',
interface MonitorStatusBarProps {
monitorId: string;
}
type Props = MonitorStatusBarProps & UptimeGraphQLQueryProps<MonitorStatusBarQueryResult>;
export const MonitorStatusBarComponent = ({ data, monitorId }: Props) => {
if (data && data.monitorStatus && data.monitorStatus.length) {
const { monitor, timestamp } = data.monitorStatus[0];
const duration = get(monitor, 'duration.us', undefined);
const status = get<'up' | 'down'>(monitor, 'status', 'down');
const full = get(data.monitorStatus[0], 'url.full');
return (
<EuiPanel>
<EuiFlexGroup gutterSize="l">
<EuiFlexItem grow={false}>
<EuiHealth
aria-label={i18n.translate(
'xpack.uptime.monitorStatusBar.healthStatusMessageAriaLabel',
{
defaultMessage: 'Monitor status',
}
)}
color={status === 'up' ? 'success' : 'danger'}
style={{ lineHeight: 'inherit' }}
>
{status === 'up'
? i18n.translate('xpack.uptime.monitorStatusBar.healthStatusMessage.upLabel', {
defaultMessage: 'Up',
})
: i18n.translate('xpack.uptime.monitorStatusBar.healthStatusMessage.downLabel', {
defaultMessage: 'Down',
})}
</EuiHealth>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexItem grow={false}>
<EuiLink
aria-label={i18n.translate(
'xpack.uptime.monitorStatusBar.monitorUrlLinkAriaLabel',
{
defaultMessage: 'Monitor URL link',
}
)}
href={full}
target="_blank"
>
{full}
</EuiLink>
</EuiFlexItem>
</EuiFlexItem>
{!!duration && (
<EuiFlexItem
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.durationTextAriaLabel', {
defaultMessage: 'Monitor duration in milliseconds',
})}
</EuiHealth>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFlexItem grow={false}>
<EuiLink
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.monitorUrlLinkAriaLabel', {
defaultMessage: 'Monitor URL link',
})}
href={url}
target="_blank"
grow={false}
>
<FormattedMessage
id="xpack.uptime.monitorStatusBar.healthStatus.durationInMillisecondsMessage"
values={{ duration: convertMicrosecondsToMilliseconds(duration) }}
defaultMessage="{duration}ms"
description="The 'ms' is an abbreviation for 'milliseconds'."
/>
</EuiFlexItem>
)}
<EuiFlexItem
aria-label={i18n.translate(
'xpack.uptime.monitorStatusBar.timestampFromNowTextAriaLabel',
{
defaultMessage: 'Time since last check',
}
)}
grow={false}
>
{url}
</EuiLink>
</EuiFlexItem>
</EuiFlexItem>
{!!duration && (
<EuiFlexItem
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.durationTextAriaLabel', {
defaultMessage: 'Monitor duration in milliseconds',
})}
grow={false}
>
<FormattedMessage
id="xpack.uptime.monitorStatusBar.healthStatus.durationInMillisecondsMessage"
values={{ duration }}
defaultMessage="{duration}ms"
description="The 'ms' is an abbreviation for 'milliseconds'."
/>
</EuiFlexItem>
)}
<EuiFlexItem
aria-label={i18n.translate('xpack.uptime.monitorStatusBar.timestampFromNowTextAriaLabel', {
defaultMessage: 'Time since last check',
})}
grow={false}
>
{moment(timestamp).fromNow()}
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);
{moment(parseInt(timestamp, 10)).fromNow()}
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
);
}
return (
<EmptyStatusBar
message={i18n.translate('xpack.uptime.monitorStatusBar.loadingMessage', {
defaultMessage: 'Loading…',
})}
monitorId={monitorId}
/>
);
};
export const MonitorStatusBar = withUptimeGraphQL<
MonitorStatusBarQueryResult,
MonitorStatusBarProps
>(MonitorStatusBarComponent, monitorStatusBarQuery);

View file

@ -22,25 +22,50 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { get } from 'lodash';
import moment from 'moment';
import React, { Fragment } from 'react';
import React, { Fragment, useEffect, useState } from 'react';
import { Ping, PingResults } from '../../../common/graphql/types';
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../lib/helper';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { pingsQuery } from '../../queries';
interface PingListProps {
loading: boolean;
pingResults?: PingResults;
selectedOption: EuiComboBoxOptionProps;
selectedOptionChanged: (selectedOptions: EuiComboBoxOptionProps[]) => void;
statusOptions: EuiComboBoxOptionProps[];
interface PingListQueryResult {
allPings?: PingResults;
}
export const PingList = ({
interface PingListProps {
onUpdateApp: () => void;
onSelectedStatusUpdate: (status: string | null) => void;
}
type Props = UptimeGraphQLQueryProps<PingListQueryResult> & PingListProps;
export const PingListComponent = ({
data,
loading,
pingResults,
selectedOption,
selectedOptionChanged,
statusOptions,
}: PingListProps) => {
onSelectedStatusUpdate,
onUpdateApp,
}: Props) => {
const [statusOptions] = useState<EuiComboBoxOptionProps[]>([
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.allStatusOptionLabel', {
defaultMessage: 'All',
}),
value: '',
},
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.upStatusOptionLabel', {
defaultMessage: 'Up',
}),
value: 'up',
},
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.downStatusOptionLabel', {
defaultMessage: 'Down',
}),
value: 'down',
},
]);
const [selectedOption, setSelectedOption] = useState<EuiComboBoxOptionProps>(statusOptions[2]);
const columns = [
{
field: 'monitor.status',
@ -112,11 +137,17 @@ export const PingList = ({
),
},
];
useEffect(
() => {
onUpdateApp();
},
[selectedOption]
);
let pings: Ping[] = [];
let total: number = 0;
if (pingResults && pingResults.pings) {
pings = pingResults.pings;
total = pingResults.total;
if (data && data.allPings && data.allPings.pings) {
pings = data.allPings.pings;
total = data.allPings.total;
const hasStatus: boolean = pings.reduce(
(hasHttpStatus: boolean, currentPing: Ping) =>
hasHttpStatus || !!get(currentPing, 'http.response.status_code'),
@ -164,12 +195,22 @@ export const PingList = ({
<EuiComboBox
isClearable={false}
singleSelection={{ asPlainText: true }}
selectedOptions={[selectedOption]}
selectedOptions={[selectedOption || statusOptions[2]]}
options={statusOptions}
aria-label={i18n.translate('xpack.uptime.pingList.statusLabel', {
defaultMessage: 'Status',
})}
onChange={selectedOptionChanged}
onChange={(selectedOptions: EuiComboBoxOptionProps[]) => {
if (selectedOptions[0]) {
setSelectedOption(selectedOptions[0]);
}
if (typeof selectedOptions[0].value === 'string') {
// @ts-ignore it's definitely a string
onSelectedStatusUpdate(
selectedOptions[0].value !== '' ? selectedOptions[0].value : null
);
}
}}
/>
</EuiFlexItem>
</EuiFlexGroup>
@ -186,3 +227,8 @@ export const PingList = ({
</Fragment>
);
};
export const PingList = withUptimeGraphQL<PingListQueryResult, PingListProps>(
PingListComponent,
pingsQuery
);

View file

@ -23,112 +23,124 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import React from 'react';
import { Snapshot as SnapshotType } from '../../../common/graphql/types';
import { UptimeAppColors } from '../../uptime_app';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../higher_order';
import { snapshotQuery } from '../../queries';
import { SnapshotHistogram } from './snapshot_histogram';
import { SnapshotLoading } from './snapshot_loading';
interface SnapshotProps {
dangerColor: string;
successColor: string;
snapshot: SnapshotType;
interface SnapshotQueryResult {
snapshot?: SnapshotType;
}
export const Snapshot = ({
dangerColor,
successColor,
snapshot: { up, down, total, histogram },
}: SnapshotProps) => (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={4}>
<EuiPanel paddingSize="s">
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.endpointStatusTitle"
defaultMessage="Current status"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup justifyContent="spaceEvenly" gutterSize="s">
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.upDescription', {
defaultMessage: 'Up',
})}
textAlign="center"
title={up}
titleColor="secondary"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.downDescription', {
defaultMessage: 'Down',
})}
textAlign="center"
title={down}
titleColor="danger"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.totalDescription', {
defaultMessage: 'Total',
})}
textAlign="center"
title={total}
titleColor="subdued"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={8}>
<EuiPanel paddingSize="s" style={{ height: 170 }}>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.statusOverTimeTitle"
defaultMessage="Status over time"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
{histogram && (
<SnapshotHistogram
dangerColor={dangerColor}
histogram={histogram}
successColor={successColor}
/>
)}
{!histogram && (
<EuiEmptyPrompt
title={
<EuiTitle>
interface SnapshotProps {
colors: UptimeAppColors;
}
type Props = UptimeGraphQLQueryProps<SnapshotQueryResult> & SnapshotProps;
export const SnapshotComponent = ({ colors: { danger, success }, data }: Props) =>
data && data.snapshot ? (
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={4}>
<EuiPanel paddingSize="s">
<EuiFlexGroup direction="column">
<EuiFlexItem grow={false}>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.noDataTitle"
defaultMessage="No histogram data available"
id="xpack.uptime.snapshot.endpointStatusTitle"
defaultMessage="Current status"
/>
</h5>
</EuiTitle>
}
body={
<p>
<FormattedMessage
id="xpack.uptime.snapshot.noDataDescription"
defaultMessage="Sorry, there is no data available for the histogram"
/>
</p>
}
/>
)}
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
</EuiFlexItem>
<EuiFlexItem>
<EuiFlexGroup justifyContent="spaceEvenly" gutterSize="s">
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.upDescription', {
defaultMessage: 'Up',
})}
textAlign="center"
title={data.snapshot.up}
titleColor="secondary"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.downDescription', {
defaultMessage: 'Down',
})}
textAlign="center"
title={data.snapshot.down}
titleColor="danger"
/>
</EuiFlexItem>
<EuiFlexItem>
<EuiStat
description={i18n.translate('xpack.uptime.snapshot.stats.totalDescription', {
defaultMessage: 'Total',
})}
textAlign="center"
title={data.snapshot.total}
titleColor="subdued"
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem grow={8}>
<EuiPanel paddingSize="s" style={{ height: 170 }}>
<EuiTitle size="xs">
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.statusOverTimeTitle"
defaultMessage="Status over time"
/>
</h5>
</EuiTitle>
<EuiSpacer size="s" />
{data.snapshot.histogram && (
<SnapshotHistogram
dangerColor={danger}
histogram={data.snapshot.histogram}
successColor={success}
/>
)}
{!data.snapshot.histogram && (
<EuiEmptyPrompt
title={
<EuiTitle>
<h5>
<FormattedMessage
id="xpack.uptime.snapshot.noDataTitle"
defaultMessage="No histogram data available"
/>
</h5>
</EuiTitle>
}
body={
<p>
<FormattedMessage
id="xpack.uptime.snapshot.noDataDescription"
defaultMessage="Sorry, there is no data available for the histogram"
/>
</p>
}
/>
)}
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
) : (
<SnapshotLoading />
);
export const Snapshot = withUptimeGraphQL<SnapshotQueryResult, SnapshotProps>(
SnapshotComponent,
snapshotQuery
);

View file

@ -6,9 +6,10 @@
import { OperationVariables } from 'apollo-client';
import { GraphQLError } from 'graphql';
import React, { Fragment, useEffect, useState } from 'react';
import React, { Fragment, useContext, useEffect, useState } from 'react';
import { withApollo, WithApolloClient } from 'react-apollo';
import { formatUptimeGraphQLErrorList } from '../../lib/helper/format_error_list';
import { UptimeRefreshContext } from '../../contexts';
export interface UptimeGraphQLQueryProps<T> {
loading: boolean;
@ -18,7 +19,6 @@ export interface UptimeGraphQLQueryProps<T> {
interface UptimeGraphQLProps {
implementsCustomErrorState?: boolean;
lastRefresh?: number;
variables: OperationVariables;
}
@ -35,10 +35,11 @@ export function withUptimeGraphQL<T, P = {}>(WrappedComponent: any, query: any)
type Props = UptimeGraphQLProps & WithApolloClient<T> & P;
return withApollo((props: Props) => {
const { lastRefresh } = useContext(UptimeRefreshContext);
const [loading, setLoading] = useState(true);
const [data, setData] = useState<T | undefined>(undefined);
const [errors, setErrors] = useState<GraphQLError[] | undefined>(undefined);
const { client, implementsCustomErrorState, variables, lastRefresh } = props;
const { client, implementsCustomErrorState, variables } = props;
const fetch = () => {
setLoading(true);
client.query<T>({ fetchPolicy: 'network-only', query, variables }).then((result: any) => {

View file

@ -1,47 +0,0 @@
/*
* 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 { get } from 'lodash';
import React from 'react';
import { formatUptimeGraphQLErrorList } from '../../../lib/helper/format_error_list';
import { UptimeCommonProps } from '../../../uptime_app';
import { EmptyState } from '../../functional/empty_state';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getDocCountQuery } from './get_doc_count';
interface EmptyStateQueryResult {
data?: {
getDocCount: {
count: number;
};
};
}
interface EmptyStateProps {
basePath: string;
children: JSX.Element[];
}
type Props = EmptyStateProps & UptimeCommonProps & UptimeGraphQLQueryProps<EmptyStateQueryResult>;
export const makeEmptyStateQuery = ({ basePath, children, data, errors, loading }: Props) => {
const count = get(data, 'getDocCount.count', 0);
return (
<EmptyState
basePath={basePath}
count={count}
error={formatUptimeGraphQLErrorList(errors || [])}
loading={loading}
>
{children}
</EmptyState>
);
};
export const EmptyStateQuery = withUptimeGraphQL<EmptyStateQueryResult, EmptyStateProps>(
makeEmptyStateQuery,
getDocCountQuery
);

View file

@ -1,7 +0,0 @@
/*
* 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 { EmptyStateQuery } from './empty_state_query';

View file

@ -1,28 +0,0 @@
/*
* 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 { ErrorListItem } from '../../../../common/graphql/types';
import { UptimeCommonProps } from '../../../uptime_app';
import { ErrorList } from '../../functional';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getErrorListQuery } from './get_error_list';
interface ErrorListQueryResult {
errorList?: ErrorListItem[];
}
type Props = UptimeCommonProps & UptimeGraphQLQueryProps<ErrorListQueryResult>;
export const makeErrorListQuery = ({ data, loading }: Props) => {
const errorList: ErrorListItem[] | undefined = data ? data.errorList : undefined;
return <ErrorList loading={loading} errorList={errorList} />;
};
export const ErrorListQuery = withUptimeGraphQL<ErrorListQueryResult>(
makeErrorListQuery,
getErrorListQuery
);

View file

@ -1,7 +0,0 @@
/*
* 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 { ErrorListQuery } from './error_list_query';

View file

@ -1,38 +0,0 @@
/*
* 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 { FilterBar as FilterBarType } from '../../../../common/graphql/types';
import { UptimeSearchBarQueryChangeHandler } from '../../../pages/overview';
import { UptimeCommonProps } from '../../../uptime_app';
import { FilterBar, FilterBarLoading } from '../../functional';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getFilterBarQuery } from './get_filter_bar';
interface FilterBarQueryResult {
filterBar?: FilterBarType;
}
interface FilterBarProps {
currentQuery?: object;
updateQuery: UptimeSearchBarQueryChangeHandler;
}
type Props = FilterBarProps & UptimeCommonProps & UptimeGraphQLQueryProps<FilterBarQueryResult>;
export const makeFilterBarQuery = ({ currentQuery, data, updateQuery }: Props) => {
if (data && data.filterBar) {
return (
<FilterBar currentQuery={currentQuery} filterBar={data.filterBar} updateQuery={updateQuery} />
);
}
return <FilterBarLoading />;
};
export const FilterBarQuery = withUptimeGraphQL<FilterBarQueryResult, FilterBarProps>(
makeFilterBarQuery,
getFilterBarQuery
);

View file

@ -1,7 +0,0 @@
/*
* 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 { FilterBarQuery } from './filter_bar_query';

View file

@ -1,15 +0,0 @@
/*
* 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 { EmptyStateQuery } from './empty_state';
export { ErrorListQuery } from './error_list';
export { FilterBarQuery } from './filter_bar';
export { MonitorChartsQuery } from './monitor_charts';
export { MonitorListQuery } from './monitor_list';
export { MonitorPageTitleQuery } from './monitor_page_title';
export { MonitorStatusBarQuery } from './monitor_status_bar';
export { PingListQuery } from './ping_list';
export { SnapshotQuery } from './snapshot';

View file

@ -1,60 +0,0 @@
/*
* 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 { i18n } from '@kbn/i18n';
import React from 'react';
import { MonitorChart } from '../../../../common/graphql/types';
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper';
import { UptimeCommonProps } from '../../../uptime_app';
import { MonitorCharts } from '../../functional';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getMonitorChartsQuery } from './get_monitor_charts';
interface MonitorChartsQueryResult {
monitorChartsData?: MonitorChart;
}
interface MonitorChartsProps {
monitorId: string;
}
type Props = MonitorChartsProps &
UptimeCommonProps &
UptimeGraphQLQueryProps<MonitorChartsQueryResult>;
const makeMonitorCharts = ({ colors: { success, range, mean, danger }, data }: Props) => {
if (data && data.monitorChartsData) {
const {
monitorChartsData,
monitorChartsData: { durationMaxValue, statusMaxCount },
} = data;
const durationMax = microsToMillis(durationMaxValue);
// These limits provide domain sizes for the charts
const checkDomainLimits = [0, statusMaxCount];
const durationDomainLimits = [0, durationMax ? durationMax : 0];
return (
<MonitorCharts
checkDomainLimits={checkDomainLimits}
danger={danger}
durationDomainLimits={durationDomainLimits}
mean={mean}
monitorChartsData={monitorChartsData}
range={range}
success={success}
/>
);
}
return i18n.translate('xpack.uptime.monitorCharts.loadingMessage', {
defaultMessage: 'Loading…',
});
};
export const MonitorChartsQuery = withUptimeGraphQL<MonitorChartsQueryResult, MonitorChartsProps>(
makeMonitorCharts,
getMonitorChartsQuery
);

View file

@ -1,7 +0,0 @@
/*
* 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 { MonitorListQuery } from './monitor_list_query';

View file

@ -1,40 +0,0 @@
/*
* 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 { get } from 'lodash';
import React from 'react';
import { LatestMonitor } from '../../../../common/graphql/types';
import { UptimeCommonProps } from '../../../uptime_app';
import { MonitorList } from '../../functional/monitor_list';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getMonitorListQuery } from './get_monitor_list';
interface MonitorListQueryResult {
// TODO: clean up this ugly result data shape, there should be no nesting
monitorStatus?: {
monitors: LatestMonitor[];
};
}
type Props = UptimeCommonProps & UptimeGraphQLQueryProps<MonitorListQueryResult>;
const makeMonitorListQuery = ({ colors: { success, danger }, data, loading }: Props) => {
const monitors: LatestMonitor[] | undefined = get(data, 'monitorStatus.monitors');
return (
<MonitorList
dangerColor={danger}
loading={loading}
monitors={monitors || []}
successColor={success}
/>
);
};
export const MonitorListQuery = withUptimeGraphQL<MonitorListQueryResult>(
makeMonitorListQuery,
getMonitorListQuery
);

View file

@ -1,7 +0,0 @@
/*
* 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 { MonitorPageTitleQuery } from './monitor_page_title_query';

View file

@ -1,38 +0,0 @@
/*
* 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 { EuiLoadingSpinner } from '@elastic/eui';
import React from 'react';
import { MonitorPageTitle as TitleType } from '../../../../common/graphql/types';
import { UptimeCommonProps } from '../../../uptime_app';
import { MonitorPageTitle } from '../../functional';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getMonitorPageTitleQuery } from './get_monitor_page_title';
interface MonitorPageTitleQueryResult {
monitorPageTitle?: TitleType;
}
interface MonitorPageTitleProps {
monitorId: string;
}
type Props = MonitorPageTitleProps &
UptimeCommonProps &
UptimeGraphQLQueryProps<MonitorPageTitleQueryResult>;
export const makeMonitorPageTitleQuery = ({ data }: Props) => {
if (data && data.monitorPageTitle) {
const { monitorPageTitle } = data;
return <MonitorPageTitle pageTitle={monitorPageTitle} />;
}
return <EuiLoadingSpinner size="xl" />;
};
export const MonitorPageTitleQuery = withUptimeGraphQL<
MonitorPageTitleQueryResult,
MonitorPageTitleProps
>(makeMonitorPageTitleQuery, getMonitorPageTitleQuery);

View file

@ -1,7 +0,0 @@
/*
* 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 { MonitorStatusBarQuery } from './monitor_status_bar_query';

View file

@ -1,57 +0,0 @@
/*
* 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 { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import React from 'react';
import { Ping } from '../../../../common/graphql/types';
import { convertMicrosecondsToMilliseconds as microsToMillis } from '../../../lib/helper';
import { UptimeCommonProps } from '../../../uptime_app';
import { EmptyStatusBar, MonitorStatusBar } from '../../functional';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getMonitorStatusBarQuery } from './get_monitor_status_bar';
interface MonitorStatusBarQueryResult {
monitorStatus?: Ping[];
}
interface MonitorStatusBarProps {
monitorId: string;
}
type Props = MonitorStatusBarProps &
UptimeCommonProps &
UptimeGraphQLQueryProps<MonitorStatusBarQueryResult>;
const makeMonitorStatusBar = ({ monitorId, data }: Props) => {
if (data && data.monitorStatus) {
const { monitorStatus } = data;
if (!monitorStatus.length) {
return <EmptyStatusBar monitorId={monitorId} />;
}
const { monitor, timestamp, url } = monitorStatus[0];
const status = get(monitor, 'status', undefined);
const duration = microsToMillis(get(monitor, 'duration.us', null));
const full = get(url, 'full', undefined);
return (
<MonitorStatusBar duration={duration} status={status} timestamp={timestamp} url={full} />
);
}
return (
<EmptyStatusBar
message={i18n.translate('xpack.uptime.monitorStatusBar.loadingMessage', {
defaultMessage: 'Loading…',
})}
monitorId={monitorId}
/>
);
};
export const MonitorStatusBarQuery = withUptimeGraphQL<
MonitorStatusBarQueryResult,
MonitorStatusBarProps
>(makeMonitorStatusBar, getMonitorStatusBarQuery);

View file

@ -1,7 +0,0 @@
/*
* 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 { PingListQuery } from './ping_list_query';

View file

@ -1,87 +0,0 @@
/*
* 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 { EuiComboBoxOptionProps } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { get } from 'lodash';
import React from 'react';
import { UMPingSortDirectionArg } from '../../../../common/domain_types';
import { PingResults } from '../../../../common/graphql/types';
import { UptimeCommonProps } from '../../../uptime_app';
import { PingList } from '../../functional';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getPingsQuery } from './get_pings';
interface PingListQueryResult {
allPings?: PingResults;
}
interface PingListProps {
monitorId?: string;
selectedOption?: EuiComboBoxOptionProps;
sort?: UMPingSortDirectionArg;
size?: number;
onStatusSelectionChange: (selectedOptions: EuiComboBoxOptionProps[]) => void;
}
type Props = PingListProps &
UptimeCommonProps &
UptimeGraphQLQueryProps<PingListQueryResult> &
PingListProps;
interface PingListState {
statusOptions: EuiComboBoxOptionProps[];
}
export class Query extends React.Component<Props, PingListState> {
constructor(props: Props) {
super(props);
const statusOptions: EuiComboBoxOptionProps[] = [
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.allStatusOptionLabel', {
defaultMessage: 'All',
}),
value: '',
},
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.upStatusOptionLabel', {
defaultMessage: 'Up',
}),
value: 'up',
},
{
label: i18n.translate('xpack.uptime.pingList.statusOptions.downStatusOptionLabel', {
defaultMessage: 'Down',
}),
value: 'down',
},
];
this.state = {
statusOptions,
};
this.props.onStatusSelectionChange([this.state.statusOptions[2]]);
}
public render() {
const { loading, data } = this.props;
const allPings: PingResults | undefined = get(data, 'allPings', undefined);
return (
<PingList
loading={loading}
pingResults={allPings}
selectedOption={this.props.selectedOption || this.state.statusOptions[2]}
selectedOptionChanged={this.props.onStatusSelectionChange}
statusOptions={this.state.statusOptions}
/>
);
}
}
export const PingListQuery = withUptimeGraphQL<PingListQueryResult, PingListProps>(
Query,
getPingsQuery
);

View file

@ -1,7 +0,0 @@
/*
* 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 { SnapshotQuery } from './snapshot_query';

View file

@ -1,31 +0,0 @@
/*
* 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 { Snapshot as SnapshotType } from '../../../../common/graphql/types';
import { UptimeCommonProps } from '../../../uptime_app';
import { Snapshot, SnapshotLoading } from '../../functional';
import { UptimeGraphQLQueryProps, withUptimeGraphQL } from '../../higher_order';
import { getSnapshotQuery } from './get_snapshot';
interface SnapshotQueryResult {
snapshot?: SnapshotType;
}
type Props = UptimeCommonProps & UptimeGraphQLQueryProps<SnapshotQueryResult>;
const Query = (props: Props) => {
const {
colors: { success, danger },
data,
} = props;
if (data && data.snapshot) {
return <Snapshot dangerColor={danger} successColor={success} snapshot={data.snapshot} />;
}
return <SnapshotLoading />;
};
export const SnapshotQuery = withUptimeGraphQL<SnapshotQueryResult>(Query, getSnapshotQuery);

View file

@ -4,4 +4,5 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { MonitorChartsQuery } from './monitor_charts_query';
export { UptimeRefreshContext } from './uptime_refresh_context';
export { UptimeSettingsContext } from './uptime_settings_context';

View file

@ -4,4 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
export type UMPingSortDirectionArg = 'asc' | 'desc';
import { createContext } from 'react';
interface UMRefreshContext {
lastRefresh: number;
}
const defaultContext: UMRefreshContext = {
lastRefresh: 0,
};
export const UptimeRefreshContext = createContext(defaultContext);

View file

@ -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;
* you may not use this file except in compliance with the Elastic License.
*/
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { createContext } from 'react';
import { UptimeAppColors } from '../uptime_app';
interface UMSettingsContext {
autorefreshIsPaused: boolean;
autorefreshInterval: number;
basePath: string;
colors: UptimeAppColors;
dateRangeStart: string;
dateRangeEnd: string;
refreshApp: () => void;
setHeadingText: (text: string) => void;
}
/**
* These are default values for the context. These defaults are typically
* overwritten by the Uptime App upon its invocation.
*/
const defaultContext: UMSettingsContext = {
autorefreshIsPaused: true,
autorefreshInterval: 10000,
basePath: '',
colors: {
success: euiLightVars.euiColorSuccess,
range: euiLightVars.euiFocusBackgroundColor,
mean: euiLightVars.euiColorPrimary,
danger: euiLightVars.euiColorDanger,
},
dateRangeStart: 'now-15m',
dateRangeEnd: 'now',
refreshApp: () => {
throw new Error('App refresh was not initialized, set it when you invoke the context');
},
setHeadingText: () => {
throw new Error('setHeadingText was not initialized on UMSettingsContext.');
},
};
export const UptimeSettingsContext = createContext(defaultContext);

View file

@ -5,7 +5,6 @@
*/
import {
EuiComboBoxOptionProps,
// @ts-ignore No typings for EuiSpacer
EuiSpacer,
// @ts-ignore No typings for EuiSuperSelect
@ -13,15 +12,16 @@ import {
} from '@elastic/eui';
import { ApolloQueryResult, OperationVariables, QueryOptions } from 'apollo-client';
import gql from 'graphql-tag';
import React, { Fragment } from 'react';
import React, { Fragment, useContext, useEffect, useState } from 'react';
import { getMonitorPageBreadcrumb } from '../breadcrumbs';
import {
MonitorChartsQuery,
MonitorPageTitleQuery,
MonitorStatusBarQuery,
PingListQuery,
} from '../components/queries';
import { UptimeCommonProps } from '../uptime_app';
MonitorCharts,
MonitorPageTitle,
MonitorStatusBar,
PingList,
} from '../components/functional';
import { UMUpdateBreadcrumbs } from '../lib/lib';
import { UptimeSettingsContext } from '../contexts';
interface MonitorPageProps {
history: { push: any };
@ -31,30 +31,16 @@ interface MonitorPageProps {
query: <T, TVariables = OperationVariables>(
options: QueryOptions<TVariables>
) => Promise<ApolloQueryResult<T>>;
setBreadcrumbs: UMUpdateBreadcrumbs;
}
type Props = MonitorPageProps & UptimeCommonProps;
interface MonitorPageState {
monitorId: string;
selectedPingListOption?: EuiComboBoxOptionProps;
}
export class MonitorPage extends React.Component<Props, MonitorPageState> {
constructor(props: Props) {
super(props);
// TODO: this is a hack because the id field's characters mess up react router's
// inner params parsing, when we add a synthetic ID for monitors this problem should go away
this.state = {
monitorId: this.props.location.pathname.replace(/^(\/monitor\/)/, ''),
};
}
public componentDidMount() {
const { query, setBreadcrumbs, setHeadingText } = this.props;
const { monitorId } = this.state;
export const MonitorPage = ({ location, query, setBreadcrumbs }: MonitorPageProps) => {
const [monitorId] = useState<string>(location.pathname.replace(/^(\/monitor\/)/, ''));
const [selectedStatus, setSelectedStatus] = useState<string | null>('down');
const { colors, dateRangeStart, dateRangeEnd, refreshApp, setHeadingText } = useContext(
UptimeSettingsContext
);
useEffect(() => {
query({
query: gql`
query MonitorPageTitle($monitorId: String!) {
@ -70,58 +56,32 @@ export class MonitorPage extends React.Component<Props, MonitorPageState> {
const { name, url, id } = result.data.monitorPageTitle;
const heading: string = name || url || id;
setBreadcrumbs(getMonitorPageBreadcrumb(heading));
setHeadingText(heading);
if (setHeadingText) {
setHeadingText(heading);
}
});
}
public render() {
const { dateRangeStart, dateRangeEnd } = this.props;
const { monitorId } = this.state;
return (
<Fragment>
<MonitorPageTitleQuery
{...this.props}
{...this.state}
monitorId={monitorId}
variables={{ monitorId }}
/>
<EuiSpacer size="s" />
<MonitorStatusBarQuery
{...this.props}
{...this.state}
monitorId={monitorId}
variables={{ dateRangeStart, dateRangeEnd, monitorId }}
/>
<EuiSpacer size="s" />
<MonitorChartsQuery
{...this.props}
{...this.state}
monitorId={monitorId}
variables={{ dateRangeStart, dateRangeEnd, monitorId }}
/>
<EuiSpacer size="s" />
<PingListQuery
variables={{
dateRangeStart,
dateRangeEnd,
monitorId,
status: this.state.selectedPingListOption
? this.state.selectedPingListOption.value
: 'down',
}}
{...this.props}
{...this.state}
onStatusSelectionChange={this.onPingListStatusSelectionChange}
selectedOption={this.state.selectedPingListOption}
/>
</Fragment>
);
}
private onPingListStatusSelectionChange = (selectedOptions: EuiComboBoxOptionProps[]) => {
if (selectedOptions[0]) {
this.setState({ selectedPingListOption: selectedOptions[0] }, () => this.props.refreshApp());
}
};
}
}, []);
return (
<Fragment>
<MonitorPageTitle monitorId={monitorId} variables={{ monitorId }} />
<EuiSpacer size="s" />
<MonitorStatusBar
monitorId={monitorId}
variables={{ dateRangeStart, dateRangeEnd, monitorId }}
/>
<EuiSpacer size="s" />
<MonitorCharts {...colors} variables={{ dateRangeStart, dateRangeEnd, monitorId }} />
<EuiSpacer size="s" />
<PingList
onSelectedStatusUpdate={setSelectedStatus}
onUpdateApp={refreshApp}
variables={{
dateRangeStart,
dateRangeEnd,
monitorId,
status: selectedStatus,
}}
/>
</Fragment>
);
};

View file

@ -7,99 +7,74 @@
// @ts-ignore EuiSearchBar missing
import { EuiSearchBar, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React, { Fragment } from 'react';
import React, { Fragment, useContext, useEffect, useState } from 'react';
import { getOverviewPageBreadcrumbs } from '../breadcrumbs';
import {
EmptyStateQuery,
ErrorListQuery,
FilterBarQuery,
MonitorListQuery,
SnapshotQuery,
} from '../components/queries';
import { EmptyState, ErrorList, FilterBar, MonitorList, Snapshot } from '../components/functional';
import { UMUpdateBreadcrumbs } from '../lib/lib';
import { UptimeCommonProps } from '../uptime_app';
import { UptimeSettingsContext } from '../contexts';
interface OverviewPageProps {
basePath: string;
setBreadcrumbs: UMUpdateBreadcrumbs;
}
type Props = OverviewPageProps & UptimeCommonProps;
interface OverviewPageState {
currentFilterObj?: object;
currentFilterQuery?: string;
}
type Props = OverviewPageProps;
export type UptimeSearchBarQueryChangeHandler = ({ query }: { query?: { text: string } }) => void;
export class OverviewPage extends React.Component<Props, OverviewPageState> {
constructor(props: Props) {
super(props);
this.state = {
currentFilterQuery: undefined,
};
}
export const OverviewPage = ({ basePath, setBreadcrumbs }: Props) => {
const { colors, dateRangeStart, dateRangeEnd, refreshApp, setHeadingText } = useContext(
UptimeSettingsContext
);
const [currentFilterQueryObj, setFilterQueryObj] = useState<object | undefined>(undefined);
const [currentFilterQuery, setCurrentFilterQuery] = useState<string | undefined>(undefined);
public componentWillMount() {
this.props.setBreadcrumbs(getOverviewPageBreadcrumbs());
this.props.setHeadingText(
i18n.translate('xpack.uptime.overviewPage.headerText', {
defaultMessage: 'Overview',
description: `The text that will be displayed in the app's heading when the Overview page loads.`,
})
);
}
useEffect(() => {
setBreadcrumbs(getOverviewPageBreadcrumbs());
if (setHeadingText) {
setHeadingText(
i18n.translate('xpack.uptime.overviewPage.headerText', {
defaultMessage: 'Overview',
description: `The text that will be displayed in the app's heading when the Overview page loads.`,
})
);
}
}, []);
public render() {
const commonVariables = {
dateRangeStart: this.props.dateRangeStart,
dateRangeEnd: this.props.dateRangeEnd,
filters: this.state.currentFilterQuery,
};
return (
<Fragment>
<EmptyStateQuery
implementsCustomErrorState={true}
variables={commonVariables}
{...this.props}
>
<FilterBarQuery
{...this.props}
currentQuery={this.state.currentFilterObj}
updateQuery={this.onFilterQueryChange}
variables={commonVariables}
/>
<EuiSpacer size="s" />
<SnapshotQuery variables={commonVariables} {...this.props} />
<EuiSpacer size="s" />
<MonitorListQuery variables={commonVariables} {...this.props} />
<EuiSpacer size="s" />
<ErrorListQuery variables={commonVariables} {...this.props} />
</EmptyStateQuery>
</Fragment>
);
}
const sharedProps = { dateRangeStart, dateRangeEnd, currentFilterQuery };
private onFilterQueryChange: UptimeSearchBarQueryChangeHandler = ({
query,
}: {
query?: { text: string };
}) => {
const updateQuery: UptimeSearchBarQueryChangeHandler = ({ query }) => {
try {
let esQuery;
if (query && query.text) {
esQuery = EuiSearchBar.Query.toESQuery(query);
}
this.setState(
{
currentFilterObj: query,
currentFilterQuery: esQuery ? JSON.stringify(esQuery) : esQuery,
},
() => this.props.refreshApp()
);
setFilterQueryObj(query);
setCurrentFilterQuery(esQuery ? JSON.stringify(esQuery) : esQuery);
if (refreshApp) {
refreshApp();
}
} catch (e) {
this.setState({ currentFilterQuery: undefined });
setFilterQueryObj(undefined);
setCurrentFilterQuery(undefined);
}
};
}
return (
<Fragment>
<EmptyState basePath={basePath} implementsCustomErrorState={true} variables={sharedProps}>
<FilterBar
currentQuery={currentFilterQueryObj}
updateQuery={updateQuery}
variables={sharedProps}
/>
<EuiSpacer size="s" />
<Snapshot colors={colors} variables={sharedProps} />
<EuiSpacer size="s" />
<MonitorList dangerColor={colors.danger} variables={sharedProps} />
<EuiSpacer size="s" />
<ErrorList variables={sharedProps} />
</EmptyState>
</Fragment>
);
};

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getDocCountQueryString = `
export const docCountQueryString = `
{
getDocCount {
count
@ -14,6 +14,6 @@ export const getDocCountQueryString = `
}
`;
export const getDocCountQuery = gql`
${getDocCountQueryString}
export const docCountQuery = gql`
${docCountQueryString}
`;

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getErrorListQueryString = `
export const errorListQueryString = `
query ErrorList($dateRangeStart: String!, $dateRangeEnd: String!, $filters: String) {
errorList: getErrorsList(
dateRangeStart: $dateRangeStart
@ -24,6 +24,6 @@ query ErrorList($dateRangeStart: String!, $dateRangeEnd: String!, $filters: Stri
}
`;
export const getErrorListQuery = gql`
${getErrorListQueryString}
export const errorListQuery = gql`
${errorListQueryString}
`;

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getFilterBarQueryString = `
export const filterBarQueryString = `
query FilterBar($dateRangeStart: String!, $dateRangeEnd: String!) {
filterBar: getFilterBar(dateRangeStart: $dateRangeStart, dateRangeEnd: $dateRangeEnd) {
ports
@ -20,6 +20,6 @@ query FilterBar($dateRangeStart: String!, $dateRangeEnd: String!) {
}
`;
export const getFilterBarQuery = gql`
${getFilterBarQueryString}
export const filterBarQuery = gql`
${filterBarQueryString}
`;

View file

@ -0,0 +1,15 @@
/*
* 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 { docCountQuery, docCountQueryString } from './doc_count_query';
export { errorListQuery, errorListQueryString } from './error_list_query';
export { filterBarQuery, filterBarQueryString } from './filter_bar_query';
export { monitorChartsQuery, monitorChartsQueryString } from './monitor_charts_query';
export { monitorListQuery, monitorListQueryString } from './monitor_list_query';
export { monitorPageTitleQuery } from './monitor_page_title_query';
export { monitorStatusBarQuery, monitorStatusBarQueryString } from './monitor_status_bar_query';
export { pingsQuery, pingsQueryString } from './pings_query';
export { snapshotQuery, snapshotQueryString } from './snapshot_query';

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getMonitorChartsQueryString = `
export const monitorChartsQueryString = `
query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId: String!) {
monitorChartsData: getMonitorChartsData(
monitorId: $monitorId
@ -34,6 +34,6 @@ query MonitorCharts($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId
}
`;
export const getMonitorChartsQuery = gql`
${getMonitorChartsQueryString}
export const monitorChartsQuery = gql`
${monitorChartsQueryString}
`;

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getMonitorListQueryString = `
export const monitorListQueryString = `
query MonitorList($dateRangeStart: String!, $dateRangeEnd: String!, $filters: String) {
monitorStatus: getMonitors(
dateRangeStart: $dateRangeStart
@ -46,6 +46,6 @@ export const getMonitorListQueryString = `
}
`;
export const getMonitorListQuery = gql`
${getMonitorListQueryString}
export const monitorListQuery = gql`
${monitorListQueryString}
`;

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getMonitorPageTitleQuery = gql`
export const monitorPageTitleQuery = gql`
query MonitorPageTitle($monitorId: String!) {
monitorPageTitle: getMonitorPageTitle(monitorId: $monitorId) {
id

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getMonitorStatusBarQueryString = `
export const monitorStatusBarQueryString = `
query MonitorStatus($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId: String) {
monitorStatus: getLatestMonitors(
dateRangeStart: $dateRangeStart
@ -28,6 +28,6 @@ query MonitorStatus($dateRangeStart: String!, $dateRangeEnd: String!, $monitorId
}
`;
export const getMonitorStatusBarQuery = gql`
${getMonitorStatusBarQueryString}
export const monitorStatusBarQuery = gql`
${monitorStatusBarQueryString}
`;

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getPingsQueryString = `
export const pingsQueryString = `
query PingList(
$dateRangeStart: String!
$dateRangeEnd: String!
@ -51,6 +51,6 @@ query PingList(
}
`;
export const getPingsQuery = gql`
${getPingsQueryString}
export const pingsQuery = gql`
${pingsQueryString}
`;

View file

@ -6,7 +6,7 @@
import gql from 'graphql-tag';
export const getSnapshotQueryString = `
export const snapshotQueryString = `
query Snapshot(
$dateRangeStart: String!
$dateRangeEnd: String!
@ -31,6 +31,6 @@ snapshot: getSnapshot(
}
`;
export const getSnapshotQuery = gql`
${getSnapshotQueryString}
export const snapshotQuery = gql`
${snapshotQueryString}
`;

View file

@ -22,37 +22,22 @@ import {
} from '@elastic/eui';
import euiDarkVars from '@elastic/eui/dist/eui_theme_dark.json';
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
import { NormalizedCacheObject } from 'apollo-cache-inmemory';
import ApolloClient from 'apollo-client';
import React from 'react';
import React, { useEffect, useState } from 'react';
import { ApolloProvider } from 'react-apollo';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import { I18nContext } from 'ui/i18n';
import { overviewBreadcrumb, UMBreadcrumb } from './breadcrumbs';
import { UMGraphQLClient, UMUpdateBreadcrumbs } from './lib/lib';
import { MonitorPage, OverviewPage } from './pages';
import { UptimeRefreshContext, UptimeSettingsContext } from './contexts';
interface UptimeAppColors {
export interface UptimeAppColors {
danger: string;
success: string;
range: string;
mean: string;
}
// TODO: these props are global to this app, we should put them in a context
export interface UptimeCommonProps {
autorefreshIsPaused: boolean;
autorefreshInterval: number;
client: ApolloClient<NormalizedCacheObject>;
colors: UptimeAppColors;
dateRangeStart: string;
dateRangeEnd: string;
lastRefresh?: number;
refreshApp: () => void;
setBreadcrumbs: UMUpdateBreadcrumbs;
setHeadingText: (text: string) => void;
}
export interface UptimePersistedState {
autorefreshIsPaused: boolean;
autorefreshInterval: number;
@ -61,7 +46,6 @@ export interface UptimePersistedState {
}
export interface UptimeAppProps {
// TODO: if we add a context to the Uptime UI, this should be included in it
basePath: string;
darkMode: boolean;
client: UMGraphQLClient;
@ -76,17 +60,6 @@ export interface UptimeAppProps {
renderGlobalHelpControls(): void;
}
interface UptimeAppState {
autorefreshIsPaused: boolean;
autorefreshInterval: number;
breadcrumbs: UMBreadcrumb[];
colors: UptimeAppColors;
dateRangeStart: string;
dateRangeEnd: string;
headingText?: string;
lastRefresh?: number;
}
// TODO: when EUI exports types for this, this should be replaced
interface SuperDateRangePickerRangeChangedEvent {
start: string;
@ -98,164 +71,155 @@ interface SuperDateRangePickerRefreshChangedEvent {
refreshInterval?: number;
}
class Application extends React.Component<UptimeAppProps, UptimeAppState> {
private setBreadcrumbs: UMUpdateBreadcrumbs;
constructor(props: UptimeAppProps) {
super(props);
const Application = (props: UptimeAppProps) => {
const {
basePath,
client,
darkMode,
initialAutorefreshIsPaused,
initialAutorefreshInterval,
initialDateRangeStart,
initialDateRangeEnd,
persistState,
renderGlobalHelpControls,
routerBasename,
setBreadcrumbs,
} = props;
const {
darkMode,
initialAutorefreshIsPaused: autorefreshIsPaused,
initialAutorefreshInterval: autorefreshInterval,
initialDateRangeStart: dateRangeStart,
initialDateRangeEnd: dateRangeEnd,
kibanaBreadcrumbs,
setBreadcrumbs,
} = props;
this.setBreadcrumbs = setBreadcrumbs;
let colors: UptimeAppColors;
if (darkMode) {
colors = {
success: euiDarkVars.euiColorSuccess,
range: euiDarkVars.euiFocusBackgroundColor,
mean: euiDarkVars.euiColorPrimary,
danger: euiDarkVars.euiColorDanger,
};
} else {
colors = {
success: euiLightVars.euiColorSuccess,
range: euiLightVars.euiFocusBackgroundColor,
mean: euiLightVars.euiColorPrimary,
danger: euiLightVars.euiColorDanger,
};
}
this.state = {
autorefreshIsPaused,
autorefreshInterval,
breadcrumbs: kibanaBreadcrumbs,
colors,
dateRangeStart,
dateRangeEnd,
let colors: UptimeAppColors;
if (darkMode) {
colors = {
success: euiDarkVars.euiColorSuccess,
range: euiDarkVars.euiFocusBackgroundColor,
mean: euiDarkVars.euiColorPrimary,
danger: euiDarkVars.euiColorDanger,
};
} else {
colors = {
success: euiLightVars.euiColorSuccess,
range: euiLightVars.euiFocusBackgroundColor,
mean: euiLightVars.euiColorPrimary,
danger: euiLightVars.euiColorDanger,
};
}
public componentWillMount() {
this.setBreadcrumbs([overviewBreadcrumb]);
}
const [autorefreshIsPaused, setAutorefreshIsPaused] = useState<boolean>(
initialAutorefreshIsPaused
);
const [autorefreshInterval, setAutorefreshInterval] = useState<number>(
initialAutorefreshInterval
);
const [dateRangeStart, setDateRangeStart] = useState<string>(initialDateRangeStart);
const [dateRangeEnd, setDateRangeEnd] = useState<string>(initialDateRangeEnd);
const [lastRefresh, setLastRefresh] = useState<number>(Date.now());
const [headingText, setHeadingText] = useState<string | undefined>(undefined);
public componentDidMount() {
this.props.renderGlobalHelpControls();
}
useEffect(() => {
setBreadcrumbs([overviewBreadcrumb]);
renderGlobalHelpControls();
}, []);
public render() {
const { basePath, routerBasename, client } = this.props;
return (
<I18nContext>
<Router basename={routerBasename}>
<ApolloProvider client={client}>
<EuiPage className="app-wrapper-panel ">
<div>
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiTitle>
<h2>{this.state.headingText}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
{
// @ts-ignore onRefresh is not defined on EuiSuperDatePicker's type yet
<EuiSuperDatePicker
start={this.state.dateRangeStart}
end={this.state.dateRangeEnd}
isPaused={this.state.autorefreshIsPaused}
refreshInterval={this.state.autorefreshInterval}
onTimeChange={({ start, end }: SuperDateRangePickerRangeChangedEvent) => {
this.setState(
{ dateRangeStart: start, dateRangeEnd: end },
this.persistState
);
this.refreshApp();
}}
const refreshApp = () => {
setLastRefresh(Date.now());
};
return (
<I18nContext>
<Router basename={routerBasename}>
<ApolloProvider client={client}>
<UptimeSettingsContext.Provider
value={{
autorefreshInterval,
autorefreshIsPaused,
basePath,
dateRangeStart,
dateRangeEnd,
colors,
refreshApp,
setHeadingText,
}}
>
<UptimeRefreshContext.Provider value={{ lastRefresh }}>
<EuiPage className="app-wrapper-panel ">
<div>
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" gutterSize="s">
<EuiFlexItem grow={false}>
<EuiTitle>
<h2>{headingText}</h2>
</EuiTitle>
</EuiFlexItem>
<EuiFlexItem grow={false}>
{
// @ts-ignore onRefresh is not defined on EuiSuperDatePicker's type yet
onRefresh={() => this.refreshApp()}
onRefreshChange={({
isPaused,
refreshInterval,
}: SuperDateRangePickerRefreshChangedEvent) => {
const autorefreshInterval =
refreshInterval === undefined
? this.state.autorefreshInterval
: refreshInterval;
this.setState(
{ autorefreshIsPaused: isPaused, autorefreshInterval },
this.persistState
);
}}
/>
}
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<Switch>
<Route
exact
path="/"
render={props => (
<OverviewPage
basePath={basePath}
{...props}
{...this.props}
{...this.state}
refreshApp={this.refreshApp}
setHeadingText={this.setHeadingText}
/>
)}
/>
<Route
path="/monitor/:id"
render={props => (
<MonitorPage
{...props}
{...this.props}
{...this.state}
refreshApp={this.refreshApp}
setHeadingText={this.setHeadingText}
query={this.props.client.query}
/>
)}
/>
</Switch>
</div>
</EuiPage>
</ApolloProvider>
</Router>
</I18nContext>
);
}
private setHeadingText = (headingText: string): void => {
this.setState({ headingText });
};
private persistState = (): void => {
const { autorefreshIsPaused, autorefreshInterval, dateRangeStart, dateRangeEnd } = this.state;
this.props.persistState({
autorefreshIsPaused,
autorefreshInterval,
dateRangeStart,
dateRangeEnd,
});
};
private refreshApp = () => {
this.setState(state => ({
...state,
lastRefresh: Date.now(),
}));
};
}
<EuiSuperDatePicker
start={dateRangeStart}
end={dateRangeEnd}
isPaused={autorefreshIsPaused}
refreshInterval={autorefreshInterval}
onTimeChange={({ start, end }: SuperDateRangePickerRangeChangedEvent) => {
setDateRangeStart(start);
setDateRangeEnd(end);
persistState({
autorefreshInterval,
autorefreshIsPaused,
dateRangeStart,
dateRangeEnd,
});
refreshApp();
}}
// @ts-ignore onRefresh is not defined on EuiSuperDatePicker's type yet
onRefresh={refreshApp}
onRefreshChange={({
isPaused,
refreshInterval,
}: SuperDateRangePickerRefreshChangedEvent) => {
setAutorefreshInterval(
refreshInterval === undefined ? autorefreshInterval : refreshInterval
);
setAutorefreshIsPaused(isPaused);
persistState({
autorefreshInterval,
autorefreshIsPaused,
dateRangeStart,
dateRangeEnd,
});
}}
/>
}
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="s" />
<Switch>
<Route
exact
path="/"
render={routerProps => (
<OverviewPage
basePath={basePath}
setBreadcrumbs={setBreadcrumbs}
{...routerProps}
/>
)}
/>
<Route
path="/monitor/:id"
render={routerProps => (
<MonitorPage
query={client.query}
setBreadcrumbs={setBreadcrumbs}
{...routerProps}
/>
)}
/>
</Switch>
</div>
</EuiPage>
</UptimeRefreshContext.Provider>
</UptimeSettingsContext.Provider>
</ApolloProvider>
</Router>
</I18nContext>
);
};
export const UptimeApp = (props: UptimeAppProps) => <Application {...props} />;

View file

@ -5,7 +5,7 @@
*/
import expect from '@kbn/expect';
import { getDocCountQueryString } from '../../../../../plugins/uptime/public/components/queries/empty_state/get_doc_count';
import { docCountQueryString } from '../../../../../plugins/uptime/public/queries';
import docCount from './fixtures/doc_count';
export default function ({ getService }) {
@ -15,7 +15,7 @@ export default function ({ getService }) {
it(`will fetch the index's count`, async () => {
const getDocCountQuery = {
operationName: null,
query: getDocCountQueryString,
query: docCountQueryString,
variables: {},
};
const {

View file

@ -5,7 +5,7 @@
*/
import expect from '@kbn/expect';
import { getErrorListQueryString } from '../../../../../plugins/uptime/public/components/queries/error_list/get_error_list';
import { errorListQueryString } from '../../../../../plugins/uptime/public/queries';
import errorList from './fixtures/error_list';
import errorListFilteredById from './fixtures/error_list_filtered_by_id';
import errorListFilteredByPort from './fixtures/error_list_filtered_by_port';
@ -18,7 +18,7 @@ export default function ({ getService }) {
it('returns expected error list', async () => {
const getErrorListQuery = {
operationName: 'ErrorList',
query: getErrorListQueryString,
query: errorListQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -36,7 +36,7 @@ export default function ({ getService }) {
it('returns an error list filtered by monitor id', async () => {
const getErrorListQuery = {
operationName: 'ErrorList',
query: getErrorListQueryString,
query: errorListQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -55,7 +55,7 @@ export default function ({ getService }) {
it('returns an error list filtered by port', async () => {
const getErrorListQuery = {
operationName: 'ErrorList',
query: getErrorListQueryString,
query: errorListQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -74,7 +74,7 @@ export default function ({ getService }) {
it('returns an error list filtered by port/type', async () => {
const getErrorListQuery = {
operationName: 'ErrorList',
query: getErrorListQueryString,
query: errorListQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',

View file

@ -5,7 +5,7 @@
*/
import expect from '@kbn/expect';
import { getFilterBarQueryString } from '../../../../../plugins/uptime/public/components/queries/filter_bar/get_filter_bar';
import { filterBarQueryString } from '../../../../../plugins/uptime/public/queries';
import filterList from './fixtures/filter_list';
export default function ({ getService }) {
@ -15,7 +15,7 @@ export default function ({ getService }) {
it('returns the expected filters', async () => {
const getFilterBarQuery = {
operationName: 'FilterBar',
query: getFilterBarQueryString,
query: filterBarQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',

View file

@ -5,7 +5,7 @@
*/
import expect from '@kbn/expect';
import { getMonitorChartsQueryString } from '../../../../../plugins/uptime/public/components/queries/monitor_charts/get_monitor_charts';
import { monitorChartsQueryString } from '../../../../../plugins/uptime/public/queries';
import monitorCharts from './fixtures/monitor_charts';
import monitorChartsEmptySet from './fixtures/monitor_charts_empty_set';
@ -16,7 +16,7 @@ export default function ({ getService }) {
it('will fetch a series of data points for monitor duration and status', async () => {
const getMonitorChartsQuery = {
operationName: 'MonitorCharts',
query: getMonitorChartsQueryString,
query: monitorChartsQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -35,7 +35,7 @@ export default function ({ getService }) {
it('will fetch empty sets for a date range with no data', async () => {
const getMonitorChartsQuery = {
operationName: 'MonitorCharts',
query: getMonitorChartsQueryString,
query: monitorChartsQueryString,
variables: {
dateRangeStart: '2002-01-28T17:40:08.078Z',
dateRangeEnd: '2002-01-28T19:00:16.078Z',

View file

@ -8,7 +8,7 @@ import expect from '@kbn/expect';
import monitorList from './fixtures/monitor_list';
import monitorListDownFiltered from './fixtures/monitor_list_down_filtered';
import monitorListUpFiltered from './fixtures/monitor_list_up_filtered';
import { getMonitorListQueryString } from '../../../../../plugins/uptime/public/components/queries/monitor_list/get_monitor_list';
import { monitorListQueryString } from '../../../../../plugins/uptime/public/queries';
export default function ({ getService }) {
describe('monitorList query', () => {
@ -17,7 +17,7 @@ export default function ({ getService }) {
it('will fetch a list of all the monitors', async () => {
const getMonitorListQuery = {
operationName: 'MonitorList',
query: getMonitorListQueryString,
query: monitorListQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -35,7 +35,7 @@ export default function ({ getService }) {
it('will fetch a filtered list of all down monitors', async () => {
const getMonitorListQuery = {
operationName: 'MonitorList',
query: getMonitorListQueryString,
query: monitorListQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -54,7 +54,7 @@ export default function ({ getService }) {
it('will fetch a filtered list of all up monitors', async () => {
const getMonitorListQuery = {
operationName: 'MonitorList',
query: getMonitorListQueryString,
query: monitorListQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',

View file

@ -7,7 +7,7 @@
import { omit } from 'lodash';
import expect from '@kbn/expect';
// eslint-disable-next-line max-len
import { getMonitorStatusBarQueryString } from '../../../../../plugins/uptime/public/components/queries/monitor_status_bar/get_monitor_status_bar';
import { monitorStatusBarQueryString } from '../../../../../plugins/uptime/public/queries';
import monitorStatus from './fixtures/monitor_status';
import monitorStatusById from './fixtures/monitor_status_by_id';
@ -18,7 +18,7 @@ export default function ({ getService }) {
it('returns the status for all monitors with no ID filtering', async () => {
const getMonitorStatusBarQuery = {
operationName: 'MonitorStatus',
query: getMonitorStatusBarQueryString,
query: monitorStatusBarQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -40,7 +40,7 @@ export default function ({ getService }) {
it('returns the status for only the given monitor', async () => {
const getMonitorStatusBarQuery = {
operationName: 'MonitorStatus',
query: getMonitorStatusBarQueryString,
query: monitorStatusBarQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',

View file

@ -5,7 +5,7 @@
*/
import expect from '@kbn/expect';
import { getPingsQueryString } from '../../../../../plugins/uptime/public/components/queries/ping_list/get_pings';
import { pingsQueryString } from '../../../../../plugins/uptime/public/queries';
import pingList from './fixtures/ping_list';
import pingListCount from './fixtures/ping_list_count';
import pingListMonitorId from './fixtures/ping_list_monitor_id';
@ -18,7 +18,7 @@ export default function ({ getService }) {
it('returns a list of pings for the given date range and default size', async () => {
const getPingsQuery = {
operationName: 'PingList',
query: getPingsQueryString,
query: pingsQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -41,7 +41,7 @@ export default function ({ getService }) {
const SIZE = 50;
const getPingsQuery = {
operationName: 'PingList',
query: getPingsQueryString,
query: pingsQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -66,7 +66,7 @@ export default function ({ getService }) {
const MONITOR_ID = 'auto-tcp-0X81440A68E839814C';
const getPingsQuery = {
operationName: 'PingList',
query: getPingsQueryString,
query: pingsQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -88,7 +88,7 @@ export default function ({ getService }) {
const MONITOR_ID = 'auto-tcp-0X81440A68E839814C';
const getPingsQuery = {
operationName: 'PingList',
query: getPingsQueryString,
query: pingsQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',

View file

@ -5,7 +5,7 @@
*/
import expect from '@kbn/expect';
import { getSnapshotQueryString } from '../../../../../plugins/uptime/public/components/queries/snapshot/get_snapshot';
import { snapshotQueryString } from '../../../../../plugins/uptime/public/queries';
import snapshot from './fixtures/snapshot';
import snapshotFilteredByDown from './fixtures/snapshot_filtered_by_down';
import snapshotFilteredByUp from './fixtures/snapshot_filtered_by_up';
@ -18,7 +18,7 @@ export default function ({ getService }) {
it('will fetch a monitor snapshot summary', async () => {
const getSnapshotQuery = {
operationName: 'Snapshot',
query: getSnapshotQueryString,
query: snapshotQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -36,7 +36,7 @@ export default function ({ getService }) {
it('will fetch a monitor snapshot filtered by down status', async () => {
const getSnapshotQuery = {
operationName: 'Snapshot',
query: getSnapshotQueryString,
query: snapshotQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -55,7 +55,7 @@ export default function ({ getService }) {
it('will fetch a monitor snapshot filtered by up status', async () => {
const getSnapshotQuery = {
operationName: 'Snapshot',
query: getSnapshotQueryString,
query: snapshotQueryString,
variables: {
dateRangeStart: '2019-01-28T17:40:08.078Z',
dateRangeEnd: '2019-01-28T19:00:16.078Z',
@ -74,7 +74,7 @@ export default function ({ getService }) {
it('returns null histogram data when no data present', async () => {
const getSnapshotQuery = {
operationName: 'Snapshot',
query: getSnapshotQueryString,
query: snapshotQueryString,
variables: {
dateRangeStart: '2019-01-25T04:30:54.740Z',
dateRangeEnd: '2019-01-28T04:50:54.740Z',