[Monitoring] Convert beats overview page to use EUI components (#20765) (#21700)

* Convert beats overview page to use EUI components

* More UI components for beats overview

* Set background color to white

* Update snapshots

* Add PageBody wrapper

* Update snapshots

* Use panels

* PR feedback

* Update snapshots
This commit is contained in:
Chris Roberson 2018-08-07 09:48:57 -04:00 committed by GitHub
parent 2df37435b9
commit a743dd060f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 765 additions and 107 deletions

View file

@ -0,0 +1,43 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Latest Active that latest active component renders normally 1`] = `
<EuiBasicTable
columns={
Array [
Object {
"field": "range",
},
Object {
"dataType": "number",
"field": "count",
},
]
}
items={
Array [
Object {
"count": 5,
"range": "Last 1 minute",
},
Object {
"count": 5,
"range": "Last 5 minutes",
},
Object {
"count": 5,
"range": "Last 20 minutes",
},
Object {
"count": 6,
"range": "Last 1 hour",
},
Object {
"count": 10,
"range": "Last 1 day",
},
]
}
noItemsMessage="No items found"
responsive={true}
/>
`;

View file

@ -0,0 +1,35 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Latest Types that latest active component renders normally 1`] = `
<EuiBasicTable
columns={
Array [
Object {
"field": "type",
},
Object {
"dataType": "number",
"field": "count",
},
]
}
items={
Array [
Object {
"count": 4,
"type": "Packetbeat",
},
Object {
"count": 4,
"type": "Metricbeat",
},
Object {
"count": 2,
"type": "Heartbeat",
},
]
}
noItemsMessage="No items found"
responsive={true}
/>
`;

View file

@ -0,0 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Latest Versions that latest active component renders normally 1`] = `
<EuiBasicTable
columns={
Array [
Object {
"field": "version",
},
Object {
"dataType": "number",
"field": "count",
},
]
}
items={
Array [
Object {
"count": 8,
"version": "6.3.1",
},
Object {
"count": 2,
"version": "6.3.0",
},
]
}
noItemsMessage="No items found"
responsive={true}
/>
`;

View file

@ -0,0 +1,370 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Overview that overview page renders normally 1`] = `
<EuiPage
restrictWidth={false}
style={
Object {
"backgroundColor": "white",
}
}
>
<EuiPageBody
restrictWidth={false}
>
<EuiFlexGroup
alignItems="stretch"
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={true}
>
<EuiFlexItem
component="div"
grow={true}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<EuiTitle
size="s"
>
<h3>
Active Beats in Last Day
</h3>
</EuiTitle>
<EuiSpacer
size="s"
/>
<LatestActive
latestActive={
Array [
Object {
"count": 5,
"range": "last1m",
},
Object {
"count": 5,
"range": "last5m",
},
Object {
"count": 5,
"range": "last20m",
},
Object {
"count": 6,
"range": "last1h",
},
Object {
"count": 10,
"range": "last1d",
},
]
}
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<EuiTitle
size="s"
>
<h3>
Top 5 Beat Types in Last Day
</h3>
</EuiTitle>
<EuiSpacer
size="s"
/>
<LatestTypes
latestTypes={
Array [
Object {
"count": 4,
"type": "Packetbeat",
},
Object {
"count": 4,
"type": "Metricbeat",
},
Object {
"count": 2,
"type": "Heartbeat",
},
]
}
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<EuiTitle
size="s"
>
<h3>
Top 5 Versions in Last Day
</h3>
</EuiTitle>
<EuiSpacer
size="s"
/>
<LatestVersions
latestVersions={
Array [
Object {
"count": 8,
"version": "6.3.1",
},
Object {
"count": 2,
"version": "6.3.0",
},
]
}
/>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer
size="s"
/>
<Stats
stats={Array []}
/>
<EuiSpacer
size="s"
/>
<EuiFlexGroup
alignItems="stretch"
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={true}
>
<EuiFlexItem
component="div"
grow={true}
key="0"
style={
Object {
"minWidth": "45%",
}
}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<MonitoringTimeseriesContainer
series={1}
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
key="1"
style={
Object {
"minWidth": "45%",
}
}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<MonitoringTimeseriesContainer
series={1}
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
key="2"
style={
Object {
"minWidth": "45%",
}
}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<MonitoringTimeseriesContainer
series={1}
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
key="3"
style={
Object {
"minWidth": "45%",
}
}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<MonitoringTimeseriesContainer
series={1}
/>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageBody>
</EuiPage>
`;
exports[`Overview that overview page shows a message if there is no beats data 1`] = `
<EuiPage
restrictWidth={false}
style={
Object {
"backgroundColor": "white",
}
}
>
<EuiPageBody
restrictWidth={false}
>
<EuiCallOut
color="primary"
data-test-subj="noRecentActivityMessage"
iconType="gear"
size="m"
title="Hi there! This area is where your latest Beats activity would show
up, but you don't seem to have any activity within the last day."
/>
<EuiSpacer
size="s"
/>
<Stats
stats={Array []}
/>
<EuiSpacer
size="s"
/>
<EuiFlexGroup
alignItems="stretch"
component="div"
direction="row"
gutterSize="l"
justifyContent="flexStart"
responsive={true}
wrap={true}
>
<EuiFlexItem
component="div"
grow={true}
key="0"
style={
Object {
"minWidth": "45%",
}
}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<MonitoringTimeseriesContainer
series={1}
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
key="1"
style={
Object {
"minWidth": "45%",
}
}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<MonitoringTimeseriesContainer
series={1}
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
key="2"
style={
Object {
"minWidth": "45%",
}
}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<MonitoringTimeseriesContainer
series={1}
/>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem
component="div"
grow={true}
key="3"
style={
Object {
"minWidth": "45%",
}
}
>
<EuiPanel
grow={true}
hasShadow={false}
paddingSize="m"
>
<MonitoringTimeseriesContainer
series={1}
/>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
</EuiPageBody>
</EuiPage>
`;

