mirror of
https://github.com/yldio/copilot.git
synced 2024-11-28 14:10:04 +02:00
Add services list view
This commit is contained in:
parent
7d39da51ed
commit
db4ac69452
@ -1 +1,2 @@
|
|||||||
export { default as EmptyServices } from './empty';
|
export { default as EmptyServices } from './empty';
|
||||||
|
export { default as ServiceListItem } from './list-item';
|
||||||
|
145
frontend/src/components/services/list-item.js
Normal file
145
frontend/src/components/services/list-item.js
Normal file
@ -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) => (
|
||||||
|
<ServiceListItem
|
||||||
|
key={service.uuid}
|
||||||
|
deploymentGroup={deploymentGroup}
|
||||||
|
service={service}
|
||||||
|
/>
|
||||||
|
)) : null;
|
||||||
|
|
||||||
|
const to = `/deploymentGroups/${deploymentGroup}/services/${service.id}`;
|
||||||
|
|
||||||
|
const title = service.parent ? (
|
||||||
|
<ListItemTitle>
|
||||||
|
{service.name}
|
||||||
|
</ListItemTitle>
|
||||||
|
) : (
|
||||||
|
<ListItemTitle>
|
||||||
|
<TitleInnerContainer>
|
||||||
|
<StyledFormGroup>
|
||||||
|
<Checkbox />
|
||||||
|
</StyledFormGroup>
|
||||||
|
<Link secondary to={to}>
|
||||||
|
{service.name}
|
||||||
|
</Link>
|
||||||
|
</TitleInnerContainer>
|
||||||
|
</ListItemTitle>
|
||||||
|
);
|
||||||
|
|
||||||
|
const subtitle = (
|
||||||
|
<ListItemSubTitle>{service.instances} instances</ListItemSubTitle>
|
||||||
|
);
|
||||||
|
|
||||||
|
const onOptionsClick = (evt) => {
|
||||||
|
// onQuickActions(evt, service.uuid);
|
||||||
|
};
|
||||||
|
|
||||||
|
const header = isChild ? null : (
|
||||||
|
<ListItemHeader>
|
||||||
|
<ListItemMeta>
|
||||||
|
{title}
|
||||||
|
<ListItemDescription>
|
||||||
|
<ListItemInfo
|
||||||
|
icon={<InstancesMultipleIcon />}
|
||||||
|
iconPosition='top'
|
||||||
|
label={`${service.instances} ${service.instances > 1 ?
|
||||||
|
'instances' : 'instance' }`}
|
||||||
|
/>
|
||||||
|
{ /* <ListItemInfo
|
||||||
|
icon={<DataCentersIcon />}
|
||||||
|
label={service.datacenters[0].id}
|
||||||
|
/>*/ }
|
||||||
|
</ListItemDescription>
|
||||||
|
</ListItemMeta>
|
||||||
|
<ListItemOptions onClick={onOptionsClick} />
|
||||||
|
</ListItemHeader>
|
||||||
|
);
|
||||||
|
|
||||||
|
const view = children ? (
|
||||||
|
<ListItemGroupView>
|
||||||
|
{children}
|
||||||
|
</ListItemGroupView>
|
||||||
|
) : (
|
||||||
|
<ListItemView>
|
||||||
|
<ListItemMeta>
|
||||||
|
{isChild && title}
|
||||||
|
{isChild && subtitle}
|
||||||
|
<ListItemDescription>
|
||||||
|
<ListItemInfo
|
||||||
|
icon={<HealthyIcon />}
|
||||||
|
label='Healthy'
|
||||||
|
/>
|
||||||
|
</ListItemDescription>
|
||||||
|
</ListItemMeta>
|
||||||
|
{ /* <ItemMetricGroup
|
||||||
|
datasets={service.metrics}
|
||||||
|
/> */ }
|
||||||
|
</ListItemView>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ListItem
|
||||||
|
collapsed={service.collapsed}
|
||||||
|
flat={isChild}
|
||||||
|
headed={!isChild}
|
||||||
|
key={service.uuid}
|
||||||
|
stacked={isChild && (service.instances > 1)}
|
||||||
|
>
|
||||||
|
{header}
|
||||||
|
{view}
|
||||||
|
</ListItem>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ServiceListItem.propTypes = {
|
||||||
|
// onQuickActions: React.PropTypes.func,
|
||||||
|
deploymentGroup: React.PropTypes.string,
|
||||||
|
service: PropTypes.object.isRequired // define better
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ServiceListItem;
|
@ -1,43 +1,67 @@
|
|||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { graphql } from 'react-apollo';
|
import { compose, graphql } from 'react-apollo';
|
||||||
import { Link } from 'react-router-dom';
|
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 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 {
|
class ServiceList extends Component {
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
|
||||||
const {
|
const {
|
||||||
location,
|
location,
|
||||||
|
deploymentGroup,
|
||||||
services,
|
services,
|
||||||
loading,
|
loading,
|
||||||
error
|
error
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const serviceList =
|
console.log('services = ', services);
|
||||||
loading ? <p>Loading...</p> :
|
|
||||||
error ? <p>Error!!!</p> :
|
if(loading || error) {
|
||||||
services.map((service, index) =>
|
return (
|
||||||
<p key={index}>
|
<p>Loading OR error</p>
|
||||||
<Link
|
);
|
||||||
to={`${location.pathname.replace('services-list', 'services')}/${service.slug}/instances`}
|
}
|
||||||
>
|
|
||||||
{service.name}
|
const serviceList = services.map((service) => (
|
||||||
</Link>
|
<ServiceListItem
|
||||||
</p>);
|
key={service.uuid}
|
||||||
|
onQuickActions={null /*onQuickActions*/}
|
||||||
|
deploymentGroup={deploymentGroup.slug}
|
||||||
|
service={service}
|
||||||
|
uiTooltip={null /* uiTooltip */}
|
||||||
|
/>
|
||||||
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<LayoutContainer>
|
||||||
<div>
|
<StyledContainer>
|
||||||
<h2>Service List</h2>
|
<div>
|
||||||
</div>
|
{ /* <div ref={this.ref('container')}> */ }
|
||||||
{ serviceList }
|
{serviceList}
|
||||||
</div>
|
{ /* <ServicesTooltip {...uiTooltip} onBlur={handleTooltipBlur} /> */ }
|
||||||
|
</div>
|
||||||
|
</StyledContainer>
|
||||||
|
</LayoutContainer>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServiceListWithData = graphql(ServicesQuery, {
|
const PortalGql = graphql(PortalQuery, {});
|
||||||
|
|
||||||
|
const ServicesGql = graphql(ServicesQuery, {
|
||||||
options(props) {
|
options(props) {
|
||||||
return {
|
return {
|
||||||
variables: {
|
variables: {
|
||||||
@ -46,10 +70,17 @@ const ServiceListWithData = graphql(ServicesQuery, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: ({ data: { deploymentGroup, loading, error }}) => ({
|
props: ({ data: { deploymentGroup, loading, error }}) => ({
|
||||||
services: deploymentGroup ? deploymentGroup.services : null,
|
deploymentGroup,
|
||||||
|
services: deploymentGroup ?
|
||||||
|
processServices(deploymentGroup.services, null) : null,
|
||||||
loading,
|
loading,
|
||||||
error
|
error
|
||||||
})
|
})
|
||||||
})(ServiceList);
|
});
|
||||||
|
|
||||||
|
const ServiceListWithData = compose(
|
||||||
|
PortalGql,
|
||||||
|
ServicesGql
|
||||||
|
)(ServiceList);
|
||||||
|
|
||||||
export default ServiceListWithData;
|
export default ServiceListWithData;
|
||||||
|
@ -5,6 +5,8 @@ import styled from 'styled-components';
|
|||||||
import PortalQuery from '@graphql/Portal.gql';
|
import PortalQuery from '@graphql/Portal.gql';
|
||||||
import ServicesQuery from '@graphql/ServicesTopology.gql';
|
import ServicesQuery from '@graphql/ServicesTopology.gql';
|
||||||
|
|
||||||
|
import { processServices } from '@root/state/selectors';
|
||||||
|
|
||||||
import { LayoutContainer } from '@components/layout';
|
import { LayoutContainer } from '@components/layout';
|
||||||
import { Loader, ErrorMessage } from '@components/messaging';
|
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 (
|
return (
|
||||||
<StyledBackground>
|
<StyledBackground>
|
||||||
<StyledContainer>
|
<StyledContainer>
|
||||||
<TopologyGraph
|
<TopologyGraph
|
||||||
services={ss}
|
services={services}
|
||||||
/>
|
/>
|
||||||
</StyledContainer>
|
</StyledContainer>
|
||||||
</StyledBackground>
|
</StyledBackground>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PortalGql = graphql(PortalQuery, {
|
const PortalGql = graphql(PortalQuery, {});
|
||||||
props: ({ data: { portal, loading, error }}) => ({
|
|
||||||
datacenter: portal ? portal.datacenter.id : null,
|
|
||||||
loading,
|
|
||||||
error
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
const ServicesGql = graphql(ServicesQuery, {
|
const ServicesGql = graphql(ServicesQuery, {
|
||||||
options(props) {
|
options(props) {
|
||||||
@ -114,7 +73,8 @@ const ServicesGql = graphql(ServicesQuery, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
props: ({ data: { deploymentGroup, loading, error }}) => ({
|
props: ({ data: { deploymentGroup, loading, error }}) => ({
|
||||||
services: deploymentGroup ? deploymentGroup.services : null,
|
services: deploymentGroup ?
|
||||||
|
processServices(deploymentGroup.services, null) : null,
|
||||||
loading,
|
loading,
|
||||||
error
|
error
|
||||||
})
|
})
|
||||||
|
@ -6,6 +6,10 @@ query Services($deploymentGroupSlug: String!){
|
|||||||
...DeploymentGroupInfo
|
...DeploymentGroupInfo
|
||||||
services {
|
services {
|
||||||
...ServiceInfo
|
...ServiceInfo
|
||||||
|
parent
|
||||||
|
instances {
|
||||||
|
uuid
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,11 +45,11 @@ const Router = (
|
|||||||
<Route path='/deployment-groups/:deploymentGroup/services' exact component={deploymentGroupRedirect} />
|
<Route path='/deployment-groups/:deploymentGroup/services' exact component={deploymentGroupRedirect} />
|
||||||
<Route path='/deployment-groups/:deploymentGroup/instances' exact component={InstanceList} />
|
<Route path='/deployment-groups/:deploymentGroup/instances' exact component={InstanceList} />
|
||||||
|
|
||||||
<Route path={`/deployment-groups/:deploymentGroup/services-list`} exact component={ServicesMenu} />
|
<Route path='/deployment-groups/:deploymentGroup/services-list' exact component={ServicesMenu} />
|
||||||
<Route path='/deployment-groups/:deploymentGroup/services-list' exact component={ServiceList} />
|
<Route path='/deployment-groups/:deploymentGroup/services-list' exact component={ServiceList} />
|
||||||
|
|
||||||
<Route path={`/deployment-groups/:deploymentGroup/services-topology`} exact component={ServicesMenu} />
|
<Route path='/deployment-groups/:deploymentGroup/services-topology' exact component={ServicesMenu} />
|
||||||
<Route path={`/deployment-groups/:deploymentGroup/services-topology`} exact component={ServicesTopology} />
|
<Route path='/deployment-groups/:deploymentGroup/services-topology' exact component={ServicesTopology} />
|
||||||
|
|
||||||
<Route path='/deployment-groups/:deploymentGroup/services/:service/instances' exact component={InstanceList} />
|
<Route path='/deployment-groups/:deploymentGroup/services/:service/instances' exact component={InstanceList} />
|
||||||
|
|
||||||
|
@ -2,7 +2,9 @@ import { createSelector } from 'reselect';
|
|||||||
|
|
||||||
const apollo = (state) => state.apollo;
|
const apollo = (state) => state.apollo;
|
||||||
|
|
||||||
const deploymentGroupById = (deploymentGroupSlug) => createSelector(
|
// redux selectors //
|
||||||
|
|
||||||
|
const deploymentGroupBySlug = (deploymentGroupSlug) => createSelector(
|
||||||
[apollo],
|
[apollo],
|
||||||
(apollo) => apollo ? Object.keys(apollo).reduce((dg, k) =>
|
(apollo) => apollo ? Object.keys(apollo).reduce((dg, k) =>
|
||||||
apollo[k].__typename === 'DeploymentGroup' &&
|
apollo[k].__typename === 'DeploymentGroup' &&
|
||||||
@ -10,7 +12,7 @@ const deploymentGroupById = (deploymentGroupSlug) => createSelector(
|
|||||||
apollo[k] : dg, {}) : null
|
apollo[k] : dg, {}) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
const servicesById = (serviceSlug) => createSelector(
|
const servicesBySlug = (serviceSlug) => createSelector(
|
||||||
[apollo],
|
[apollo],
|
||||||
(apollo) => apollo ? Object.keys(apollo).reduce((s, k) =>
|
(apollo) => apollo ? Object.keys(apollo).reduce((s, k) =>
|
||||||
apollo[k].__typename === 'Service' &&
|
apollo[k].__typename === 'Service' &&
|
||||||
@ -18,7 +20,50 @@ const servicesById = (serviceSlug) => createSelector(
|
|||||||
apollo[k] : s, {}) : null
|
apollo[k] : s, {}) : null
|
||||||
);
|
);
|
||||||
|
|
||||||
export {
|
// apollo gql utils //
|
||||||
deploymentGroupById as deploymentGroupByIdSelector,
|
|
||||||
servicesById as servicesByIdSelector
|
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
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user