Merge pull request #336 from yldio/feature/add-topology-view

Add topology view
This commit is contained in:
Alex Windett 2017-03-01 10:38:53 +00:00 committed by GitHub
commit 08acbe5944
8 changed files with 183 additions and 75 deletions

View File

@ -0,0 +1,71 @@
import React from 'react';
import EmptyServices from '@components/empty/services';
import PropTypes from '@root/prop-types';
import Row from '@ui/components/row';
import Column from '@ui/components/column';
import { H2 } from '@ui/components/base-elements';
import {
FormGroup,
Toggle,
ToggleList
} from '@ui/components/form';
const ServicesView = ({
children,
org = {},
match = {},
project = {},
routerPush = {},
services = []
}) => {
const toggle = () => {
if(!services) {
return null;
}
const value = match.path === '/:org/projects/:projectId/services' ?
'topology' : 'list';
const onToggleChange = (evt) => {
evt.preventDefault();
const value = evt.target.value;
const path = `/${org.id}/projects/${project.id}/services${
value === 'list' ? '/list' : ''
}`;
routerPush(path);
};
return (
<FormGroup name='service-view' value={value}>
<ToggleList>
<Toggle value='topology' onChange={onToggleChange}>Topology</Toggle>
<Toggle value='list' onChange={onToggleChange}>List</Toggle>
</ToggleList>
</FormGroup>
);
};
const content = services.length ?
children : <EmptyServices />;
return (
<Row>
<Column xs={12}>
<H2>Services</H2>
{ toggle() }
{ content }
</Column>
</Row>
);
};
ServicesView.propTypes = {
children: React.PropTypes.node,
match: React.PropTypes.object.isRequired,
org: PropTypes.org,
project: PropTypes.project,
routerPush: React.PropTypes.func.isRequired,
services: React.PropTypes.arrayOf(PropTypes.service)
};
export default ServicesView;

View File