View file

@ -5,12 +5,10 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import {
KuiTable,
KuiTableRow,
KuiTableRowCell,
KuiTableBody,
} from '@kbn/ui-framework/components';
EuiBasicTable
} from '@elastic/eui';
export function LatestActive({ latestActive }) {
const rangeMap = {
@ -21,20 +19,30 @@ export function LatestActive({ latestActive }) {
'last1d': 'Last 1 day',
};
const activity = latestActive.map(({ range, count }, index) => {
return (
<KuiTableRow key={`latest-active-${index}`}>
<KuiTableRowCell>{rangeMap[range]}</KuiTableRowCell>
<KuiTableRowCell align="right">{count}</KuiTableRowCell>
</KuiTableRow>
);
});
const activity = latestActive.map(({ range, count }) => ({
range: rangeMap[range],
count,
}));
return (
<KuiTable>
<KuiTableBody>
{activity}
</KuiTableBody>
</KuiTable>
<EuiBasicTable
items={activity}
columns={[
{
field: 'range',
},
{
field: 'count',
dataType: 'number',
}
]}
/>
);
}
LatestActive.propTypes = {
latestActive: PropTypes.arrayOf(PropTypes.shape({
range: PropTypes.string.isRequired,
count: PropTypes.number.isRequired,
})).isRequired
};

View file

@ -0,0 +1,30 @@
/*
* 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 { shallow } from 'enzyme';
import { LatestActive } from './latest_active';
describe('Latest Active', () => {
test('that latest active component renders normally', () => {
const latestActive = [
{ range: 'last1m', count: 5 },
{ range: 'last5m', count: 5 },
{ range: 'last20m', count: 5 },
{ range: 'last1h', count: 6 },
{ range: 'last1d', count: 10 },
];
const component = shallow(
<LatestActive
latestActive={latestActive}
/>
);
expect(component).toMatchSnapshot();
});
});

View file

@ -5,28 +5,31 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import {
KuiTable,
KuiTableRow,
KuiTableRowCell,
KuiTableBody,
} from '@kbn/ui-framework/components';
EuiBasicTable,
} from '@elastic/eui';
export function LatestTypes({ latestTypes }) {
const types = latestTypes.map(({ type, count }, index) => {
return (
<KuiTableRow key={`latest-types-${index}`}>
<KuiTableRowCell>{type}</KuiTableRowCell>
<KuiTableRowCell align="right">{count}</KuiTableRowCell>
</KuiTableRow>
);
});
return (
<KuiTable>
<KuiTableBody>
{types}
</KuiTableBody>
</KuiTable>
<EuiBasicTable
items={latestTypes}
columns={[
{
field: 'type',
},
{
field: 'count',
dataType: 'number',
}
]}
/>
);
}
LatestTypes.propTypes = {
latestTypes: PropTypes.arrayOf(PropTypes.shape({
type: PropTypes.string.isRequired,
count: PropTypes.number.isRequired,
})).isRequired,
};

View file

@ -0,0 +1,27 @@
/*
* 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 { shallow } from 'enzyme';
import { LatestTypes } from './latest_types';
describe('Latest Types', () => {
test('that latest active component renders normally', () => {
const latestTypes = [
{ type: 'Packetbeat', count: 4 },
{ type: 'Metricbeat', count: 4 },
{ type: 'Heartbeat', count: 2 }
];
const component = shallow(
<LatestTypes
latestTypes={latestTypes}
/>
);
expect(component).toMatchSnapshot();
});
});

View file

@ -5,28 +5,31 @@
*/
import React from 'react';
import PropTypes from 'prop-types';
import {
KuiTable,
KuiTableRow,
KuiTableRowCell,
KuiTableBody,
} from '@kbn/ui-framework/components';
EuiBasicTable,
} from '@elastic/eui';
export function LatestVersions({ latestVersions }) {
const versions = latestVersions.map(({ version, count }, index) => {
return (
<KuiTableRow key={`latest-version-${index}`}>
<KuiTableRowCell>{version}</KuiTableRowCell>
<KuiTableRowCell align="right">{count}</KuiTableRowCell>
</KuiTableRow>
);
});
return (
<KuiTable>
<KuiTableBody>
{versions}
</KuiTableBody>
</KuiTable>
<EuiBasicTable
items={latestVersions}
columns={[
{
field: 'version',
},
{
field: 'count',
dataType: 'number',
}
]}
/>
);
}
LatestVersions.propTypes = {
latestVersions: PropTypes.arrayOf(PropTypes.shape({
version: PropTypes.string.isRequired,
count: PropTypes.number.isRequired,
})).isRequired,
};

