import { createSelector } from 'reselect'; import forceArray from 'force-array'; const apollo = state => state.apollo; // Redux selectors // const deploymentGroupBySlug = deploymentGroupSlug => createSelector( [apollo], apollo => apollo && apollo.data ? Object.keys(apollo.data).reduce( (dg, k) => apollo.data[k].__typename === 'DeploymentGroup' && apollo.data[k].slug === deploymentGroupSlug ? apollo.data[k] : dg, null ) : null ); const serviceBySlug = serviceSlug => createSelector( [apollo], apollo => apollo && apollo.data ? Object.keys(apollo.data).reduce( (s, k) => apollo.data[k].__typename === 'Service' && apollo.data[k].slug === serviceSlug ? apollo.data[k] : s, null ) : null ); const instancesByServiceId = serviceId => createSelector( [apollo], apollo => apollo && apollo.data ? Object.keys(apollo.data).reduce((is, i, k) => { if ( apollo.data[k].__typename === 'Instance' && apollo.data[k].service === serviceId ) { is.push(apollo.data[k]); } return is; }, []) : null ); // Apollo gql utils // const findService = (services, uuid) => services.reduce((service, s) => (s.uuid === uuid ? s : service), null); const activeInstanceStatuses = [ 'PROVISIONING', 'READY', 'ACTIVE', 'RUNNING', 'STOPPING', 'INCOMPLETE' ]; const transitionalServiceStatuses = [ 'PROVISIONING', 'SCALING', 'STOPPING', 'DELETING', 'RESTARTING' ]; 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 getInstancesActive = instanceStatuses => { return instanceStatuses.reduce( (active, instanceStatus) => activeInstanceStatuses.indexOf(instanceStatus.status) === -1 ? active : true, false ); }; 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' }); }; const processServices = services => { return forceArray(services).reduce((ss, s, i) => { if(s.status !== 'DELETED') { const service = getService(s, i); if(s.branches && s.branches.length) { service.children = processServices(s.branches) } ss.push(service); } return ss; }, []); }; const processServicesForTopology = services => { const processedServices = processServices(services); const connectedServices = processedServices.reduce( (connections, service) => { if(!service.connections || !service.connections.length) { return connections; } const existingConnections = service.connections.reduce((connections, connection) => { const connectionExists = processedServices.filter(ps => ps.id === connection).length; if(connectionExists) { connections.push(connection); } return connections; }, []); return existingConnections.length ? connections.concat(existingConnections).concat(service.id) : connections }, []); return processedServices.map(service => ({ ...service, connected: connectedServices.indexOf(service.id) !== -1 })); }; export { deploymentGroupBySlug as deploymentGroupBySlugSelector, serviceBySlug as serviceBySlugSelector, processServices, processServicesForTopology, instancesByServiceId };