From 05d0420813bea1b474b8f2855bcbb1ced1bbbdd8 Mon Sep 17 00:00:00 2001 From: JUDIT GRESKOVITS Date: Fri, 30 Jun 2017 11:52:55 +0100 Subject: [PATCH] feat(ui-toolkit, cp-frontend): Display statuses on topology view --- .../components/services/instance-statuses.js | 28 +++++-------- .../src/components/services/list-item.js | 5 ++- .../src/containers/services/topology.js | 15 ++++++- .../src/graphql/ServicesTopology.gql | 1 + packages/cp-frontend/src/state/selectors.js | 20 +++++++++ packages/ui-toolkit/src/topology/constants.js | 5 ++- .../src/topology/{link => }/functions.js | 41 +++++++++++++++---- packages/ui-toolkit/src/topology/index.js | 12 +++--- .../ui-toolkit/src/topology/node/content.js | 19 +++++---- .../ui-toolkit/src/topology/node/index.js | 8 +--- packages/ui-toolkit/src/topology/node/info.js | 15 ++++++- 11 files changed, 114 insertions(+), 55 deletions(-) rename packages/ui-toolkit/src/topology/{link => }/functions.js (70%) diff --git a/packages/cp-frontend/src/components/services/instance-statuses.js b/packages/cp-frontend/src/components/services/instance-statuses.js index 412f316e..4e10ad00 100644 --- a/packages/cp-frontend/src/components/services/instance-statuses.js +++ b/packages/cp-frontend/src/components/services/instance-statuses.js @@ -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 ( - {`${instances} - ${instances > 1 ? 'instances' : 'instance'} + {`${count} + ${count > 1 ? 'instances' : 'instance'} ${status.toLowerCase()}`} ); @@ -40,13 +34,13 @@ const InstanceStatuses = ({ instances }) => { return ( - {instanceStatuses} + {statuses} ); }; InstanceStatuses.propTypes = { - instances: PropTypes.array.isRequired + instanceStatuses: PropTypes.array.isRequired }; export default InstanceStatuses; diff --git a/packages/cp-frontend/src/components/services/list-item.js b/packages/cp-frontend/src/components/services/list-item.js index 414668f8..18c6a365 100644 --- a/packages/cp-frontend/src/components/services/list-item.js +++ b/packages/cp-frontend/src/components/services/list-item.js @@ -96,7 +96,8 @@ const ServiceListItem = ({ ; - + console.log('*** service = ', service); + console.log('*** service.instanceStatuses = ', service.instanceStatuses); const view = children ? {children} @@ -105,7 +106,7 @@ const ServiceListItem = ({ {isChild && title} {isChild && subtitle} - + } iconPosition="left" diff --git a/packages/cp-frontend/src/containers/services/topology.js b/packages/cp-frontend/src/containers/services/topology.js index 9c5f96a5..fda0e402 100644 --- a/packages/cp-frontend/src/containers/services/topology.js +++ b/packages/cp-frontend/src/containers/services/topology.js @@ -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 ( @@ -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} /> diff --git a/packages/cp-frontend/src/graphql/ServicesTopology.gql b/packages/cp-frontend/src/graphql/ServicesTopology.gql index 2a063adb..231eda22 100644 --- a/packages/cp-frontend/src/graphql/ServicesTopology.gql +++ b/packages/cp-frontend/src/graphql/ServicesTopology.gql @@ -10,6 +10,7 @@ query Instances($deploymentGroupSlug: String!){ connections instances { id + status } } } diff --git a/packages/cp-frontend/src/state/selectors.js b/packages/cp-frontend/src/state/selectors.js index 8d0b7406..b8122743 100644 --- a/packages/cp-frontend/src/state/selectors.js +++ b/packages/cp-frontend/src/state/selectors.js @@ -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' }); diff --git a/packages/ui-toolkit/src/topology/constants.js b/packages/ui-toolkit/src/topology/constants.js index 14d1f177..7d04a7aa 100644 --- a/packages/ui-toolkit/src/topology/constants.js +++ b/packages/ui-toolkit/src/topology/constants.js @@ -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, diff --git a/packages/ui-toolkit/src/topology/link/functions.js b/packages/ui-toolkit/src/topology/functions.js similarity index 70% rename from packages/ui-toolkit/src/topology/link/functions.js rename to packages/ui-toolkit/src/topology/functions.js index 725e147d..7c9d344d 100644 --- a/packages/ui-toolkit/src/topology/link/functions.js +++ b/packages/ui-toolkit/src/topology/functions.js @@ -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 }; diff --git a/packages/ui-toolkit/src/topology/index.js b/packages/ui-toolkit/src/topology/index.js index be8e184a..43ee8ac4 100644 --- a/packages/ui-toolkit/src/topology/index.js +++ b/packages/ui-toolkit/src/topology/index.js @@ -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 }; }); diff --git a/packages/ui-toolkit/src/topology/node/content.js b/packages/ui-toolkit/src/topology/node/content.js index 459ec2aa..3bb35916 100644 --- a/packages/ui-toolkit/src/topology/node/content.js +++ b/packages/ui-toolkit/src/topology/node/content.js @@ -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'; @@ -44,14 +44,15 @@ const GraphNodeContent = ({ connected, child = false, data, index = 0 }) => { /> : null; */ - const nodeInfo = - ; + const nodeInfo = + ; return ( diff --git a/packages/ui-toolkit/src/topology/node/index.js b/packages/ui-toolkit/src/topology/node/index.js index 33526be4..7c00f68c 100644 --- a/packages/ui-toolkit/src/topology/node/index.js +++ b/packages/ui-toolkit/src/topology/node/index.js @@ -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; diff --git a/packages/ui-toolkit/src/topology/node/info.js b/packages/ui-toolkit/src/topology/node/info.js index aee458cf..98b94a06 100644 --- a/packages/ui-toolkit/src/topology/node/info.js +++ b/packages/ui-toolkit/src/topology/node/info.js @@ -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) => + + {`${instanceStatus.count} + ${instanceStatus.status.toLowerCase()}`} + + ); + return ( @@ -40,6 +47,9 @@ const GraphNodeInfo = ({ connected, datacenter, instances, healthy, pos }) => { {`${instances.length} inst.`} + + { statuses } + {/* @@ -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 };