@ -1,23 +1,35 @@
import React from 'react'; import React from 'react';
import { Switch, Route } from 'react-router-dom'; import { Switch, Route } from 'react-router-dom';
import Section from './section'; import Section from './section';
import Services from '@containers/services'; import ServicesTopology from '@containers/services';
import ServicesList from '@containers/services/list';
import Service from '@containers/service'; import Service from '@containers/service';
export default () => { export default () => {
const topology = (props) => (
<Section {...props}>
<ServicesTopology {...props} />
</Section>
);
const list = (props) => ( const list = (props) => (
<Section {...props}> <Section {...props}>
<Services {...props} /> <ServicesList {...props} />
</Section> </Section>
); );
return ( return (
<Switch> <Switch>
<Route <Route
component={list} component={topology}
exact exact
path='/:org/projects/:projectId/services' path='/:org/projects/:projectId/services'
/> />
<Route
component={list}
exact
path='/:org/projects/:projectId/services/list'
/>
<Route <Route
component={Service} component={Service}
path='/:org/projects/:projectId/services/:serviceId/:section?' path='/:org/projects/:projectId/services/:serviceId/:section?'

View File

@ -1,68 +1,42 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import EmptyServices from '@components/empty/services';
import PropTypes from '@root/prop-types'; import PropTypes from '@root/prop-types';
import ServiceItem from '@components/service/item'; import { TopologyGraph } from '@ui/components/topology';
import ServiceViewToggle from '@components/service/view-toggle'; import ServicesView from '@components/services/view';
import Row from '@ui/components/row';
import Column from '@ui/components/column';
import { H2 } from '@ui/components/base-elements';
import { import {
orgByIdSelector, orgByIdSelector,
projectByIdSelector, projectByIdSelector,
servicesByProjectIdSelector,
servicesForTopologySelector servicesForTopologySelector
} from '@state/selectors'; } from '@state/selectors';
const Services = ({ const Services = (props) => {
org = {},
project = {},
services = [],
servicesForTopology = []
}) => {
const empty = services.length ? null : (
<EmptyServices />
);
const serviceList = services.map((service) => ( const {
<ServiceItem services = []
key={service.uuid} } = props;
org={org.id}
project={project.id}
service={service}
/>
));
return ( return (
<Row> <ServicesView {...props}>
<Column xs={12}> <TopologyGraph services={services} />
<H2>Services</H2> </ServicesView>
<ServiceViewToggle />
{empty}
{serviceList}
</Column>
</Row>
); );
}; };
Services.propTypes = { Services.propTypes = {
org: PropTypes.org, services: React.PropTypes.arrayOf(PropTypes.service)
project: PropTypes.project,
services: React.PropTypes.arrayOf(PropTypes.service),
servicesForTopology: React.PropTypes.arrayOf(React.PropTypes.object)
}; };
const mapStateToProps = (state, { const mapStateToProps = (state, {
match = { match = {
params: {} params: {}
} },
push
}) => ({ }) => ({
org: orgByIdSelector(match.params.org)(state), org: orgByIdSelector(match.params.org)(state),
project: projectByIdSelector(match.params.projectId)(state), project: projectByIdSelector(match.params.projectId)(state),
services: servicesByProjectIdSelector(match.params.projectId)(state), routerPush: push,
servicesForTopology: services: servicesForTopologySelector(match.params.projectId)(state)
servicesForTopologySelector(match.params.projectId)(state)
}); });
export default connect( export default connect(

View File

@ -0,0 +1,56 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from '@root/prop-types';
import ServiceItem from '@components/service/item';
import ServicesView from '@components/services/view';
import {
orgByIdSelector,
projectByIdSelector,
servicesByProjectIdSelector
} from '@state/selectors';
const Services = (props) => {
const {
org = {},
project = {},
services = []
} = props;
const serviceList = services.map((service) => (
<ServiceItem
key={service.uuid}
org={org.id}
project={project.id}
service={service}
/>
));
return (
<ServicesView {...props}>
{serviceList}
</ServicesView>
);
};
Services.propTypes = {
org: PropTypes.org,
project: PropTypes.project,
services: React.PropTypes.arrayOf(PropTypes.service)
};
const mapStateToProps = (state, {
match = {
params: {}
},
push
}) => ({
org: orgByIdSelector(match.params.org)(state),
project: projectByIdSelector(match.params.projectId)(state),
routerPush: push,
services: servicesByProjectIdSelector(match.params.projectId)(state)
});
export default connect(
mapStateToProps
)(Services);

View File

@ -1,22 +1,12 @@
import Checkbox from './checkbox'; export { default as Checkbox } from './checkbox';
import Fieldset from './fieldset'; export { default as Fieldset } from './fieldset';
import FormGroup from './group'; export { default as FormGroup } from './group';
import Input from './input'; export { default as Input } from './input';
import FormLabel from './label'; export { default as FormLabel } from './label';
import Legend from './legend'; export { default as Legend } from './legend';
import FormMeta from './meta'; export { default as FormMeta } from './meta';
import Radio, { RadioList } from './radio'; export { default as Radio } from './radio';
import Select from './select'; export { RadioList as RadioList } from './radio';
export { default as Select } from './select';
export { export { default as Toggle } from './toggle';
Checkbox, export { ToggleList as ToggleList } from './toggle';
Fieldset,
FormGroup,
Input,
FormLabel,
Legend,
FormMeta,
Radio,
RadioList,
Select
};

View File

@ -5,6 +5,7 @@ import { Subscriber } from 'react-broadcast';
import { Baseline } from '../../../shared/composers'; import { Baseline } from '../../../shared/composers';
import BaseInput from '../base-input'; import BaseInput from '../base-input';
import { boxes, colors } from '../../../shared/constants'; import { boxes, colors } from '../../../shared/constants';
import { rndId } from '../../../shared/functions';
const Input = styled.input` const Input = styled.input`
display: none; display: none;
@ -91,16 +92,20 @@ const Toggle = BaseInput(({
...props ...props
}) => { }) => {
const render = (value) => { const render = (value) => {
const id = rndId();
return ( return (
<StyledLi> <StyledLi>
<InputContainer> <InputContainer>
<Input <Input
{...props} // eslint-disable-next-line react/prop-types
checked={value.value === props.value}
{...value} {...value}
{...props}
id={id}
type='radio' type='radio'
/> />
<Label <Label
htmlFor={value.id} htmlFor={id}
// eslint-disable-next-line react/prop-types // eslint-disable-next-line react/prop-types
error={props.error} error={props.error}
// eslint-disable-next-line react/prop-types // eslint-disable-next-line react/prop-types

View File

@ -1,8 +1,8 @@
import { Baseline } from '../../shared/composers'; import { Baseline } from '../../shared/composers';
import PropTypes from './prop-types'; import PropTypes from './prop-types';
import HeartIcon from './icon-heart.svg'; // import HeartIcon from './icon-heart.svg';
import GraphNodeButton from './graph-node-button'; import GraphNodeButton from './graph-node-button';
import GraphNodeInfo from './graph-node-info'; // import GraphNodeInfo from './graph-node-info';
import GraphNodeMetrics from './graph-node-metrics'; import GraphNodeMetrics from './graph-node-metrics';
import styled from 'styled-components'; import styled from 'styled-components';
import React from 'react'; import React from 'react';
@ -65,10 +65,10 @@ const GraphNode = ({
}; };
const paddingLeft = 18; const paddingLeft = 18;
const infoPosition = { /*const infoPosition = {
x: paddingLeft, x: paddingLeft,
y: 59 y: 59
}; };*/
const metricsPosition = { const metricsPosition = {
x: paddingLeft, x: paddingLeft,
y: 89 y: 89
@ -145,20 +145,20 @@ const GraphNode = ({
cy={9} cy={9}
r={9} r={9}
/> />
<HeartIcon /> {/*<HeartIcon />*/}
</g> </g>
<GraphNodeButton <GraphNodeButton
buttonRect={buttonRect} buttonRect={buttonRect}
onButtonClick={onButtonClick} onButtonClick={onButtonClick}
connected={connected} connected={connected}
/> />
<GraphNodeInfo {/*<GraphNodeInfo
datacentres={data.datacentres} datacentres={data.datacentres}
instances={data.instances} instances={data.instances}
healthy healthy
infoPosition={infoPosition} infoPosition={infoPosition}
connected={connected} connected={connected}
/> />*/}
<GraphNodeMetrics <GraphNodeMetrics
metrics={data.metrics} metrics={data.metrics}
metricsPosition={metricsPosition} metricsPosition={metricsPosition}

View File

@ -8,7 +8,6 @@ import React from 'react';
const StyledSvg = styled.svg` const StyledSvg = styled.svg`
width: 1024px; width: 1024px;
height: 860px; height: 860px;
border: 1px solid #ff0000;
`; `;
const nodeSize = { const nodeSize = {
@ -28,6 +27,7 @@ let dragInfo = {
}; };
class TopologyGraph extends React.Component { class TopologyGraph extends React.Component {
componentWillMount() { componentWillMount() {
const services = this.props.services; const services = this.props.services;