Merge pull request #336 from yldio/feature/add-topology-view
Add topology view
This commit is contained in:
commit
08acbe5944
71
frontend/src/components/services/view.js
Normal file
71
frontend/src/components/services/view.js
Normal 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;
|
@ -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?'
|
||||||
|
@ -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(
|
||||||
|
56
frontend/src/containers/services/list.js
Normal file
56
frontend/src/containers/services/list.js
Normal 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);
|
@ -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
|
|
||||||
};
|
|
||||||
|
@ -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
|
||||||
|
@ -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}
|
||||||
|
@ -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;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user