View file

@ -0,0 +1,26 @@
/*
* 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 { shallow } from 'enzyme';
import { LatestVersions } from './latest_versions';
describe('Latest Versions', () => {
test('that latest active component renders normally', () => {
const latestVersions = [
{ version: '6.3.1', count: 8 },
{ version: '6.3.0', count: 2 }
];
const component = shallow(
<LatestVersions
latestVersions={latestVersions}
/>
);
expect(component).toMatchSnapshot();
});
});

View file

@ -10,29 +10,43 @@ import { LatestVersions } from './latest_versions';
import { LatestTypes } from './latest_types';
import { Stats } from '../';
import { MonitoringTimeseriesContainer } from '../../chart';
import { EuiCallOut } from '@elastic/eui';
import {
EuiCallOut,
EuiTitle,
EuiSpacer,
EuiPage,
EuiFlexGroup,
EuiFlexItem,
EuiPageBody,
EuiPanel
} from '@elastic/eui';
function renderLatestActive(latestActive, latestTypes, latestVersions) {
if (latestTypes && latestTypes.length > 0) {
return (
<div className="page-row">
<div className="row">
<div className="col-md-4">
<h2 className="euiTitle">Active Beats in Last Day</h2>
<EuiFlexGroup wrap>
<EuiFlexItem>
<EuiPanel>
<EuiTitle size="s"><h3>Active Beats in Last Day</h3></EuiTitle>
<EuiSpacer size="s"/>
<LatestActive latestActive={latestActive} />
</div>
<div className="col-md-4">
<h2 className="euiTitle">Top 5 Beat Types in Last Day</h2>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel>
<EuiTitle size="s"><h3>Top 5 Beat Types in Last Day</h3></EuiTitle>
<EuiSpacer size="s"/>
<LatestTypes latestTypes={latestTypes} />
</div>
<div className="col-md-4">
<h2 className="euiTitle">Top 5 Versions in Last Day</h2>
</EuiPanel>
</EuiFlexItem>
<EuiFlexItem>
<EuiPanel>
<EuiTitle size="s"><h3>Top 5 Versions in Last Day</h3></EuiTitle>
<EuiSpacer size="s"/>
<LatestVersions latestVersions={latestVersions} />
</div>
</div>
</div>
</EuiPanel>
</EuiFlexItem>
</EuiFlexGroup>
);
}
@ -56,41 +70,35 @@ export function BeatsOverview({
metrics,
...props
}) {
const seriesToShow = [
metrics.beat_event_rates,
metrics.beat_fail_rates,
metrics.beat_throughput_rates,
metrics.beat_output_errors,
];
const charts = seriesToShow.map((data, index) => (
<EuiFlexItem style={{ minWidth: '45%' }} key={index}>
<EuiPanel>
<MonitoringTimeseriesContainer
series={data}
{...props}
/>
</EuiPanel>
</EuiFlexItem>
));
return (
<div>
{renderLatestActive(latestActive, latestTypes, latestVersions)}
<Stats stats={stats} />
<div className="page-row">
<div className="row">
<div className="col-md-6">
<MonitoringTimeseriesContainer
series={metrics.beat_event_rates}
{...props}
/>
</div>
<div className="col-md-6">
<MonitoringTimeseriesContainer
series={metrics.beat_fail_rates}
{...props}
/>
</div>
<div className="col-md-6">
<MonitoringTimeseriesContainer
series={metrics.beat_throughput_rates}
{...props}
/>
</div>
<div className="col-md-6">
<MonitoringTimeseriesContainer
series={metrics.beat_output_errors}
{...props}
/>
</div>
</div>
</div>
</div>
<EuiPage style={{ backgroundColor: 'white' }}>
<EuiPageBody>
{renderLatestActive(latestActive, latestTypes, latestVersions)}
<EuiSpacer size="s"/>
<Stats stats={stats} />
<EuiSpacer size="s"/>
<EuiFlexGroup wrap>
{charts}
</EuiFlexGroup>
</EuiPageBody>
</EuiPage>
);
}

View file

@ -0,0 +1,74 @@
/*
* 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 { shallow } from 'enzyme';
jest.mock('../stats', () => ({
Stats: () => 'Stats',
}));
jest.mock('../../', () => ({
MonitoringTimeseriesContainer: () => 'MonitoringTimeseriesContainer',
}));
import { BeatsOverview } from './overview';
describe('Overview', () => {
test('that overview page renders normally', () => {
const latestActive = [
{ range: 'last1m', count: 5 },
{ range: 'last5m', count: 5 },
{ range: 'last20m', count: 5 },
{ range: 'last1h', count: 6 },
{ range: 'last1d', count: 10 },
];
const latestTypes = [
{ type: 'Packetbeat', count: 4 },
{ type: 'Metricbeat', count: 4 },
{ type: 'Heartbeat', count: 2 }
];
const latestVersions = [
{ version: '6.3.1', count: 8 },
{ version: '6.3.0', count: 2 }
];
const metrics = {
beat_event_rates: 1,
beat_fail_rates: 1,
beat_throughput_rates: 1,
beat_output_errors: 1
};
const component = shallow(
<BeatsOverview
latestActive={latestActive}
latestTypes={latestTypes}
latestVersions={latestVersions}
stats={[]}
metrics={metrics}
/>
);
expect(component).toMatchSnapshot();
});
test('that overview page shows a message if there is no beats data', () => {
const metrics = {
beat_event_rates: 1,
beat_fail_rates: 1,
beat_throughput_rates: 1,
beat_output_errors: 1
};
const component = shallow(
<BeatsOverview
stats={[]}
metrics={metrics}
/>
);
expect(component).toMatchSnapshot();
});
});