import _ from 'lodash'; import OctopusArms from './util/OctopusArms.jsx'; import PropTypes from 'prop-types'; import React from 'react'; import { Col, Progress, Row } from 'antd'; import { displayName, metricToFormatter } from './util/Utils.js'; import { getSuccessRateClassification, srArcClassLabels } from './util/MetricUtils.jsx' ; import './../../css/octopus.css'; const maxNumNeighbors = 6; // max number of neighbor nodes to show in the octopus graph const Metric = ({title, value, className}) => { return (
{title}
{value}
); }; Metric.defaultProps = { className: "" }; Metric.propTypes = { className: PropTypes.string, title: PropTypes.string.isRequired, value: PropTypes.string.isRequired }; export default class Octopus extends React.Component { static defaultProps = { neighbors: {}, resource: {}, unmeshedSources: [] } static propTypes = { neighbors: PropTypes.shape({}), resource: PropTypes.shape({}), unmeshedSources: PropTypes.arrayOf(PropTypes.shape({})), } getNeighborDisplayData = neighbors => { // only display maxNumNeighbors neighboring nodes in the octopus graph, // otherwise it will be really tall let upstreams = _.sortBy(neighbors.upstream, "resource.successRate"); let downstreams = _.sortBy(neighbors.downstream, "resource.successRate"); let display = { upstreams: { displayed: upstreams, collapsed: [] }, downstreams: { displayed: downstreams, collapsed: [] } }; if (_.size(upstreams) > maxNumNeighbors) { display.upstreams.displayed = _.take(upstreams, maxNumNeighbors); display.upstreams.collapsed = _.slice(upstreams, maxNumNeighbors, _.size(upstreams)); } if (_.size(downstreams) > maxNumNeighbors) { display.downstreams.displayed = _.take(downstreams, maxNumNeighbors); display.downstreams.collapsed = _.slice(downstreams, maxNumNeighbors, _.size(downstreams)); } return display; } linkedResourceTitle = (resource, display) => { return _.isNil(resource.namespace) ? display : ; } renderResourceSummary(resource, type) { let display = displayName(resource); return (
{ this.linkedResourceTitle(resource, display) }
metricToFormatter["SUCCESS_RATE"](resource.successRate)} width={type === "main" ? 132 : 64} percent={resource.successRate * 100} gapDegree={180} />
); } renderUnmeshedResources = unmeshedResources => { return (
Unmeshed
{ _.map(unmeshedResources, r => { let display = displayName(r); return
{display}
; }) }
); } renderCollapsedNeighbors = neighbors => { return (
{ _.map(neighbors, r => { let display = displayName(r); return
{this.linkedResourceTitle(r, display)}
; }) }
); } renderArrowCol = (numNeighbors, isOutbound) => { let baseHeight = 180; let width = 75; let showArrow = numNeighbors > 0; let isEven = numNeighbors % 2 === 0; let middleElementIndex = isEven ? ((numNeighbors - 1) / 2) : _.floor(numNeighbors / 2); let arrowTypes = _.map(_.times(numNeighbors), i => { if (i < middleElementIndex) { let height = (_.ceil(middleElementIndex - i) - 1) * baseHeight + (baseHeight / 2); return { type: "up", inboundType: "down", height }; } else if (i === middleElementIndex) { return { type: "flat", inboundType: "flat", height: baseHeight }; } else { let height = (_.ceil(i - middleElementIndex) - 1) * baseHeight + (baseHeight / 2); return { type: "down", inboundType: "up", height }; } }); let height = numNeighbors * baseHeight; let svg = ( { _.map(arrowTypes, arrow => { let arrowType = isOutbound ? arrow.type : arrow.inboundType; return OctopusArms[arrowType](width, height, arrow.height, isOutbound); }) } ); return !showArrow ? null : svg; } render() { let { resource, neighbors, unmeshedSources } = this.props; if (_.isEmpty(resource)) { return null; } let display = this.getNeighborDisplayData(neighbors); let numUpstreams = _.size(display.upstreams.displayed) + (_.isEmpty(unmeshedSources) ? 0 : 1) + (_.isEmpty(display.upstreams.collapsed) ? 0 : 1); let hasUpstreams = numUpstreams > 0; let numDownstreams = _.size(display.downstreams.displayed) + (_.isEmpty(display.downstreams.collapsed) ? 0 : 1); let hasDownstreams = numDownstreams > 0; return (
{_.map(display.upstreams.displayed, n => this.renderResourceSummary(n, "neighbor"))} {_.isEmpty(unmeshedSources) ? null : this.renderUnmeshedResources(unmeshedSources)} {_.isEmpty(display.upstreams.collapsed) ? null : this.renderCollapsedNeighbors(display.upstreams.collapsed)} {this.renderArrowCol(numUpstreams, false)} {this.renderResourceSummary(resource, "main")} {this.renderArrowCol(numDownstreams, true)} {_.map(display.downstreams.displayed, n => this.renderResourceSummary(n, "neighbor"))} {_.isEmpty(display.downstreams.collapsed) ? null : this.renderCollapsedNeighbors(display.downstreams.collapsed)}
); } }