fix inconsistent deployment count on servicemesh page (#69)

* fix inconsistent deployment count on servicemesh page.
* tests added for deploy count messaging on servicemesh page
* refactored code for Call To Action component to use 'instructions' in util
* refactored correlating css
This commit is contained in:
Franziska von der Goltz 2017-12-19 14:53:47 -08:00 committed by GitHub
parent 683b5c0dd6
commit 3591936de3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 151 additions and 49 deletions

View File

@ -4,24 +4,15 @@
.call-to-action {
padding: 16px 0;
& .action {
font-size: 14px;
font-weight: var(--font-weight-bold);
padding: 8px 0;
& code {
background-color: rgba(47, 128, 237, 1);
color: white;
font-size: .9rem;
letter-spacing: 0px;
padding: 4px 8px;
border-radius: 4px;
}
& code {
background-color: rgba(47, 128, 237, 1);
color: white;
font-size: .9rem;
letter-spacing: 0px;
padding: 4px 8px;
border-radius: 4px;
}
& .summary {
color: #27AE60;

View File

@ -15,12 +15,6 @@
width: 131px;
}
.instructions {
font-size: 14px;
font-weight: var(--font-weight-bold);
padding: 8px 0;
}
.incomplete-mesh-message, .complete-mesh-message {
background-color: var(--messageblue);
color: white;

View File

@ -137,6 +137,12 @@ tr th.numeric, .numeric {
color: var(--subheader-grey);
}
.action {
font-size: 14px;
font-weight: var(--font-weight-bold);
padding: 8px 0;
}
/* fancy borders */
.border-container {
padding: var(--base-width);
@ -158,4 +164,4 @@ tr th.numeric, .numeric {
}
.border-container.border-neutral {
background-image: url(./../img/grey_check.png);
}
}

View File

@ -1,3 +1,4 @@
import { instructions } from './util/Utils.js';
import React from 'react';
import { Col, Row } from 'antd';
import './../../css/cta.css';
@ -39,8 +40,7 @@ export default class CallToAction extends React.Component {
</Row>
</div>
<div className="action">Next, add one or more deployments to the deployment.yml file</div>
<div className="action">Then run <code>conduit inject deployment.yml | kubectl apply -f -</code> to add deploys to the service mesh</div>
{instructions}
</div>
);
}

View File

@ -4,9 +4,9 @@ import ConduitSpinner from "./ConduitSpinner.jsx";
import DeploymentSummary from './DeploymentSummary.jsx';
import Metric from './Metric.jsx';
import React from 'react';
import { rowGutter } from './util/Utils.js';
import StatusTable from './StatusTable.jsx';
import { Col, Row, Table } from 'antd';
import { instructions, rowGutter } from './util/Utils.js';
import { processRollupMetrics, processTimeseriesMetrics } from './util/MetricUtils.js';
import './../../css/service-mesh.css';
import 'whatwg-fetch';
@ -86,7 +86,7 @@ export default class ServiceMesh extends React.Component {
let timeseriesRequest = fetch(timeseriesPath).then(r => r.json());
let podsRequest = fetch(podsPath).then(r => r.json());
Promise.all([rollupRequest, timeseriesRequest, podsRequest])
this.serverPromise = Promise.all([rollupRequest, timeseriesRequest, podsRequest])
.then(([metrics, ts, pods]) => {
let m = processRollupMetrics(metrics.metrics, "component");
let tsByComponent = processTimeseriesMetrics(ts.metrics, "component");
@ -108,13 +108,13 @@ export default class ServiceMesh extends React.Component {
}
addedDeploymentCount() {
return _.size(_.find(this.state.deploys, d => {
return _.size(_.filter(this.state.deploys, d => {
return _.every(d.pods, ["value", "good"]);
}));
}
unaddedDeploymentCount() {
return _.size(this.state.deploys) - this.addedDeploymentCount();
return this.deployCount() - this.addedDeploymentCount();
}
proxyCount() {
@ -127,6 +127,10 @@ export default class ServiceMesh extends React.Component {
return _.size(this.state.components);
}
deployCount() {
return _.size(this.state.deploys);
}
getServiceMeshDetails() {
return [
{ key: 1, name: "Conduit version", value: this.props.releaseVersion },
@ -218,7 +222,7 @@ export default class ServiceMesh extends React.Component {
<div className="clearfix header-with-metric">
<div className="subsection-header">Data plane</div>
<Metric title="Proxies" value={this.proxyCount()} className="metric-large" />
<Metric title="Deployments" value={_.size(this.state.deploys)} className="metric-large" />
<Metric title="Deployments" value={this.deployCount()} className="metric-large" />
</div>
<StatusTable
@ -249,26 +253,34 @@ export default class ServiceMesh extends React.Component {
}
renderAddDeploymentsMessage() {
return (
<div className="mesh-message">
{this.unaddedDeploymentCount() === 0 ?
if (this.deployCount() === 0) {
return (
<div className="incomplete-mesh-message">
No deployments detected. {instructions}
</div>
);
} else {
switch (this.unaddedDeploymentCount()) {
case 0:
return (
<div className="complete-mesh-message">
All deployments have been added to the service mesh.
</div>
: this.unaddedDeploymentCount() === 1 ?
<div className="incomplete-mesh-message">
1 deployment has not been added to the service mesh.
<div className="instructions">Add the remaining deployment to the deployment.yml file</div>
<div className="instructions">Then run <code>conduit inject deployment.yml | kubectl apply -f - </code> to add the deployment to the service mesh</div>
</div>
: <div className="incomplete-mesh-message">
{this.unaddedDeploymentCount()} deployments have not been added to the service mesh.
<div className="instructions">Next, add one or more deployments to the deployment.yml file</div>
<div className="instructions">Then run <code>conduit inject deployment.yml | kubectl apply -f -</code> to add deploys to the service mesh</div>
</div>
}
</div>
);
);
case 1:
return (
<div className="incomplete-mesh-message">
1 deployment has not been added to the service mesh. {instructions}
</div>
);
default:
return (
<div className="incomplete-mesh-message">
{this.unaddedDeploymentCount()} deployments have not been added to the service mesh. {instructions}
</div>
);
}
}
}
renderControlPlane() {
@ -291,7 +303,7 @@ export default class ServiceMesh extends React.Component {
renderOverview() {
if (this.proxyCount() === 0) {
return <CallToAction numDeployments={_.size(this.state.metrics)} />;
return <CallToAction numDeployments={this.deployCount()} />;
} else {
return this.renderControllerHealth();
}

View File

@ -1,4 +1,5 @@
import _ from 'lodash';
import React from 'react';
import * as d3 from 'd3';
/*
@ -74,3 +75,11 @@ export const toClassName = name => {
if (!name) return "";
return _.lowerCase(name).replace(/[^a-zA-Z0-9]/g, "_");
};
/*
* Instructions for adding deployments to service mesh
*/
export const instructions = (
<div className="action">Add one or more deployments to the deployment.yml file <br /><br />
Then run <code>conduit inject deployment.yml | kubectl apply -f - </code> to add deploys to the service mesh</div>
);

View File

@ -52,4 +52,4 @@
"style-loader": "^0.18.2",
"url-loader": "^0.6.2"
}
}
}

View File

@ -0,0 +1,78 @@
import _ from 'lodash';
import { expect } from 'chai';
import { mount } from 'enzyme';
import podFixtures from './fixtures/pods.json';
import { routerWrap } from './testHelpers.jsx';
import ServiceMesh from '../js/components/ServiceMesh.jsx';
import sinon from 'sinon';
import sinonStubPromise from 'sinon-stub-promise';
sinonStubPromise(sinon);
describe('ServiceMesh', () => {
let component, fetchStub;
function withPromise(fn) {
return component.find("ServiceMesh").get(0).serverPromise.then(fn);
}
beforeEach(() => {
fetchStub = sinon.stub(window, 'fetch');
});
afterEach(() => {
window.fetch.restore();
});
it("displays message for no deployments detetcted", () => {
fetchStub.returnsPromise().resolves({
json: () => Promise.resolve({ pods: []})
});
component = mount(routerWrap(ServiceMesh));
return withPromise(() => {
expect(component.html()).includes("No deployments detected.");
});
});
it("displays message for more than one deployment added to servicemesh", () => {
fetchStub.returnsPromise().resolves({
json: () => Promise.resolve({ pods: podFixtures.pods})
});
component = mount(routerWrap(ServiceMesh));
return withPromise(() => {
expect(component.html()).includes("deployments have not been added to the service mesh.");
});
});
it("displays message for only one deployment not added to servicemesh", () => {
let addedPods = _.clone(podFixtures.pods);
_.set(addedPods[0], "added", true);
fetchStub.returnsPromise().resolves({
json: () => Promise.resolve({ pods: addedPods})
});
component = mount(routerWrap(ServiceMesh));
return withPromise(() => {
expect(component.html()).includes("1 deployment has not been added to the service mesh.");
});
});
it("displays message for all deployments added to servicemesh", () => {
let addedPods = _.clone(podFixtures.pods);
_.forEach(addedPods, pod => {
_.set(pod, "added", true);
});
fetchStub.returnsPromise().resolves({
json: () => Promise.resolve({ pods: addedPods})
});
component = mount(routerWrap(ServiceMesh));
return withPromise(() => {
expect(component.html()).includes("All deployments have been added to the service mesh.");
});
});
});

View File

@ -0,0 +1,12 @@
import _ from 'lodash';
import { createMemoryHistory } from 'history';
import React from 'react';
import { Route, Router } from 'react-router';
export function routerWrap(Component, extraProps={}, route="/", currentLoc="/") {
return (
<Router history={createMemoryHistory(currentLoc)} createElement={(Component, props) => <Component {...(_.merge({}, props, extraProps))} />}>
<Route path={route} component={Component} />
</Router>
);
}