Add display chips to the resource detail page to provide more detail (#2063)

* Simplify syntax for state variable access

* Add a warning chip if a resource isn't receiving traffic
Also add a meshed chip to the resource detail pages
This commit is contained in:
Risha Mars 2019-01-17 13:58:15 -08:00 committed by GitHub
parent 53f8bb5a15
commit 2adcdfbca8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 74 additions and 27 deletions

View File

@ -167,7 +167,7 @@ class NamespaceLanding extends React.Component {
let hr = (
<Grid container justify="space-between" alignItems="center">
<Grid item><Typography variant="subtitle1">{ns.name}</Typography></Grid>
{!ns.added ? null : <Grid item><SimpleChip /></Grid> }
{!ns.added ? null : <Grid item><SimpleChip label="meshed" type="good" /></Grid> }
</Grid>
);
return {

View File

@ -1,14 +1,14 @@
import 'whatwg-fetch';
import { emptyMetric, processSingleResourceRollup } from './util/MetricUtils.jsx';
import { resourceTypeToCamelCase, singularResource } from './util/Utils.js';
import AddResources from './AddResources.jsx';
import ErrorBanner from './ErrorBanner.jsx';
import Grid from '@material-ui/core/Grid';
import MetricsTable from './MetricsTable.jsx';
import Octopus from './Octopus.jsx';
import PropTypes from 'prop-types';
import React from 'react';
import SimpleChip from './util/Chip.jsx';
import Spinner from './util/Spinner.jsx';
import TopRoutesTabs from './TopRoutesTabs.jsx';
import Typography from '@material-ui/core/Typography';
@ -21,6 +21,9 @@ import _reduce from 'lodash/reduce';
import { processNeighborData } from './util/TapUtils.jsx';
import { withContext } from './util/AppContext.jsx';
// if there has been no traffic for some time, show a warning
const showNoTrafficMsgDelayMs = 6000;
const getResourceFromUrl = (match, pathPrefix) => {
let resource = {
namespace: match.params.namespace
@ -64,12 +67,13 @@ export class ResourceDetailBase extends React.Component {
resourceName: resource.name,
resourceType: resource.type,
resource,
lastMetricReceivedTime: Date.now(),
pollingInterval: 2000,
resourceMetrics: [],
podMetrics: [], // metrics for all pods whose owner is this resource
neighborMetrics: {
upstream: {},
downstream: {}
upstream: [],
downstream: []
},
unmeshedSources: {},
resourceIsMeshed: true,
@ -152,6 +156,11 @@ export class ResourceDetailBase extends React.Component {
resourceIsMeshed = _get(this.state.resourceMetrics, '[0].pods.meshedPods') > 0;
}
let lastMetricReceivedTime = this.state.lastMetricReceivedTime;
if (!_isEmpty(resourceMetrics[0]) && resourceMetrics[0].totalRequests !== 0) {
lastMetricReceivedTime = Date.now();
}
this.setState({
resourceMetrics,
resourceIsMeshed,
@ -160,6 +169,7 @@ export class ResourceDetailBase extends React.Component {
upstream: upstreamMetrics,
downstream: downstreamMetrics
},
lastMetricReceivedTime,
loaded: true,
pendingRequests: false,
error: null,
@ -200,14 +210,24 @@ export class ResourceDetailBase extends React.Component {
return <Spinner />;
}
let { resourceName, resourceType, namespace } = this.state;
let {
resourceName,
resourceType,
namespace,
resourceMetrics,
unmeshedSources,
resourceIsMeshed,
neighborMetrics,
lastMetricReceivedTime
} = this.state;
let query = {
resourceName,
resourceType,
namespace
};
let unmeshed = _filter(this.state.unmeshedSources, d => d.type === this.state.resourceType)
let unmeshed = _filter(unmeshedSources, d => d.type === resourceType)
.map(d => _merge({}, emptyMetric, d, {
unmeshed: true,
pods: {
@ -216,31 +236,47 @@ export class ResourceDetailBase extends React.Component {
}
}));
let upstreams = this.state.neighborMetrics.upstream.concat(unmeshed);
let upstreams = neighborMetrics.upstream.concat(unmeshed);
let showNoTrafficMsg = resourceIsMeshed && (Date.now() - lastMetricReceivedTime > showNoTrafficMsgDelayMs);
return (
<div>
<Grid container justify="space-between" alignItems="center">
<Grid item><Typography variant="h5">{resourceType}/{resourceName}</Typography></Grid>
<Grid item>
<Grid container spacing={8}>
{ showNoTrafficMsg ? <Grid item><SimpleChip label="no traffic" type="warning" /></Grid> : null }
<Grid item>
{ resourceIsMeshed ?
<SimpleChip label="meshed" type="good" /> :
<SimpleChip label="unmeshed" type="bad" />
}
</Grid>
</Grid>
</Grid>
</Grid>
{
this.state.resourceIsMeshed ? null :
resourceIsMeshed ? null :
<React.Fragment>
<AddResources
resourceName={this.state.resourceName}
resourceType={this.state.resourceType} />
resourceName={resourceName}
resourceType={resourceType} />
</React.Fragment>
}
<Octopus
resource={this.state.resourceMetrics[0]}
neighbors={this.state.neighborMetrics}
unmeshedSources={Object.values(this.state.unmeshedSources)}
resource={resourceMetrics[0]}
neighbors={neighborMetrics}
unmeshedSources={Object.values(unmeshedSources)}
api={this.api} />
<TopRoutesTabs
query={query}
pathPrefix={this.props.pathPrefix}
updateNeighborsFromTapData={this.updateNeighborsFromTapData}
disableTop={!this.state.resourceIsMeshed} />
disableTop={!resourceIsMeshed} />
{ _isEmpty(upstreams) ? null : (
<React.Fragment>

View File

@ -3,25 +3,36 @@ import PropTypes from 'prop-types';
import React from 'react';
import { withStyles } from '@material-ui/core/styles';
const styles = () => ({
root: {
display: 'flex',
justifyContent: 'center',
flexWrap: 'wrap',
const styles = theme => ({
good: {
color: theme.status.dark.good,
border: '1px solid ' + theme.status.dark.good
},
warning: {
color: theme.status.dark.warning,
border: '1px solid ' + theme.status.dark.warning,
},
bad: {
color: theme.status.dark.danger,
border: '1px solid ' + theme.status.dark.danger,
}
});
function SimpleChip(props) {
const { classes } = props;
const { classes, label, type } = props;
return (
<div className={classes.root}>
<Chip className={classes.chip} color="primary" label="meshed" variant="outlined" />
</div>
<Chip
className={classes[type]}
label={label}
variant="outlined" />
);
}
SimpleChip.propTypes = {
classes: PropTypes.shape({}).isRequired
classes: PropTypes.shape({}).isRequired,
label: PropTypes.string.isRequired,
type: PropTypes.string.isRequired
};
export default withStyles(styles)(SimpleChip);
export default withStyles(styles, { withTheme: true })(SimpleChip);