feat(cp-frontend, cp-gql-mock-server): add stop, start, delete to resolvers

This commit is contained in:
JUDIT GRESKOVITS 2017-06-26 13:25:46 +01:00 committed by Sérgio Ramos
parent 2ea33c2a07
commit a373e4efa2
12 changed files with 233 additions and 56 deletions

View File

@ -63,12 +63,18 @@ const ServiceListItem = ({
</TitleInnerContainer> </TitleInnerContainer>
</CardTitle>; </CardTitle>;
const subtitle = <CardSubTitle>{service.instances} instances</CardSubTitle>; const subtitle = (
<CardSubTitle>{service.instances.length} instances</CardSubTitle>
);
const handleCardOptionsClick = evt => { const handleCardOptionsClick = evt => {
onQuickActionsClick(evt, service); onQuickActionsClick(evt, service);
}; };
const statuses = service.instances.map(instance =>
<p>1 instance {instance.status}</p>
);
const header = isChild const header = isChild
? null ? null
: <StyledCardHeader> : <StyledCardHeader>
@ -99,6 +105,7 @@ const ServiceListItem = ({
{isChild && subtitle} {isChild && subtitle}
<CardDescription> <CardDescription>
{/* <CardInfo icon={<HealthyIcon />} label="Healthy" /> */} {/* <CardInfo icon={<HealthyIcon />} label="Healthy" /> */}
{statuses}
</CardDescription> </CardDescription>
</CardMeta> </CardMeta>
{/* <ItemMetricGroup {/* <ItemMetricGroup

View File

@ -32,21 +32,34 @@ const ServicesQuickActions = ({
onRestartClick(evt, service); onRestartClick(evt, service);
}; };
const handleStopClick = evt => {
onStopClick(evt, service);
};
const handleStartClick = evt => { const handleStartClick = evt => {
onStartClick(evt, service); 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
: <TooltipButton onClick={handleStartClick}>Start</TooltipButton>;
const stopService = status === 'STOPPED'
? null
: <TooltipButton onClick={handleStopClick}>Stop</TooltipButton>;
return ( return (
<Tooltip {...p} onBlur={onBlur}> <Tooltip {...p} onBlur={onBlur}>
<TooltipButton to={scaleUrl}>Scale</TooltipButton> <TooltipButton to={scaleUrl}>Scale</TooltipButton>
<TooltipButton onClick={handleRestartClick}>Restart</TooltipButton> <TooltipButton onClick={handleRestartClick}>Restart</TooltipButton>
<TooltipButton onClick={handleStopClick}>Stop</TooltipButton> {startService}
{stopService}
<TooltipDivider /> <TooltipDivider />
<TooltipButton to={deleteUrl}>Delete</TooltipButton> <TooltipButton to={deleteUrl}>Delete</TooltipButton>
</Tooltip> </Tooltip>

View File

@ -1,4 +1,4 @@
import React, { PureComponent } from 'react'; import React, { Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { compose, graphql, gql } from 'react-apollo'; import { compose, graphql, gql } from 'react-apollo';
import ServicesDeleteMutation from '@graphql/ServicesDeleteMutation.gql'; import ServicesDeleteMutation from '@graphql/ServicesDeleteMutation.gql';
@ -7,7 +7,7 @@ import { ServiceDelete as ServiceDeleteComponent } from '@components/service';
import { Modal } from 'joyent-ui-toolkit'; import { Modal } from 'joyent-ui-toolkit';
import ServiceGql from './service-gql'; import ServiceGql from './service-gql';
class ServiceDelete extends PureComponent { class ServiceDelete extends Component {
render() { render() {
if (this.props.loading) { if (this.props.loading) {
return <Loader />; return <Loader />;
@ -26,7 +26,7 @@ class ServiceDelete extends PureComponent {
}; };
const handleConfirmClick = evt => { const handleConfirmClick = evt => {
deleteServices(service.id); deleteServices(service.id).then(() => handleCloseClick());
}; };
return ( return (
@ -49,7 +49,27 @@ ServiceDelete.propTypes = {
const DeleteServicesGql = graphql(ServicesDeleteMutation, { const DeleteServicesGql = graphql(ServicesDeleteMutation, {
props: ({ mutate }) => ({ 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
}
};
}
}
})
}) })
}); });

View File

@ -57,7 +57,7 @@ class ServiceList extends Component {
); );
} }
const handleQuickActionsClick = (evt, { service }) => { const handleQuickActionsClick = (evt, service) => {
const list = this._refs.container; const list = this._refs.container;
const listRect = list.getBoundingClientRect(); const listRect = list.getBoundingClientRect();
const button = evt.currentTarget; const button = evt.currentTarget;
@ -93,14 +93,16 @@ class ServiceList extends Component {
toggleServicesQuickActions({ show: false }); toggleServicesQuickActions({ show: false });
}; };
const serviceList = services.map(service => const serviceList = services.map(service => {
<ServiceListItem return (
key={service.id} <ServiceListItem
deploymentGroup={deploymentGroup.slug} key={service.id}
service={service} deploymentGroup={deploymentGroup.slug}
onQuickActionsClick={handleQuickActionsClick} service={service}
/> onQuickActionsClick={handleQuickActionsClick}
); />
);
});
return ( return (
<LayoutContainer> <LayoutContainer>

View File

@ -9,6 +9,7 @@ query Instances($deploymentGroupSlug: String!, $serviceSlug: String) {
instances { instances {
id id
name name
status
} }
} }
} }

View File

@ -9,6 +9,7 @@ query Services($deploymentGroupSlug: String!){
parent parent
instances { instances {
id id
status
} }
} }
} }

View File

@ -2,5 +2,9 @@ mutation DeleteServices($ids: [ID]!) {
deleteServices(ids: $ids) { deleteServices(ids: $ids) {
id id
slug slug
instances {
id
status
}
} }
} }

View File

@ -2,5 +2,9 @@ mutation StartServices($ids: [ID]!) {
startServices(ids: $ids) { startServices(ids: $ids) {
id id
slug slug
instances {
id
status
}
} }
} }

View File

@ -2,5 +2,9 @@ mutation StopServices($ids: [ID]!) {
stopServices(ids: $ids) { stopServices(ids: $ids) {
id id
slug slug
instances {
id
status
}
} }
} }

View File

@ -71,29 +71,35 @@ const getService = (service, index, datacenter) => ({
name: `${m}`, name: `${m}`,
value: `${m}` value: `${m}`
})), })),
instances: service.instances.length, // instances: service.instances.length,
datacenter datacenter
}); });
const processServices = (services, datacenter) => { const processServices = (services, datacenter) => {
console.log('services = ', services);
return forceArray(services).reduce((ss, s, i) => { 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) { if (s.parent) {
let parent = findService(ss, s.parent); const parents = ss.filter(parentS => parentS.id === s.parent);
if (!parent) { let parent;
parent = { uuid: s.parent }; if (parents.length) {
parent = parents[0];
} else {
parent = { id: s.parent };
ss.push(parent); ss.push(parent);
} }
if (!parent.children) { if (!parent.children) {
parent.children = []; parent.children = [];
} }
parent.children.push(getService(s, i, datacenter)); parent.children.push(getService(s, i, datacenter));
} } else {
if (!s.parent) { const serviceIndex = ss.findIndex(existingS => existingS.id === s.id);
ss.push(getService(s, i, datacenter)); if (serviceIndex == -1) {
ss.push(getService(s, i, datacenter));
} else {
ss.splice(serviceIndex, 1, {
...ss[serviceIndex],
...getService(s, i, datacenter)
});
}
} }
return ss; return ss;
}, []); }, []);

View File

@ -112,67 +112,78 @@
"id": "309ecd9f-ac03-474b-aff7-4bd2e743296c", "id": "309ecd9f-ac03-474b-aff7-4bd2e743296c",
"name": "wordpress_01", "name": "wordpress_01",
"serviceId": "be227788-74f1-4e5b-a85f-b5c71cbae8d8", "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", "id": "0db6db53-de6f-4378-839e-5d5b452fbaf2",
"name": "nfs_01", "name": "nfs_01",
"serviceId": "6a0eee76-c019-413b-9d5f-44712b55b993", "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", "id": "250c8a6c-7d02-49a9-8abd-e1c22773041d",
"name": "consul", "name": "consul",
"serviceId": "97c68055-db88-45c9-ad49-f26da4264777", "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", "id": "2c921f3a-8bc3-4f57-9cd7-789ebae72061",
"name": "memcache_01", "name": "memcache_01",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "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", "id": "68d3046e-8e34-4f5d-a0e5-db3795a250fd",
"name": "memcache_02", "name": "memcache_02",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "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", "id": "2ea99763-3b44-4179-8393-d66d94961051",
"name": "memcache_03", "name": "memcache_03",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "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", "id": "25f6bc62-63b8-4959-908e-1f6d7ff6341d",
"name": "memcache_04", "name": "memcache_04",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "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", "id": "8be01042-0281-4a77-a357-25979e87bf3d",
"name": "memcache_05", "name": "memcache_05",
"serviceId": "6d31aff4-de1e-4042-a983-fbd23d5c530c", "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", "id": "3d652e9d-73e8-4a6f-8171-84fa83740662",
"name": "nginx", "name": "nginx",
"serviceId": "081a792c-47e0-4439-924b-2efa9788ae9e", "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", "id": "c3ec7633-a02b-4615-86a0-9e6faeaae94b",
"name": "percona-primary", "name": "percona-primary",
"serviceId": "4ee4103e-1a52-4099-a48e-01588f597c70", "serviceId": "9572d367-c4ae-4fb1-8ad5-f5e3830e7034",
"deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"status": "RUNNING"
}, },
{ {
"id": "c2b5fec2-31e2-41a7-b7fc-cd0bb1822e76", "id": "c2b5fec2-31e2-41a7-b7fc-cd0bb1822e76",
"name": "percona-secondary", "name": "percona-secondary",
"serviceId": "4ee4103e-1a52-4099-a48e-01588f597c70", "serviceId": "c8411ef0-ab39-42cb-a704-d20b170eff31",
"deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401" "deploymentGroupId": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"status": "RUNNING"
} }
] ]
} }

View File

@ -16,10 +16,11 @@ const find = (query = {}) => item =>
const cleanQuery = (q = {}) => JSON.parse(JSON.stringify(q)); const cleanQuery = (q = {}) => JSON.parse(JSON.stringify(q));
const getInstances = query => const getInstances = query => {
Promise.resolve(instances.filter(find(cleanQuery(query)))); return Promise.resolve(instances.filter(find(cleanQuery(query))));
};
const getServices = query => { const getUnfilteredServices = query => {
const instancesResolver = ({ id }) => query => const instancesResolver = ({ id }) => query =>
getInstances( getInstances(
Object.assign({}, query, { 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 getDeploymentGroups = query => {
const servicesResolver = ({ id }) => query => const servicesResolver = ({ id }) => query =>
getServices( getServices(
@ -100,11 +169,6 @@ const createServicesFromManifest = ({ deploymentGroupId, raw }) => {
return Promise.resolve(undefined); return Promise.resolve(undefined);
}; };
const deleteServices = options => {
const service = getServices({ id: options.ids[0] });
return service;
};
const scale = options => { const scale = options => {
const service = getServices({ id: options.serviceId })[0]; const service = getServices({ id: options.serviceId })[0];
@ -124,14 +188,54 @@ const restartServices = options => {
return service; 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 stopServices = options => {
const service = getServices({ id: options.ids[0] }); const stopService = updateServiceStatus(options.ids[0], 'STOPPED');
return service; return Promise.resolve(stopService);
}; };
const startServices = options => { const startServices = options => {
const service = getServices({ id: options.ids[0] }); const startService = updateServiceStatus(options.ids[0], 'RUNNING');
return service; return Promise.resolve(startService);
}; };
module.exports = { module.exports = {