From db4ac694529ba89148c129048a6b95117275d387 Mon Sep 17 00:00:00 2001 From: JUDIT GRESKOVITS Date: Thu, 18 May 2017 22:04:29 +0100 Subject: [PATCH] Add services list view --- frontend/src/components/services/index.js | 1 + frontend/src/components/services/list-item.js | 145 ++++++++++++++++++ frontend/src/containers/services/list.js | 75 ++++++--- frontend/src/containers/services/topology.js | 52 +------ frontend/src/graphql/Services.gql | 4 + frontend/src/router.js | 6 +- frontend/src/state/selectors.js | 55 ++++++- 7 files changed, 262 insertions(+), 76 deletions(-) create mode 100644 frontend/src/components/services/list-item.js diff --git a/frontend/src/components/services/index.js b/frontend/src/components/services/index.js index ff8529ba..ec05ff7a 100644 --- a/frontend/src/components/services/index.js +++ b/frontend/src/components/services/index.js @@ -1 +1,2 @@ export { default as EmptyServices } from './empty'; +export { default as ServiceListItem } from './list-item'; diff --git a/frontend/src/components/services/list-item.js b/frontend/src/components/services/list-item.js new file mode 100644 index 00000000..5b0efbfa --- /dev/null +++ b/frontend/src/components/services/list-item.js @@ -0,0 +1,145 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import styled from 'styled-components'; +// import forceArray from 'force-array'; + +// import ItemMetricGroup from '@components/item-metric-group'; +import { Link } from '@ui/components/anchor'; +import { Checkbox, FormGroup } from '@ui/components/form'; +import { + DataCentersIcon, + HealthyIcon, + InstancesMultipleIcon +} from '@ui/components/icons'; + +import { + ListItem, + ListItemView, + ListItemMeta, + ListItemTitle, + ListItemSubTitle, + ListItemDescription, + ListItemGroupView, + ListItemOptions, + ListItemHeader, + ListItemInfo +} from '@ui/components/list'; + +const StyledFormGroup = styled(FormGroup)` + width: auto; +`; + +const TitleInnerContainer = styled.div` + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; +`; + +const ServiceListItem = ({ + // onQuickActions=() => {}, + deploymentGroup = '', + service = {} +}) => { + const isChild = !!service.parent; + + const children = service.children ? + service.children.map((service) => ( + + )) : null; + + const to = `/deploymentGroups/${deploymentGroup}/services/${service.id}`; + + const title = service.parent ? ( + + {service.name} + + ) : ( + + + + + + + {service.name} + + + + ); + + const subtitle = ( + {service.instances} instances + ); + + const onOptionsClick = (evt) => { + // onQuickActions(evt, service.uuid); + }; + + const header = isChild ? null : ( + + + {title} + + } + iconPosition='top' + label={`${service.instances} ${service.instances > 1 ? + 'instances' : 'instance' }`} + /> + { /* } + label={service.datacenters[0].id} + />*/ } + + + + + ); + + const view = children ? ( + + {children} + + ) : ( + + + {isChild && title} + {isChild && subtitle} + + } + label='Healthy' + /> + + + { /* */ } + + ); + + return ( + 1)} + > + {header} + {view} + + ); +}; + +ServiceListItem.propTypes = { + // onQuickActions: React.PropTypes.func, + deploymentGroup: React.PropTypes.string, + service: PropTypes.object.isRequired // define better +}; + +export default ServiceListItem; diff --git a/frontend/src/containers/services/list.js b/frontend/src/containers/services/list.js index 77c10b4d..779987f9 100644 --- a/frontend/src/containers/services/list.js +++ b/frontend/src/containers/services/list.js @@ -1,43 +1,67 @@ import React, { Component } from 'react'; -import { graphql } from 'react-apollo'; -import { Link } from 'react-router-dom'; +import { compose, graphql } from 'react-apollo'; +import { connect } from 'react-redux'; +import styled from 'styled-components'; +// import { Link } from 'react-router-dom'; +import PortalQuery from '@graphql/Portal.gql'; import ServicesQuery from '@graphql/Services.gql'; +import { processServices } from '@root/state/selectors'; + +import { LayoutContainer } from '@components/layout'; +import { ServiceListItem } from '@components/services'; + +const StyledContainer = styled.div` + position: relative; +`; + class ServiceList extends Component { render() { const { location, + deploymentGroup, services, loading, error } = this.props; - const serviceList = - loading ?

Loading...

: - error ?

Error!!!

