diff --git a/packages/cp-frontend/src/components/services/list-item.js b/packages/cp-frontend/src/components/services/list-item.js
index 254f07e3..ca2a91a0 100644
--- a/packages/cp-frontend/src/components/services/list-item.js
+++ b/packages/cp-frontend/src/components/services/list-item.js
@@ -63,12 +63,18 @@ const ServiceListItem = ({
;
- const subtitle = {service.instances} instances;
+ const subtitle = (
+ {service.instances.length} instances
+ );
const handleCardOptionsClick = evt => {
onQuickActionsClick(evt, service);
};
+ const statuses = service.instances.map(instance =>
+
1 instance {instance.status}
+ );
+
const header = isChild
? null
:
@@ -99,6 +105,7 @@ const ServiceListItem = ({
{isChild && subtitle}
{/* } label="Healthy" /> */}
+ {statuses}
{/* {
- onStopClick(evt, service);
- };
-
const handleStartClick = evt => {
onStartClick(evt, service);
};
- // TODO we'll need to check for service status and diplay start or restart & stop accordingly
+ const handleStopClick = evt => {
+ onStopClick(evt, service);
+ };
+
+ const status = service.instances.reduce((status, instance) => {
+ return status
+ ? instance.status === status ? status : 'MIXED'
+ : instance.status;
+ }, null);
+
+ const startService = status === 'RUNNING'
+ ? null
+ : Start;
+
+ const stopService = status === 'STOPPED'
+ ? null
+ : Stop;
return (
Scale
Restart
- Stop
+ {startService}
+ {stopService}
Delete
diff --git a/packages/cp-frontend/src/containers/service/delete.js b/packages/cp-frontend/src/containers/service/delete.js
index a2a0c8d3..2e138f0b 100644
--- a/packages/cp-frontend/src/containers/service/delete.js
+++ b/packages/cp-frontend/src/containers/service/delete.js
@@ -1,4 +1,4 @@
-import React, { PureComponent } from 'react';
+import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { compose, graphql, gql } from 'react-apollo';
import ServicesDeleteMutation from '@graphql/ServicesDeleteMutation.gql';
@@ -7,7 +7,7 @@ import { ServiceDelete as ServiceDeleteComponent } from '@components/service';
import { Modal } from 'joyent-ui-toolkit';
import ServiceGql from './service-gql';
-class ServiceDelete extends PureComponent {
+class ServiceDelete extends Component {
render() {
if (this.props.loading) {
return ;
@@ -26,7 +26,7 @@ class ServiceDelete extends PureComponent {
};
const handleConfirmClick = evt => {
- deleteServices(service.id);
+ deleteServices(service.id).then(() => handleCloseClick());
};
return (
@@ -49,7 +49,27 @@ ServiceDelete.propTypes = {
const DeleteServicesGql = graphql(ServicesDeleteMutation, {
props: ({ mutate }) => ({
- deleteServices: serviceId => mutate({ variables: { ids: [serviceId] } })
+ deleteServices: serviceId =>
+ mutate({
+ variables: { ids: [serviceId] },
+ updateQueries: {
+ Services: (prev, { mutationResult }) => {
+ const deletedService = mutationResult.data.deleteServices[0];
+ const prevServices = prev.deploymentGroup.services;
+ const services = prevServices.filter(
+ service =>
+ service.id !== deletedService.id &&
+ service.parent !== deletedService.id
+ );
+ return {
+ deploymentGroup: {
+ ...prev.deploymentGroup,
+ services
+ }
+ };
+ }
+ }
+ })
})
});
diff --git a/packages/cp-frontend/src/containers/services/list.js b/packages/cp-frontend/src/containers/services/list.js
index 5c59d99a..a5885f5d 100644
--- a/packages/cp-frontend/src/containers/services/list.js
+++ b/packages/cp-frontend/src/containers/services/list.js
@@ -57,7 +57,7 @@ class ServiceList extends Component {
);
}
- const handleQuickActionsClick = (evt, { service }) => {
+ const handleQuickActionsClick = (evt, service) => {
const list = this._refs.container;
const listRect = list.getBoundingClientRect();
const button = evt.currentTarget;
@@ -93,14 +93,16 @@ class ServiceList extends Component {
toggleServicesQuickActions({ show: false });
};
- const serviceList = services.map(service =>
-
- );
+ const serviceList = services.map(service => {
+ return (
+
+ );
+ });
return (
diff --git a/packages/cp-frontend/src/graphql/Instances.gql b/packages/cp-frontend/src/graphql/Instances.gql
index 26025f11..3def1dd3 100644
--- a/packages/cp-frontend/src/graphql/Instances.gql
+++ b/packages/cp-frontend/src/graphql/Instances.gql
@@ -9,6 +9,7 @@ query Instances($deploymentGroupSlug: String!, $serviceSlug: String) {
instances {
id
name
+ status
}
}
}
diff --git a/packages/cp-frontend/src/graphql/Services.gql b/packages/cp-frontend/src/graphql/Services.gql
index 47cdb866..09ffa6c1 100644
--- a/packages/cp-frontend/src/graphql/Services.gql
+++ b/packages/cp-frontend/src/graphql/Services.gql
@@ -9,6 +9,7 @@ query Services($deploymentGroupSlug: String!){
parent
instances {
id
+ status
}
}
}
diff --git a/packages/cp-frontend/src/graphql/ServicesDeleteMutation.gql b/packages/cp-frontend/src/graphql/ServicesDeleteMutation.gql
index 0790ea31..b4ef3a26 100644
--- a/packages/cp-frontend/src/graphql/ServicesDeleteMutation.gql
+++ b/packages/cp-frontend/src/graphql/ServicesDeleteMutation.gql
@@ -2,5 +2,9 @@ mutation DeleteServices($ids: [ID]!) {
deleteServices(ids: $ids) {
id
slug
+ instances {
+ id
+ status
+ }
}
}
diff --git a/packages/cp-frontend/src/graphql/ServicesStartMutation.gql b/packages/cp-frontend/src/graphql/ServicesStartMutation.gql
index a47e541c..e854e34e 100644
--- a/packages/cp-frontend/src/graphql/ServicesStartMutation.gql
+++ b/packages/cp-frontend/src/graphql/ServicesStartMutation.gql
@@ -2,5 +2,9 @@ mutation StartServices($ids: [ID]!) {
startServices(ids: $ids) {
id
slug
+ instances {
+ id
+ status
+ }
}
}
diff --git a/packages/cp-frontend/src/graphql/ServicesStopMutation.gql b/packages/cp-frontend/src/graphql/ServicesStopMutation.gql
index 1ef7ebe1..f2778ba7 100644
--- a/packages/cp-frontend/src/graphql/ServicesStopMutation.gql
+++ b/packages/cp-frontend/src/graphql/ServicesStopMutation.gql
@@ -2,5 +2,9 @@ mutation StopServices($ids: [ID]!) {
stopServices(ids: $ids) {
id
slug
+ instances {
+ id
+ status
+ }
}
}
diff --git a/packages/cp-frontend/src/state/selectors.js b/packages/cp-frontend/src/state/selectors.js
index e78d0df1..ca307a99 100644
--- a/packages/cp-frontend/src/state/selectors.js
+++ b/packages/cp-frontend/src/state/selectors.js
@@ -71,29 +71,35 @@ const getService = (service, index, datacenter) => ({
name: `${m}`,
value: `${m}`
})),
- instances: service.instances.length,
+ // instances: service.instances.length,
datacenter
});
const processServices = (services, datacenter) => {
- console.log('services = ', services);
return forceArray(services).reduce((ss, s, i) => {
- // Check whether it exits in thing, if so, add as child
- // if not, create and add as child
-
if (s.parent) {
- let parent = findService(ss, s.parent);
- if (!parent) {
- parent = { uuid: s.parent };
+ const parents = ss.filter(parentS => parentS.id === s.parent);
+ let parent;
+ if (parents.length) {
+ parent = parents[0];
+ } else {
+ parent = { id: s.parent };
ss.push(parent);
}
if (!parent.children) {
parent.children = [];
}
parent.children.push(getService(s, i, datacenter));
- }
- if (!s.parent) {
- ss.push(getService(s, i, datacenter));
+ } else {
+ const serviceIndex = ss.findIndex(existingS => existingS.id === s.id);
+ if (serviceIndex == -1) {
+ ss.push(getService(s, i, datacenter));
+ } else {
+ ss.splice(serviceIndex, 1, {
+ ...ss[serviceIndex],
+ ...getService(s, i, datacenter)
+ });
+ }
}
return ss;
}, []);
diff --git a/packages/cp-gql-mock-server/src/data.json b/packages/cp-gql-mock-server/src/data.json
index f5a71c9c..7849d3fc 100644
--- a/packages/cp-gql-mock-server/src/data.json
+++ b/packages/cp-gql-mock-server/src/data.json
@@ -112,67 +112,78 @@
"id": "309ecd9f-ac03-474b-aff7-4bd2e743296c",
"name": "wordpress_01",
"serviceId": "be227788-74f1-4e5b-a85f-b5c71cbae8d8",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "0db6db53-de6f-4378-839e-5d5b452fbaf2",
"name": "nfs_01",
"serviceId": "6a0eee76-c019-413b-9d5f-44712b55b993",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "250c8a6c-7d02-49a9-8abd-e1c22773041d",
"name": "consul",
"serviceId": "97c68055-db88-45c9-ad49-f26da4264777",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "2c921f3a-8bc3-4f57-9cd7-789ebae72061",
"name": "memcache_01",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "68d3046e-8e34-4f5d-a0e5-db3795a250fd",
"name": "memcache_02",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "2ea99763-3b44-4179-8393-d66d94961051",
"name": "memcache_03",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "25f6bc62-63b8-4959-908e-1f6d7ff6341d",
"name": "memcache_04",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "8be01042-0281-4a77-a357-25979e87bf3d",
"name": "memcache_05",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "3d652e9d-73e8-4a6f-8171-84fa83740662",
"name": "nginx",
"serviceId": "081a792c-47e0-4439-924b-2efa9788ae9e",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "c3ec7633-a02b-4615-86a0-9e6faeaae94b",
"name": "percona-primary",
- "serviceId": "4ee4103e-1a52-4099-a48e-01588f597c70",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "serviceId": "9572d367-c4ae-4fb1-8ad5-f5e3830e7034",
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
},
{
"id": "c2b5fec2-31e2-41a7-b7fc-cd0bb1822e76",
"name": "percona-secondary",
- "serviceId": "4ee4103e-1a52-4099-a48e-01588f597c70",
- "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401"
+ "serviceId": "c8411ef0-ab39-42cb-a704-d20b170eff31",
+ "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
+ "status": "RUNNING"
}
]
}
diff --git a/packages/cp-gql-mock-server/src/resolvers.js b/packages/cp-gql-mock-server/src/resolvers.js
index 13764483..72be229e 100644
--- a/packages/cp-gql-mock-server/src/resolvers.js
+++ b/packages/cp-gql-mock-server/src/resolvers.js
@@ -16,10 +16,11 @@ const find = (query = {}) => item =>
const cleanQuery = (q = {}) => JSON.parse(JSON.stringify(q));
-const getInstances = query =>
- Promise.resolve(instances.filter(find(cleanQuery(query))));
+const getInstances = query => {
+ return Promise.resolve(instances.filter(find(cleanQuery(query))));
+};
-const getServices = query => {
+const getUnfilteredServices = query => {
const instancesResolver = ({ id }) => query =>
getInstances(
Object.assign({}, query, {
@@ -37,6 +38,74 @@ const getServices = query => {
);
};
+const getServices = query => {
+ const services = getUnfilteredServices(query)
+ .then(services => {
+ // loop through services and for each of them get all services that's parent id is the service
+ // once done - this will be a Promise all - need to remove any duplicates from the services list - the original
+ // then we can do below...
+ return (
+ Promise.all(
+ services.map(service => getUnfilteredServices({ parent: service.id }))
+ )
+ // this is going to be an array of arrays of services
+ .then(childServices => {
+ return childServices.reduce((childServices, childService) => {
+ return childServices.concat(childService);
+ }, []);
+ })
+ // now it's at least flat
+ .then(childServices => {
+ return services.concat(
+ childServices.reduce((childServices, childService) => {
+ const exists = services.filter(
+ service => service.id === childService.id
+ ).length;
+ if (!exists) {
+ childServices.push(childService);
+ }
+ return childServices;
+ }, [])
+ );
+ })
+ .then(services => {
+ return Promise.all(
+ services.map(service => service.instances())
+ ).then(instances => {
+ return { services, instances };
+ });
+ })
+ );
+ })
+ .then(({ services, instances }) => {
+ const activeServices = services.reduce((services, service, index) => {
+ const active = instances[index].filter(
+ instance =>
+ instance.status !== 'DELETED' && instance.status !== 'EXITED'
+ ).length;
+ if (active) {
+ services.push(service);
+ }
+ return services;
+ }, []);
+ const allServices = activeServices.reduce((allServices, service) => {
+ if (service.parent) {
+ const parentService = services.filter(s => s.id === service.parent);
+ const exists = allServices.filter(s => s.id === service.parent)
+ .length;
+ if (!exists && parentService) {
+ allServices.push(parentService[0]);
+ }
+ }
+ allServices.push(service);
+ return allServices;
+ }, []);
+ return allServices;
+ });
+
+ return Promise.resolve(services);
+};
+
const getDeploymentGroups = query => {
const servicesResolver = ({ id }) => query =>
getServices(
@@ -100,11 +169,6 @@ const createServicesFromManifest = ({ deploymentGroupId, raw }) => {
return Promise.resolve(undefined);
};
-const deleteServices = options => {
- const service = getServices({ id: options.ids[0] });
- return service;
-};
-
const scale = options => {
const service = getServices({ id: options.serviceId })[0];
@@ -124,14 +188,54 @@ const restartServices = options => {
return service;
};
+const updateInstancesStatus = (is, status) => {
+ is.forEach(i => {
+ const instance = instances.filter(instance => instance.id === i.id)[0];
+ instance.status = status;
+ });
+
+ return Promise.resolve(instances);
+};
+
+const updateServiceStatus = (serviceId, status) => {
+ return getServices({ id: serviceId })
+ .then(services => services.shift().instances())
+ .then(instances => updateInstancesStatus(instances, status))
+ .then(instances => getServices({ id: serviceId }));
+};
+
+const deleteServices = options => {
+ const serviceId = options.ids[0];
+ const deleteService = getServices({ id: serviceId }).then(services => {
+ const service = services.shift();
+ return service.instances().then(instances => {
+ if (instances.length) {
+ updateInstancesStatus(instances, 'DELETED');
+ return [service];
+ }
+
+ return getUnfilteredServices({ parent: serviceId }).then(services => {
+ return Promise.all(
+ services.map(service => service.instances())
+ ).then(instances => {
+ const is = instances.reduce((is, i) => is.concat(i), []);
+ updateInstancesStatus(is, 'DELETED');
+ return [service];
+ });
+ });
+ });
+ });
+ return Promise.resolve(deleteService);
+};
+
const stopServices = options => {
- const service = getServices({ id: options.ids[0] });
- return service;
+ const stopService = updateServiceStatus(options.ids[0], 'STOPPED');
+ return Promise.resolve(stopService);
};
const startServices = options => {
- const service = getServices({ id: options.ids[0] });
- return service;
+ const startService = updateServiceStatus(options.ids[0], 'RUNNING');
+ return Promise.resolve(startService);
};
module.exports = {