Added service images widget

This commit is contained in:
jpellizzari
2017-04-26 14:49:48 -07:00
parent 95660e3da7
commit 3ec7cc82e6
10 changed files with 288 additions and 2 deletions

View File

@@ -0,0 +1,34 @@
import React from 'react';
import { connect } from 'react-redux';
class CloudFeature extends React.Component {
getChildContext() {
return {
store: this.context.serviceStore || this.context.store
};
}
render() {
if (process.env.WEAVE_CLOUD) {
return React.cloneElement(React.Children.only(this.props.children), {
params: this.context.router.params,
router: this.context.router
});
}
return null;
}
}
CloudFeature.contextTypes = {
store: React.PropTypes.object.isRequired,
router: React.PropTypes.object,
serviceStore: React.PropTypes.object
};
CloudFeature.childContextTypes = {
store: React.PropTypes.object,
router: React.PropTypes.object
};
export default connect()(CloudFeature);

View File

@@ -18,6 +18,8 @@ import NodeDetailsInfo from './node-details/node-details-info';
import NodeDetailsRelatives from './node-details/node-details-relatives';
import NodeDetailsTable from './node-details/node-details-table';
import Warning from './warning';
import CloudFeature from './cloud-feature';
import NodeDetailsImageStatus from './node-details/node-details-image-status';
const log = debug('scope:node-details');
@@ -230,6 +232,9 @@ class NodeDetails extends React.Component {
}
return null;
})}
<CloudFeature>
<NodeDetailsImageStatus name={details.label} metadata={details.metadata} />
</CloudFeature>
</div>
</div>
);

View File

@@ -0,0 +1,122 @@
import React from 'react';
import { connect } from 'react-redux';
import find from 'lodash/find';
import map from 'lodash/map';
import { CircularProgress } from 'weaveworks-ui-components';
import { getImagesForService } from '../../actions/app-actions';
const topologyWhitelist = ['services', 'deployments'];
function getNewImages(images, currentId) {
// Assume that the current image is always in the list of all available images.
// Should be a safe assumption...
const current = find(images, i => i.ID === currentId);
const timestamp = new Date(current.CreatedAt);
return find(images, i => timestamp < new Date(i.CreatedAt)) || [];
}
class NodeDetailsImageStatus extends React.PureComponent {
constructor(props, context) {
super(props, context);
this.handleServiceClick = this.handleServiceClick.bind(this);
}
componentDidMount() {
if (this.shouldRender() && this.props.serviceId) {
this.props.getImagesForService(this.props.params.orgId, this.props.serviceId);
}
}
handleServiceClick() {
const { router, serviceId, params } = this.props;
router.push(`/flux/${params.orgId}/services/${encodeURIComponent(serviceId)}`);
}
shouldRender() {
const { currentTopologyId } = this.props;
return currentTopologyId && topologyWhitelist.includes(currentTopologyId);
}
renderImages() {
const { errors, containers, isFetching } = this.props;
const error = !isFetching && errors;
if (isFetching) {
return (
<div className="progress-wrapper"><CircularProgress /></div>
);
}
if (error) {
return (
<p>Error: {JSON.stringify(map(errors, 'message'))}</p>
);
}
if (!containers) {
return 'No service images found';
}
return (
<div className="images">
{containers.map((container) => {
const statusText = getNewImages(container.Available, container.Current.ID).length > 0
? <span className="new-image">New image(s) available</span>
: 'Image up to date';
return (
<div key={container.Name} className="wrapper">
<div className="node-details-table-node-label">{container.Name}</div>
<div className="node-details-table-node-value">{statusText}</div>
</div>
);
})}
</div>
);
}
render() {
const { containers } = this.props;
if (!this.shouldRender()) {
return null;
}
return (
<div className="node-details-content-section image-status">
<div className="node-details-content-section-header">
Container Image Status
{containers &&
<div>
<a
onClick={this.handleServiceClick}
className="node-details-table-node-link">
View in Deploy
</a>
</div>
}
</div>
{this.renderImages()}
</div>
);
}
}
function mapStateToProps({ scope }, { metadata, name }) {
const namespace = find(metadata, d => d.id === 'kubernetes_namespace');
const serviceId = namespace ? `${namespace.value}/${name}` : null;
const { containers, isFetching, errors } = scope.getIn(['serviceImages', serviceId]) || {};
return {
isFetching,
errors,
currentTopologyId: scope.get('currentTopologyId'),
containers,
serviceId
};
}
export default connect(mapStateToProps, { getImagesForService })(NodeDetailsImageStatus);