: - services.map((service, index) => -

- - {service.name} - -

); + console.log('services = ', services); + + if(loading || error) { + return ( +

Loading OR error

+ ); + } + + const serviceList = services.map((service) => ( + + )); return ( -
-
-

Service List

-
- { serviceList } -
+ + +
+ { /*
*/ } + {serviceList} + { /* */ } +
+ + ); } } -const ServiceListWithData = graphql(ServicesQuery, { +const PortalGql = graphql(PortalQuery, {}); + +const ServicesGql = graphql(ServicesQuery, { options(props) { return { variables: { @@ -46,10 +70,17 @@ const ServiceListWithData = graphql(ServicesQuery, { } }, props: ({ data: { deploymentGroup, loading, error }}) => ({ - services: deploymentGroup ? deploymentGroup.services : null, + deploymentGroup, + services: deploymentGroup ? + processServices(deploymentGroup.services, null) : null, loading, error }) -})(ServiceList); +}); + +const ServiceListWithData = compose( + PortalGql, + ServicesGql +)(ServiceList); export default ServiceListWithData; diff --git a/frontend/src/containers/services/topology.js b/frontend/src/containers/services/topology.js index 10c2cf4a..ec69408d 100644 --- a/frontend/src/containers/services/topology.js +++ b/frontend/src/containers/services/topology.js @@ -5,6 +5,8 @@ import styled from 'styled-components'; import PortalQuery from '@graphql/Portal.gql'; import ServicesQuery from '@graphql/ServicesTopology.gql'; +import { processServices } from '@root/state/selectors'; + import { LayoutContainer } from '@components/layout'; import { Loader, ErrorMessage } from '@components/messaging'; @@ -49,61 +51,18 @@ const ServicesTopology = ({ ) } - const findService = (ss, uuid) => - ss.reduce((s, service) => service.uuid === uuid ? - service : s, null); - - const getService = (s, i) => ({ - index: i, - ...s, - metrics: [1, 2, 3].map((m) => ({ - name: `${m}`, - value: `${m}` - })), - instances: s.instances.length, - datacenter: datacenter - }); - - // Selector??? - const ss = 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 }; - ss.push(parent); - } - if(!parent.children) { - parent.children = []; - } - parent.children.push(getService(s, i)); - } - if(!s.parent) { - ss.push(getService(s, i)); - } - return ss; - }, []); - return ( ); } -const PortalGql = graphql(PortalQuery, { - props: ({ data: { portal, loading, error }}) => ({ - datacenter: portal ? portal.datacenter.id : null, - loading, - error - }) -}) +const PortalGql = graphql(PortalQuery, {}); const ServicesGql = graphql(ServicesQuery, { options(props) { @@ -114,7 +73,8 @@ const ServicesGql = graphql(ServicesQuery, { } }, props: ({ data: { deploymentGroup, loading, error }}) => ({ - services: deploymentGroup ? deploymentGroup.services : null, + services: deploymentGroup ? + processServices(deploymentGroup.services, null) : null, loading, error }) diff --git a/frontend/src/graphql/Services.gql b/frontend/src/graphql/Services.gql index a572584d..4fe85705 100644 --- a/frontend/src/graphql/Services.gql +++ b/frontend/src/graphql/Services.gql @@ -6,6 +6,10 @@ query Services($deploymentGroupSlug: String!){ ...DeploymentGroupInfo services { ...ServiceInfo + parent + instances { + uuid + } } } } diff --git a/frontend/src/router.js b/frontend/src/router.js index b05a0e82..0a8139b0 100644 --- a/frontend/src/router.js +++ b/frontend/src/router.js @@ -45,11 +45,11 @@ const Router = ( - + - - + + diff --git a/frontend/src/state/selectors.js b/frontend/src/state/selectors.js index 248cc5ef..231b685e 100644 --- a/frontend/src/state/selectors.js +++ b/frontend/src/state/selectors.js @@ -2,7 +2,9 @@ import { createSelector } from 'reselect'; const apollo = (state) => state.apollo; -const deploymentGroupById = (deploymentGroupSlug) => createSelector( +// redux selectors // + +const deploymentGroupBySlug = (deploymentGroupSlug) => createSelector( [apollo], (apollo) => apollo ? Object.keys(apollo).reduce((dg, k) => apollo[k].__typename === 'DeploymentGroup' && @@ -10,7 +12,7 @@ const deploymentGroupById = (deploymentGroupSlug) => createSelector( apollo[k] : dg, {}) : null ); -const servicesById = (serviceSlug) => createSelector( +const servicesBySlug = (serviceSlug) => createSelector( [apollo], (apollo) => apollo ? Object.keys(apollo).reduce((s, k) => apollo[k].__typename === 'Service' && @@ -18,7 +20,50 @@ const servicesById = (serviceSlug) => createSelector( apollo[k] : s, {}) : null ); -export { - deploymentGroupById as deploymentGroupByIdSelector, - servicesById as servicesByIdSelector +// apollo gql utils // + +const findService = (services, uuid) => + services.reduce((service, s) => s.uuid === uuid ? + s : service, null); + +const getService = (service, index, datacenter) => ({ + index, + ...service, + // tmp for topology + metrics: [1, 2, 3].map((m) => ({ + name: `${m}`, + value: `${m}` + })), + instances: service.instances.length, + datacenter +}); + +const processServices = (services, datacenter) => { + console.log('services = ', services); + return 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 }; + ss.push(parent); + } + if(!parent.children) { + parent.children = []; + } + parent.children.push(getService(s, i, datacenter)); + } + if(!s.parent) { + ss.push(getService(s, i, datacenter)); + } + return ss; + }, []); +} + +export { + deploymentGroupBySlug as deploymentGroupBySlugSelector, + servicesBySlug as servicesBySlugSelector, + processServices as processServices }