feat(ui-toolkit, cp-frontend): Display statuses on topology view
This commit is contained in:
parent
6651208b2e
commit
05d0420813
@ -15,24 +15,18 @@ const StyledStatusContainer = styled.div`
|
||||
height: ${remcalc(54)}
|
||||
`;
|
||||
|
||||
const InstanceStatuses = ({ instances }) => {
|
||||
const statuses = instances.reduce((statuses, instance) => {
|
||||
if (instance.status !== 'RUNNING') {
|
||||
if (statuses[instance.status]) {
|
||||
statuses[instance.status]++;
|
||||
} else {
|
||||
statuses[instance.status] = 1;
|
||||
}
|
||||
}
|
||||
return statuses;
|
||||
}, {});
|
||||
const InstanceStatuses = ({ instanceStatuses }) => {
|
||||
|
||||
const statuses = instanceStatuses.map(instanceStatus => {
|
||||
const {
|
||||
status,
|
||||
count
|
||||
} = instanceStatus;
|
||||
|
||||
const instanceStatuses = Object.keys(statuses).map(status => {
|
||||
const instances = statuses[status];
|
||||
return (
|
||||
<StyledStatus>
|
||||
{`${instances}
|
||||
${instances > 1 ? 'instances' : 'instance'}
|
||||
{`${count}
|
||||
${count > 1 ? 'instances' : 'instance'}
|
||||
${status.toLowerCase()}`}
|
||||
</StyledStatus>
|
||||
);
|
||||
@ -40,13 +34,13 @@ const InstanceStatuses = ({ instances }) => {
|
||||
|
||||
return (
|
||||
<StyledStatusContainer>
|
||||
{instanceStatuses}
|
||||
{statuses}
|
||||
</StyledStatusContainer>
|
||||
);
|
||||
};
|
||||
|
||||
InstanceStatuses.propTypes = {
|
||||
instances: PropTypes.array.isRequired
|
||||
instanceStatuses: PropTypes.array.isRequired
|
||||
};
|
||||
|
||||
export default InstanceStatuses;
|
||||
|
@ -96,7 +96,8 @@ const ServiceListItem = ({
|
||||
</CardDescription>
|
||||
<CardOptions onClick={handleCardOptionsClick} />
|
||||
</StyledCardHeader>;
|
||||
|
||||
console.log('*** service = ', service);
|
||||
console.log('*** service.instanceStatuses = ', service.instanceStatuses);
|
||||
const view = children
|
||||
? <CardGroupView>
|
||||
{children}
|
||||
@ -105,7 +106,7 @@ const ServiceListItem = ({
|
||||
{isChild && title}
|
||||
{isChild && subtitle}
|
||||
<CardDescription>
|
||||
<InstanceStatuses instances={service.instances} />
|
||||
<InstanceStatuses instanceStatuses={service.instanceStatuses} />
|
||||
<CardInfo
|
||||
icon={<HealthyIcon />}
|
||||
iconPosition="left"
|
||||
|
@ -73,10 +73,20 @@ const ServicesTopology = ({
|
||||
startServices(service.id);
|
||||
};
|
||||
|
||||
const handleScaleClick = (evt, service) => {
|
||||
toggleServicesQuickActions({ show: false });
|
||||
push(`${url}/${service.slug}/delete`);
|
||||
};
|
||||
|
||||
const handleDeleteClick = (evt, service) => {
|
||||
toggleServicesQuickActions({ show: false });
|
||||
push(`${url}/${service.slug}/scale`);
|
||||
};
|
||||
|
||||
const handleNodeTitleClick = (evt, { service }) => {
|
||||
push(`${url.split('/').slice(0, 3).join('/')}/services/${service.slug}`);
|
||||
};
|
||||
|
||||
console.log('ServicesTopology services = ', services);
|
||||
return (
|
||||
<StyledBackground>
|
||||
<StyledContainer>
|
||||
@ -89,11 +99,12 @@ const ServicesTopology = ({
|
||||
service={servicesQuickActions.service}
|
||||
show={servicesQuickActions.show}
|
||||
position={servicesQuickActions.position}
|
||||
url={url}
|
||||
onBlur={handleTooltipBlur}
|
||||
onRestartClick={handleRestartClick}
|
||||
onStopClick={handleStopClick}
|
||||
onStartClick={handleStartClick}
|
||||
onScaleClick={handleScaleClick}
|
||||
onDeleteClick={handleDeleteClick}
|
||||
/>
|
||||
</StyledContainer>
|
||||
</StyledBackground>
|
||||
|
@ -10,6 +10,7 @@ query Instances($deploymentGroupSlug: String!){
|
||||
connections
|
||||
instances {
|
||||
id
|
||||
status
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -59,10 +59,30 @@ const instancesByServiceId = serviceId =>
|
||||
const findService = (services, uuid) =>
|
||||
services.reduce((service, s) => (s.uuid === uuid ? s : service), null);
|
||||
|
||||
const getInstanceStatuses = (service) => {
|
||||
|
||||
const instanceStatuses = service.instances.reduce((statuses, instance) => {
|
||||
if (instance.status !== 'RUNNING') {
|
||||
if (statuses[instance.status]) {
|
||||
statuses[instance.status]++;
|
||||
} else {
|
||||
statuses[instance.status] = 1;
|
||||
}
|
||||
}
|
||||
return statuses;
|
||||
}, {});
|
||||
|
||||
return Object.keys(instanceStatuses).map(status => ({
|
||||
status,
|
||||
count: instanceStatuses[status]
|
||||
}));
|
||||
}
|
||||
|
||||
const getService = (service, index, datacenter) => ({
|
||||
index,
|
||||
...service,
|
||||
datacenter,
|
||||
instanceStatuses: getInstanceStatuses(service),
|
||||
isConsul: service.slug === 'consul'
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
const Lengths = {
|
||||
paddingLeft: 12,
|
||||
nodeWidth: 180
|
||||
nodeWidth: 180,
|
||||
statusHeight: 18
|
||||
};
|
||||
|
||||
const Sizes = {
|
||||
@ -68,12 +69,14 @@ const Rects = {
|
||||
},
|
||||
// Top, bottom, left, right - from 'centre'
|
||||
nodeRect: {
|
||||
...Sizes.nodeSize,
|
||||
left: -Sizes.nodeSize.width / 2,
|
||||
right: Sizes.nodeSize.width / 2,
|
||||
top: -Sizes.nodeSize.height / 2,
|
||||
bottom: Sizes.nodeSize.height / 2
|
||||
},
|
||||
nodeRectWithChildren: {
|
||||
...Sizes.nodeSizeWithChildren,
|
||||
left: -Sizes.nodeSizeWithChildren.width / 2,
|
||||
right: Sizes.nodeSizeWithChildren.width / 2,
|
||||
top: -Sizes.nodeSizeWithChildren.height / 2 + Sizes.contentSize.height / 3,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Constants from '../constants';
|
||||
import Constants from './constants';
|
||||
|
||||
const getAngleFromPoints = (source, target) => {
|
||||
const lineAngle = Math.atan2(target.y - source.y, target.x - source.x);
|
||||
@ -70,23 +70,20 @@ const getPositions = (rect, halfCorner = 0) => [
|
||||
}
|
||||
];
|
||||
|
||||
const getRect = data =>
|
||||
data.children ? Constants.nodeRectWithChildren : Constants.nodeRect;
|
||||
/* const getRect = data =>
|
||||
data.children ? Constants.nodeRectWithChildren : Constants.nodeRect; */
|
||||
|
||||
const calculateLineLayout = ({ source, target }) => {
|
||||
// Actually, this will need to be got dynamically, in case them things are different sizes
|
||||
// yeah right, now you'll get to do exactly that
|
||||
|
||||
const sourceRect = getRect(source);
|
||||
const targetRect = getRect(target);
|
||||
|
||||
const halfCorner = 2;
|
||||
|
||||
const sourcePositions = getPositions(sourceRect, halfCorner);
|
||||
const sourcePositions = getPositions(source.nodeRect, halfCorner);
|
||||
const sourceAngle = getAngleFromPoints(source, target);
|
||||
const sourcePosition = getPosition(sourceAngle, sourcePositions, source);
|
||||
|
||||
const targetPositions = getPositions(targetRect, halfCorner);
|
||||
const targetPositions = getPositions(target.nodeRect, halfCorner);
|
||||
const targetAngle = getAngleFromPoints(target, sourcePosition);
|
||||
const targetPosition = getPosition(targetAngle, targetPositions, target); // , true);
|
||||
|
||||
@ -101,4 +98,30 @@ const calculateLineLayout = ({ source, target }) => {
|
||||
};
|
||||
};
|
||||
|
||||
export { calculateLineLayout };
|
||||
const getNodeRect = (data) => {
|
||||
const nodeSize = data.children
|
||||
? Constants.nodeSizeWithChildren
|
||||
: Constants.nodeSize;
|
||||
|
||||
const statuses = data.children
|
||||
? data.children.reduce((statuses, child) =>
|
||||
statuses + child.instanceStatuses.length, 0)
|
||||
: data.instanceStatuses.length;
|
||||
|
||||
const { width, height } = nodeSize;
|
||||
|
||||
const nodeHeight = statuses
|
||||
? height + Constants.statusHeight*statuses + 6
|
||||
: height;
|
||||
|
||||
return ({
|
||||
left: -width / 2,
|
||||
right: width / 2,
|
||||
top: -height / 2,
|
||||
bottom: nodeHeight - height / 2,
|
||||
width,
|
||||
height: nodeHeight
|
||||
})
|
||||
};
|
||||
|
||||
export { getNodeRect, calculateLineLayout };
|
@ -8,7 +8,7 @@ import { createSimulation } from './simulation';
|
||||
import TopologyNode from './node';
|
||||
import TopologyLink from './link';
|
||||
import TopologyLinkArrow from './link/arrow';
|
||||
import { calculateLineLayout } from './link/functions';
|
||||
import { getNodeRect, calculateLineLayout } from './functions';
|
||||
|
||||
const StyledSvg = Svg.extend`
|
||||
width: 100%;
|
||||
@ -124,10 +124,7 @@ class Topology extends React.Component {
|
||||
}
|
||||
|
||||
findNodeData(nodesData, nodeId) {
|
||||
return nodesData.reduce(
|
||||
(acc, nodeData, index) => (nodeData.id === nodeId ? nodeData : acc),
|
||||
{}
|
||||
);
|
||||
return nodesData.filter(nodeData => nodeData.id === nodeId).shift();
|
||||
}
|
||||
|
||||
setDragInfo(dragging, nodeId = null, position = {}) {
|
||||
@ -148,9 +145,12 @@ class Topology extends React.Component {
|
||||
? this.getConsulNodePosition()
|
||||
: this.getConstrainedNodePosition(service.id, service.children);
|
||||
|
||||
const nodeRect = getNodeRect(service);
|
||||
|
||||
return {
|
||||
...service,
|
||||
...nodePosition
|
||||
...nodePosition,
|
||||
nodeRect
|
||||
};
|
||||
});
|
||||
|
||||
|
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import Baseline from '../../baseline';
|
||||
import Constants from '../constants';
|
||||
import { GraphLine, GraphSubtitle } from './shapes';
|
||||
import { GraphLine, GraphSubtitle, GraphText } from './shapes';
|
||||
import GraphNodeInfo from './info';
|
||||
import GraphNodeMetrics from './metrics';
|
||||
|
||||
@ -48,6 +48,7 @@ const GraphNodeContent = ({ connected, child = false, data, index = 0 }) => {
|
||||
<GraphNodeInfo
|
||||
datacenter={data.datacenter}
|
||||
instances={data.instances}
|
||||
instanceStatuses={data.instanceStatuses}
|
||||
healthy
|
||||
connected={connected}
|
||||
pos={nodeInfoPos}
|
||||
|
@ -15,13 +15,7 @@ const GraphNode = ({
|
||||
onNodeTitleClick,
|
||||
onQuickActions
|
||||
}) => {
|
||||
const { width, height } = data.children
|
||||
? Constants.nodeSizeWithChildren
|
||||
: Constants.nodeSize;
|
||||
|
||||
const { left, top } = data.children
|
||||
? Constants.nodeRectWithChildren
|
||||
: Constants.nodeRect;
|
||||
const { left, top, width, height } = data.nodeRect;
|
||||
|
||||
let x = data.x;
|
||||
let y = data.y;
|
||||
|
@ -25,9 +25,16 @@ const StyledDataCentresIcon = styled(DataCentresIcon)`
|
||||
`};
|
||||
`;
|
||||
|
||||
const GraphNodeInfo = ({ connected, datacenter, instances, healthy, pos }) => {
|
||||
const GraphNodeInfo = ({ connected, datacenter, instances, instanceStatuses, healthy, pos }) => {
|
||||
const { x, y } = pos;
|
||||
|
||||
const statuses = instanceStatuses.map((instanceStatus, index) =>
|
||||
<GraphText key={index} connected={connected}>
|
||||
{`${instanceStatus.count}
|
||||
${instanceStatus.status.toLowerCase()}`}
|
||||
</GraphText>
|
||||
);
|
||||
|
||||
return (
|
||||
<g transform={`translate(${x}, ${y})`}>
|
||||
<g transform={`translate(0, 0)`}>
|
||||
@ -40,6 +47,9 @@ const GraphNodeInfo = ({ connected, datacenter, instances, healthy, pos }) => {
|
||||
<GraphText x={54} y={14} connected={connected}>
|
||||
{`${instances.length} inst.`}
|
||||
</GraphText>
|
||||
<g transform={'translate(54, 36)'}>
|
||||
{ statuses }
|
||||
</g>
|
||||
{/* <g transform={'translate(82, 0)'}>
|
||||
<StyledDataCentresIcon connected={connected} />
|
||||
</g>
|
||||
@ -54,7 +64,8 @@ GraphNodeInfo.propTypes = {
|
||||
connected: PropTypes.bool,
|
||||
datacenter: PropTypes.string,
|
||||
healthy: PropTypes.bool,
|
||||
instances: PropTypes.number,
|
||||
instances: PropTypes.array,
|
||||
instanceStatuses: PropTypes.array,
|
||||
pos: Point.isRequired
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user