feat(cp-frontend, ui-toolkit): Resize nodes and topolgy

This commit is contained in:
JUDIT GRESKOVITS 2017-06-27 17:19:27 +01:00 committed by Sérgio Ramos
parent 5dab93e59e
commit 8e90dbfa56
11 changed files with 148 additions and 94 deletions

View File

@ -6,6 +6,7 @@
"repository": "github:yldio/joyent-portal",
"main": "src/index.js",
"scripts": {
"dev": "REACT_APP_GQL_PORT=3000 PORT=3069 react-scripts start",
"start": "PORT=3069 react-scripts start",
"build": "react-scripts build",
"lint:css": "echo 0",

View File

@ -62,13 +62,8 @@ const findService = (services, uuid) =>
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
datacenter,
isConsul: service.slug === 'consul'
});
const processServices = (services, datacenter) => {
@ -88,7 +83,7 @@ const processServices = (services, datacenter) => {
parent.children.push(getService(s, i, datacenter));
} else {
const serviceIndex = ss.findIndex(existingS => existingS.id === s.id);
if (serviceIndex == -1) {
if (serviceIndex === -1) {
ss.push(getService(s, i, datacenter));
} else {
ss.splice(serviceIndex, 1, {

View File

@ -1,5 +1,5 @@
const Lengths = {
paddingLeft: 18,
paddingLeft: 12,
nodeWidth: 180
};
@ -10,15 +10,22 @@ const Sizes = {
},
contentSize: {
width: Lengths.nodeWidth,
height: 101 // This is the height w/o info comp
// height: 101 // This is the height w/o info comp
height: 42
},
childContentSize: {
width: Lengths.nodeWidth,
height: 64
},
nodeSize: {
width: Lengths.nodeWidth,
height: 156
// height: 156
height: 90
},
nodeSizeWithChildren: {
width: Lengths.nodeWidth,
height: 276
// height: 276
height: 176
}
};
@ -55,6 +62,10 @@ const Rects = {
...Sizes.contentSize,
...Points.contentPosition
},
childContentRect: {
...Sizes.childContentSize,
...Points.contentPosition
},
// Top, bottom, left, right - from 'centre'
nodeRect: {
left: -Sizes.nodeSize.width / 2,

View File

@ -2,8 +2,9 @@
"uuid": "primary-consul",
"id": "consul",
"name": "Consul",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"isConsul": true,
"metrics": [{
"name": "CPU",
"value": "50%"
@ -20,7 +21,7 @@
"uuid": "primary-nginx",
"id": "nginx",
"name": "Nginx",
"instances": 1,
"instances": [""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -87,7 +88,7 @@
"uuid": "primary-mongodb",
"id": "mongodb",
"name": "MongoDB",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -105,7 +106,7 @@
"uuid": 21393,
"id": "accountservice",
"name": "AccountService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -124,7 +125,7 @@
"uuid": 688632,
"id": "addressservice",
"name": "AddressService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -142,7 +143,7 @@
"uuid": 3802,
"id": "bloomreachservice",
"name": "BloomreachService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -160,7 +161,7 @@
"uuid": 211054,
"id": "cartservice",
"name": "CartService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -178,7 +179,7 @@
"uuid": 514555,
"id": "extra service reported by containerpilot: cartservice-https",
"name": "Extra service reported by ContainerPilot: CartService-HTTPS",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -196,7 +197,7 @@
"uuid": 823837,
"id": "cctokenizationclientservice",
"name": "CCTokenizationClientService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -215,7 +216,7 @@
"uuid": 728066,
"id": "checkoutservice",
"name": "CheckoutService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -233,7 +234,7 @@
"uuid": 626040,
"id": "colorswatchservice",
"name": "ColorSwatchService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -251,7 +252,7 @@
"uuid": 39531,
"id": "emailmarketingservice",
"name": "EmailMarketingService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -269,7 +270,7 @@
"uuid": 338897,
"id": "favoriteservice",
"name": "FavoriteService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -287,7 +288,7 @@
"uuid": 870461,
"id": "findinstoreservice",
"name": "FindInStoreService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -306,7 +307,7 @@
"uuid": 306578,
"id": "fitpredictorservice",
"name": "FitpredictorService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -324,7 +325,7 @@
"uuid": 557611,
"id": "hidefromcatalogservice",
"name": "HidefromcatalogService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -342,7 +343,7 @@
"uuid": 24764,
"id": "internationalcheckoutservice",
"name": "InternationalCheckoutService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -360,7 +361,7 @@
"uuid": 866947,
"id": "internationalposervice",
"name": "InternationalPOService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -378,7 +379,7 @@
"uuid": 521183,
"id": "internationalshippingservice",
"name": "InternationalShippingService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -397,7 +398,7 @@
"uuid": 920500,
"id": "inventoryservice",
"name": "InventoryService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -415,7 +416,7 @@
"uuid": 673424,
"id": "localizationservice",
"name": "LocalizationService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -433,7 +434,7 @@
"uuid": 752876,
"id": "moreaccountservice",
"name": "MoreAccountService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -451,7 +452,7 @@
"uuid": 125936,
"id": "navigationservice",
"name": "NavigationService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -469,7 +470,7 @@
"uuid": 195071,
"id": "ordercreationjob",
"name": "OrderCreationJob",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -488,7 +489,7 @@
"uuid": 101278,
"id": "orderservice",
"name": "OrderService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -506,7 +507,7 @@
"uuid": 766252,
"id": "orderservice",
"name": "OrderService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -524,7 +525,7 @@
"uuid": 272044,
"id": "paymentmethodservice",
"name": "PaymentMethodService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -542,7 +543,7 @@
"uuid": 579947,
"id": "paymentservice",
"name": "PaymentService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -560,7 +561,7 @@
"uuid": 211151,
"id": "paymentservice",
"name": "PaymentService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -579,7 +580,7 @@
"uuid": 712793,
"id": "priceservice",
"name": "PriceService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -597,7 +598,7 @@
"uuid": 831906,
"id": "privatesaleservice",
"name": "PrivatesaleService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -615,7 +616,7 @@
"uuid": 897694,
"id": "productarrayservice",
"name": "ProductArrayService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -633,7 +634,7 @@
"uuid": 261116,
"id": "productdetailservice",
"name": "ProductDetailService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -651,7 +652,7 @@
"uuid": 246274,
"id": "productservice",
"name": "ProductService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -670,7 +671,7 @@
"uuid": 380300,
"id": "profileservice",
"name": "ProfileService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -688,7 +689,7 @@
"uuid": 299558,
"id": "promoservice",
"name": "PromoService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -706,7 +707,7 @@
"uuid": 303216,
"id": "promotionservice",
"name": "PromotionService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -724,7 +725,7 @@
"uuid": 974334,
"id": "questionanswerservice",
"name": "QuestionanswerService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -742,7 +743,7 @@
"uuid": 127763,
"id": "redbaloonservice",
"name": "RedBaloonService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -761,7 +762,7 @@
"uuid": 437955,
"id": "extra service reported by containerpilot: redbaloonservice-https",
"name": "Extra service reported by ContainerPilot: RedBaloonService-HTTPS",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -779,7 +780,7 @@
"uuid": 143274,
"id": "reviewsservice",
"name": "ReviewsService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -797,7 +798,7 @@
"uuid": 634968,
"id": "searchfacetsservice",
"name": "SearchFacetsService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -815,7 +816,7 @@
"uuid": 431609,
"id": "searchindexservice",
"name": "SearchIndexService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -833,7 +834,7 @@
"uuid": 282549,
"id": "shoprunnerservice",
"name": "ShopRunnerService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -852,7 +853,7 @@
"uuid": 262582,
"id": "taxservice",
"name": "TaxService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -870,7 +871,7 @@
"uuid": 418482,
"id": "toggleservice",
"name": "ToggleService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -888,7 +889,7 @@
"uuid": 284724,
"id": "useraccountservice",
"name": "UserAccountService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -906,7 +907,7 @@
"uuid": 798952,
"id": "userauthenticationservice",
"name": "UserAuthenticationService",
"instances": 4,
"instances": ["", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -924,7 +925,7 @@
"uuid": 308763,
"id": "waitlistoverlayservice",
"name": "WaitlistOverlayService",
"instances": 5,
"instances": ["", "", "", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -943,7 +944,7 @@
"uuid": 111726,
"id": "waitlistservice",
"name": "WaitlistService",
"instances": 3,
"instances": ["", "", ""],
"project": "9fcb374d-a267-4c2a-9d9c-ba469b804639",
"metrics": [{
"name": "CPU",
@ -957,4 +958,4 @@
}],
"datacentres": 1,
"healthy": true
}]
}]

View File

@ -3,7 +3,7 @@
"id": "nginx",
"name": "Nginx",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"instances": 1,
"instances": [""],
"metrics": [{
"name": "CPU",
"value": "50%"
@ -24,7 +24,7 @@
"id": "wordpress",
"name": "Wordpress",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"instances": 2,
"instances": ["", ""],
"metrics": [{
"name": "CPU",
"value": "50%"
@ -47,7 +47,7 @@
"id": "nfs",
"name": "NFS",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"instances": 2,
"instances": ["", ""],
"metrics": [{
"name": "CPU",
"value": "50%"
@ -65,7 +65,7 @@
"id": "memcached",
"name": "Memcached",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"instances": 2,
"instances": ["", ""],
"metrics": [{
"name": "CPU",
"value": "50%"
@ -83,7 +83,7 @@
"id": "percona",
"name": "Percona",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"instances": 2,
"instances": ["", ""],
"metrics": [{
"name": "CPU",
"value": "50%"
@ -101,7 +101,8 @@
"id": "consul",
"name": "Consul",
"project": "e0ea0c02-55cc-45fe-8064-3e5176a59401",
"instances": 2,
"instances": ["", ""],
"isConsul": true,
"metrics": [{
"name": "CPU",
"value": "50%"
@ -114,4 +115,4 @@
}],
"healthy": true,
"datacentres": 2
}]
}]

View File

@ -20,6 +20,27 @@ const StyledSvg = Svg.extend`
*/
class Topology extends React.Component {
componentWillMount() {
this.create();
}
componentDidMount() {
this.boundResize = this.handleResize.bind(this);
window.addEventListener('resize', this.boundResize);
}
componentWillUnmount() {
window.removeEventListener('resize', this.boundResize);
}
shouldComponentUpdate() {
return true;
}
handleResize(evt) {
this.create();
}
create() {
const services = this.getServicesWithoutConsul();
const svgSize = this.getSvgSize();
@ -34,7 +55,7 @@ class Topology extends React.Component {
getServicesWithoutConsul() {
return this.props.services.reduce((acc, service, index) => {
if (service.id !== 'consul') acc.push(service);
if (!service.isConsul) acc.push(service);
return acc;
}, []);
}
@ -123,7 +144,7 @@ class Topology extends React.Component {
const { nodes, links } = this.state;
const nodesData = services.map((service, index) => {
const nodePosition = service.id === 'consul'
const nodePosition = service.isConsul
? this.getConsulNodePosition()
: this.getConstrainedNodePosition(service.id, service.children);
@ -204,7 +225,7 @@ class Topology extends React.Component {
onDragStart={onDragStart}
onNodeTitleClick={onNodeTitleClick}
onQuickActions={onQuickActionsClick}
connected={n.id !== 'consul'}
connected={!n.isConsul}
/>;
const renderedLink = (l, index) =>

View File

@ -7,25 +7,26 @@ import GraphNodeInfo from './info';
import GraphNodeMetrics from './metrics';
const GraphNodeContent = ({ connected, child = false, data, index = 0 }) => {
const { x, y, width, height } = Constants.contentRect;
let { x, y, width, height } = Constants.contentRect;
if(child) height = Constants.childContentSize.height;
const contentY = y + height * index;
const offset = index ? 18 : -6;
// const offset = index ? 18 : -6;
const nodeInfoPos = child
? {
x: Constants.infoPosition.x,
y: Constants.infoPosition.y + offset
y: Constants.infoPosition.y + 21 // offset
}
: Constants.infoPosition;
const nodeMetricsPos = child
/* const nodeMetricsPos = child
? {
x: Constants.metricsPosition.x,
y: Constants.metricsPosition.y + offset
}
: Constants.metricsPosition;
: Constants.metricsPosition; */
const nodeSubtitle = child
? <GraphSubtitle {...Constants.subtitlePosition} connected={connected}>
@ -33,7 +34,7 @@ const GraphNodeContent = ({ connected, child = false, data, index = 0 }) => {
</GraphSubtitle>
: null;
const nodeInfo = !child || index
/* const nodeInfo = !child || index
? <GraphNodeInfo
datacenter={data.datacenter}
instances={data.instances}
@ -41,18 +42,27 @@ const GraphNodeContent = ({ connected, child = false, data, index = 0 }) => {
connected={connected}
pos={nodeInfoPos}
/>
: null;
: null; */
const nodeInfo =
<GraphNodeInfo
datacenter={data.datacenter}
instances={data.instances}
healthy
connected={connected}
pos={nodeInfoPos}
/>;
return (
<g transform={`translate(${x}, ${contentY})`}>
<GraphLine x1={0} y1={0} x2={width} y2={0} connected={connected} />
{nodeSubtitle}
{nodeInfo}
<GraphNodeMetrics
{/* <GraphNodeMetrics
metrics={data.metrics}
connected={connected}
pos={nodeMetricsPos}
/>
/> */}
</g>
);
};

View File

@ -6,7 +6,8 @@ import Baseline from '../../baseline';
import DataCentresIcon from './icon-data-centers.svg';
import InstancesIcon from './icon-instances.svg';
import { Point } from '../prop-types';
import { GraphText } from './shapes';
import { GraphText, GraphHealthyCircle } from './shapes';
import HeartIcon from './icon-heart.svg';
const StyledInstancesIcon = styled(InstancesIcon)`
fill: ${props => props.theme.secondary};
@ -29,18 +30,22 @@ const GraphNodeInfo = ({ connected, datacenter, instances, healthy, pos }) => {
return (
<g transform={`translate(${x}, ${y})`}>
<g transform={'translate(0, 2)'}>
<g transform={`translate(0, 0)`}>
<GraphHealthyCircle cx={9} cy={9} r={9} />
<HeartIcon />
</g>
<g transform={'translate(30, 4.5)'}>
<StyledInstancesIcon connected={connected} />
</g>
<GraphText x={23} y={12} connected={connected}>
{`${instances} inst.`}
<GraphText x={54} y={14} connected={connected}>
{`${instances.length} inst.`}
</GraphText>
<g transform={'translate(82, 0)'}>
{/* <g transform={'translate(82, 0)'}>
<StyledDataCentresIcon connected={connected} />
</g>
<GraphText x={96} y={12} connected={connected}>
{datacenter}
</GraphText>
</GraphText> */}
</g>
);
};

View File

@ -22,6 +22,7 @@ export const GraphNodeRect = styled.rect`
stroke: ${props => props.theme.secondaryActive};
fill: ${props => props.theme.secondary};
`};
cursor: move;
`;
export const GraphShadowRect = styled.rect`
@ -46,6 +47,7 @@ export const GraphTitle = styled.text`
${is('connected')`
fill: ${props => props.theme.white};
`};
cursor: pointer;
`;
export const GraphSubtitle = styled.text`

View File

@ -16,10 +16,10 @@ const GraphNodeTitle = ({ connected, data, onNodeTitleClick }) =>
>
{data.name}
</GraphTitle>
<g transform={`translate(${115}, ${15})`}>
{/* <g transform={`translate(${115}, ${15})`}>
<GraphHealthyCircle cx={9} cy={9} r={9} />
<HeartIcon />
</g>
</g> */}
</g>;
GraphNodeTitle.propTypes = {

View File

@ -22,10 +22,17 @@ const createLinks = services =>
(acc, service, index) =>
service.connections
? acc.concat(
service.connections.map((connection, index) => ({
source: service.id,
target: connection
}))
service.connections.reduce((connections, connection, index) => {
const targetExists = services.filter(service =>
service.id === connection).length;
if(targetExists) {
connections.push({
source: service.id,
target: connection
});
}
return connections;
}, [])
)
: acc,
[]