diff --git a/packages/cp-frontend/src/components/services/list-item.js b/packages/cp-frontend/src/components/services/list-item.js index 1c4dba0c..e122741b 100644 --- a/packages/cp-frontend/src/components/services/list-item.js +++ b/packages/cp-frontend/src/components/services/list-item.js @@ -16,7 +16,7 @@ import { Anchor } from 'joyent-ui-toolkit'; -import { InstancesIcon, HealthyIcon, P } from 'joyent-ui-toolkit'; +import { InstancesIcon, HealthyIcon, UnhealthyIcon, P } from 'joyent-ui-toolkit'; import Status from './status'; @@ -97,6 +97,20 @@ const ServiceListItem = ({ ; + const healthyInfo = service.instancesHealthy + ? } + iconPosition='left' + label='Healthy' + color='dark' + /> + : } + iconPosition='left' + label='Unhealthy' + color='dark' + /> + const view = children ? {children} @@ -106,12 +120,7 @@ const ServiceListItem = ({ {isChild && subtitle} - } - iconPosition="left" - label="Healthy" - color="dark" - /> + {healthyInfo} ; diff --git a/packages/cp-frontend/src/graphql/Instances.gql b/packages/cp-frontend/src/graphql/Instances.gql index 3def1dd3..4b03dd5b 100644 --- a/packages/cp-frontend/src/graphql/Instances.gql +++ b/packages/cp-frontend/src/graphql/Instances.gql @@ -10,6 +10,7 @@ query Instances($deploymentGroupSlug: String!, $serviceSlug: String) { id name status + healthy } } } diff --git a/packages/cp-frontend/src/graphql/Services.gql b/packages/cp-frontend/src/graphql/Services.gql index 5ceeed6e..c446b232 100644 --- a/packages/cp-frontend/src/graphql/Services.gql +++ b/packages/cp-frontend/src/graphql/Services.gql @@ -11,6 +11,7 @@ query Services($deploymentGroupSlug: String!){ instances { id status + healthy } } } diff --git a/packages/cp-frontend/src/graphql/ServicesDeleteMutation.gql b/packages/cp-frontend/src/graphql/ServicesDeleteMutation.gql index 6e62f6a3..ab4bb2c7 100644 --- a/packages/cp-frontend/src/graphql/ServicesDeleteMutation.gql +++ b/packages/cp-frontend/src/graphql/ServicesDeleteMutation.gql @@ -6,6 +6,7 @@ mutation DeleteServices($ids: [ID]!) { instances { id status + healthy } } } diff --git a/packages/cp-frontend/src/graphql/ServicesStartMutation.gql b/packages/cp-frontend/src/graphql/ServicesStartMutation.gql index 31ae80a9..1354a530 100644 --- a/packages/cp-frontend/src/graphql/ServicesStartMutation.gql +++ b/packages/cp-frontend/src/graphql/ServicesStartMutation.gql @@ -6,6 +6,7 @@ mutation StartServices($ids: [ID]!) { instances { id status + healthy } } } diff --git a/packages/cp-frontend/src/graphql/ServicesStopMutation.gql b/packages/cp-frontend/src/graphql/ServicesStopMutation.gql index 9f4149ca..ab00ad7b 100644 --- a/packages/cp-frontend/src/graphql/ServicesStopMutation.gql +++ b/packages/cp-frontend/src/graphql/ServicesStopMutation.gql @@ -6,6 +6,7 @@ mutation StopServices($ids: [ID]!) { instances { id status + healthy } } } diff --git a/packages/cp-frontend/src/state/selectors.js b/packages/cp-frontend/src/state/selectors.js index 0bdfd9c7..9770b73c 100644 --- a/packages/cp-frontend/src/state/selectors.js +++ b/packages/cp-frontend/src/state/selectors.js @@ -105,16 +105,26 @@ const getInstancesActive = instanceStatuses => { ); }; +const getInstancesHealthy = instances => { + return instances.reduce( + (healthy, instance) => + instance.healthy === 'HEALTHY' ? healthy : false, + true + ); +}; + const getService = (service, index) => { const instanceStatuses = getInstanceStatuses(service); const instancesActive = getInstancesActive(instanceStatuses); + const instancesHealthy = getInstancesHealthy(service.instances); const transitionalStatus = transitionalServiceStatuses.indexOf(service.status) !== -1; return ({ index, ...service, instanceStatuses, instancesActive, + instancesHealthy, transitionalStatus, isConsul: service.slug === 'consul' }); diff --git a/packages/cp-gql-mock-server/src/data.json b/packages/cp-gql-mock-server/src/data.json index 7849d3fc..d9f2cdd2 100644 --- a/packages/cp-gql-mock-server/src/data.json +++ b/packages/cp-gql-mock-server/src/data.json @@ -113,77 +113,88 @@ "name": "wordpress_01", "serviceId": "be227788-74f1-4e5b-a85f-b5c71cbae8d8", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" }, { "id": "0db6db53-de6f-4378-839e-5d5b452fbaf2", "name": "nfs_01", "serviceId": "6a0eee76-c019-413b-9d5f-44712b55b993", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" }, { "id": "250c8a6c-7d02-49a9-8abd-e1c22773041d", "name": "consul", "serviceId": "97c68055-db88-45c9-ad49-f26da4264777", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "UNHEALTHY" }, { "id": "2c921f3a-8bc3-4f57-9cd7-789ebae72061", "name": "memcache_01", "serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" }, { "id": "68d3046e-8e34-4f5d-a0e5-db3795a250fd", "name": "memcache_02", "serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" }, { "id": "2ea99763-3b44-4179-8393-d66d94961051", "name": "memcache_03", "serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" }, { "id": "25f6bc62-63b8-4959-908e-1f6d7ff6341d", "name": "memcache_04", "serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" }, { "id": "8be01042-0281-4a77-a357-25979e87bf3d", "name": "memcache_05", "serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" }, { "id": "3d652e9d-73e8-4a6f-8171-84fa83740662", "name": "nginx", "serviceId": "081a792c-47e0-4439-924b-2efa9788ae9e", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" }, { "id": "c3ec7633-a02b-4615-86a0-9e6faeaae94b", "name": "percona-primary", "serviceId": "9572d367-c4ae-4fb1-8ad5-f5e3830e7034", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "UNHEALTHY" }, { "id": "c2b5fec2-31e2-41a7-b7fc-cd0bb1822e76", "name": "percona-secondary", "serviceId": "c8411ef0-ab39-42cb-a704-d20b170eff31", "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401", - "status": "RUNNING" + "status": "RUNNING", + "healthy": "HEALTHY" } ] } diff --git a/packages/ui-toolkit/src/icons/index.js b/packages/ui-toolkit/src/icons/index.js index b11b14f8..63a0dd2a 100644 --- a/packages/ui-toolkit/src/icons/index.js +++ b/packages/ui-toolkit/src/icons/index.js @@ -5,3 +5,4 @@ export { default as ArrowIcon } from './arrow'; export { default as TickIcon } from './tick'; export { default as InstancesIcon } from './instances'; export { default as HealthyIcon } from './healthy'; +export { default as UnhealthyIcon } from './unhealthy'; diff --git a/packages/ui-toolkit/src/icons/unhealthy.js b/packages/ui-toolkit/src/icons/unhealthy.js new file mode 100644 index 00000000..9c4f8670 --- /dev/null +++ b/packages/ui-toolkit/src/icons/unhealthy.js @@ -0,0 +1,7 @@ +import Baseline from '../baseline'; +// eslint-disable-next-line no-unused-vars +import React from 'react'; + +import UnhealthyIcon from './svg/icon_error_failure.svg'; + +export default Baseline(UnhealthyIcon); diff --git a/packages/ui-toolkit/src/index.js b/packages/ui-toolkit/src/index.js index d939556a..c341b118 100644 --- a/packages/ui-toolkit/src/index.js +++ b/packages/ui-toolkit/src/index.js @@ -100,5 +100,6 @@ export { MinusIcon, ArrowIcon, InstancesIcon, - HealthyIcon + HealthyIcon, + UnhealthyIcon } from './icons'; diff --git a/packages/ui-toolkit/src/topology/index.js b/packages/ui-toolkit/src/topology/index.js index 32cec7a0..2894caa1 100644 --- a/packages/ui-toolkit/src/topology/index.js +++ b/packages/ui-toolkit/src/topology/index.js @@ -14,7 +14,7 @@ import { getNodeRect, calculateLineLayout } from './functions'; const StyledSvg = Svg.extend` width: 100%; - height: 1400px; + height: 1000px; `; /** @@ -194,7 +194,7 @@ class Topology extends React.Component { return { width: windowWidth - 2 * 24, - height: 1400 + height: 1000 }; } diff --git a/packages/ui-toolkit/src/topology/node/info.js b/packages/ui-toolkit/src/topology/node/info.js index 69b7f0db..76f755a1 100644 --- a/packages/ui-toolkit/src/topology/node/info.js +++ b/packages/ui-toolkit/src/topology/node/info.js @@ -8,6 +8,7 @@ import InstancesIcon from './icon-instances.svg'; import { Point } from '../prop-types'; import { GraphText, GraphHealthyCircle } from './shapes'; import HeartIcon from './icon-heart.svg'; +import { HealthyIcon, UnhealthyIcon } from '../../icons'; const StyledInstancesIcon = styled(InstancesIcon)` fill: ${props => props.theme.white}; @@ -39,7 +40,7 @@ const GraphNodeInfo = ({ data, pos }) => { datacenter, instances, instanceStatuses, - healthy, + instancesHealthy, isConsul, instancesActive, transitionalStatus, @@ -59,11 +60,13 @@ const GraphNodeInfo = ({ data, pos }) => { ); + const healthy = instancesHealthy + ? : ; + return ( - - + { healthy } @@ -86,14 +89,7 @@ const GraphNodeInfo = ({ data, pos }) => { GraphNodeInfo.propTypes = { data: PropTypes.object.isRequired, - pos: Point.isRequired/*, - datacenter: PropTypes.string, - healthy: PropTypes.bool, - instances: PropTypes.array, - instanceStatuses: PropTypes.array, - pos: Point.isRequired, - isConsul: PropTypes.bool, - instancesActive: PropTypes.bool*/ + pos: Point.isRequired }; export default Baseline(GraphNodeInfo); diff --git a/packages/ui-toolkit/src/topology/simulation.js b/packages/ui-toolkit/src/topology/simulation.js index 040e54e4..51b30ec9 100644 --- a/packages/ui-toolkit/src/topology/simulation.js +++ b/packages/ui-toolkit/src/topology/simulation.js @@ -41,20 +41,15 @@ const createLinks = services => const createSimulation = (services, svgSize, animationTicks = 0) => { // This is not going to work given that as well as the d3 layout stuff, other things might be at play too // We should pass two objects to the components - one for positioning and one for data - console.log('createSimulation services = ', services); - console.log('createSimulation services.length = ', services.length); const nodes = services.map((service, index) => { - console.log('createSimulation services.map service.id = ', service.id); - console.log('createSimulation services.map service.connected = ', service.connected); return ({ id: service.id, index }) }); - console.log('createSimulation nodes = ', nodes); - console.log('createSimulation nodes.length = ', nodes.length); + const links = createLinks(services); - console.log('createSimulation links = ', links); + const { width, height } = svgSize; const nodeRadius = rectRadius(Constants.nodeSizeWithChildren); @@ -65,7 +60,6 @@ const createSimulation = (services, svgSize, animationTicks = 0) => { .force('center', forceCenter(width / 2, height / 2)); forcePlayAnimation(simulation, animationTicks); - console.log('createSimulation nodes = ', nodes); return { nodes,