feat(ui-toolkit, cp-frontend): Allow topology nodes are displayed at top when not connected
This commit is contained in:
parent
be7bb5f871
commit
abdd9f9f6a
@ -51,24 +51,7 @@ const DeleteServicesGql = graphql(ServicesDeleteMutation, {
|
||||
props: ({ mutate }) => ({
|
||||
deleteServices: serviceId =>
|
||||
mutate({
|
||||
variables: { ids: [serviceId] },
|
||||
updateQueries: {
|
||||
Services: (prev, { mutationResult }) => {
|
||||
const deletedService = mutationResult.data.deleteServices[0];
|
||||
const prevServices = prev.deploymentGroup.services;
|
||||
const services = prevServices.filter(
|
||||
service =>
|
||||
service.id !== deletedService.id &&
|
||||
service.parent !== deletedService.id
|
||||
);
|
||||
return {
|
||||
deploymentGroup: {
|
||||
...prev.deploymentGroup,
|
||||
services
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
variables: { ids: [serviceId] }
|
||||
})
|
||||
})
|
||||
});
|
||||
|
@ -126,6 +126,7 @@ const UiConnect = connect(mapStateToProps, mapDispatchToProps);
|
||||
const ServicesGql = graphql(ServicesQuery, {
|
||||
options(props) {
|
||||
return {
|
||||
pollInterval: 1000,
|
||||
variables: {
|
||||
deploymentGroupSlug: props.match.params.deploymentGroup
|
||||
}
|
||||
|
@ -158,12 +158,23 @@ const processServicesForTopology = services => {
|
||||
const processedServices = processServices(services);
|
||||
|
||||
const connectedServices = processedServices.reduce(
|
||||
(connections, service) =>
|
||||
service.connections && service.connections.length
|
||||
? connections.concat(service.connections).concat(service.id)
|
||||
: connections,
|
||||
[]
|
||||
);
|
||||
(connections, service) => {
|
||||
if(!service.connections || !service.connections.length) {
|
||||
return connections;
|
||||
}
|
||||
|
||||
const existingConnections = service.connections.reduce((connections, connection) => {
|
||||
const connectionExists = processedServices.filter(ps => ps.id === connection).length;
|
||||
if(connectionExists) {
|
||||
connections.push(connection);
|
||||
}
|
||||
return connections;
|
||||
}, []);
|
||||
|
||||
return existingConnections.length
|
||||
? connections.concat(existingConnections).concat(service.id)
|
||||
: connections
|
||||
}, []);
|
||||
|
||||
return processedServices.map(service => ({
|
||||
...service,
|
||||
|
@ -99,15 +99,21 @@ const calculateLineLayout = ({ source, target }) => {
|
||||
};
|
||||
};
|
||||
|
||||
const getStatusesLength = (data) =>
|
||||
data.transitionalStatus
|
||||
? 1
|
||||
: data.instanceStatuses.length;
|
||||
|
||||
const getNodeRect = (data) => {
|
||||
const nodeSize = data.children
|
||||
? Constants.nodeSizeWithChildren
|
||||
: Constants.nodeSize;
|
||||
|
||||
const statuses = data.children
|
||||
? data.children.reduce((statuses, child) =>
|
||||
statuses + child.instanceStatuses.length, 0)
|
||||
: data.instanceStatuses.length;
|
||||
? data.children.reduce((statuses, child) => {
|
||||
return statuses + getStatusesLength(child), 0
|
||||
})
|
||||
: getStatusesLength(data);
|
||||
|
||||
const { width, height } = nodeSize;
|
||||
|
||||
|
@ -79,6 +79,7 @@ class Topology extends React.Component {
|
||||
|
||||
getNextNodes(nextServices) {
|
||||
const nodes = this.state.nodes;
|
||||
let notConnectedX = 0;
|
||||
return nodes.reduce((nextNodes, node) => {
|
||||
const keep = nextServices.filter(nextService => nextService.id === node.id).length;
|
||||
if(keep) {
|
||||
@ -94,6 +95,9 @@ class Topology extends React.Component {
|
||||
// on other updates, we should update the services on the state and that's it
|
||||
// we should forceUpdate once the state has been updated
|
||||
const nextServices = nextProps.services.sort();
|
||||
const connectedNextServices = nextServices.filter(service => service.connected);
|
||||
const notConnectedNextServices = nextServices.filter(service => !service.connected);
|
||||
|
||||
const { services, nodes } = this.state;
|
||||
if(nextServices.length > services.length) {
|
||||
// new service added, we need to redraw
|
||||
@ -117,14 +121,16 @@ class Topology extends React.Component {
|
||||
this.create(nextProps);
|
||||
}
|
||||
else if(servicesRemoved.length || changedConnections.removed) {
|
||||
const nextNodes = servicesRemoved.length
|
||||
? this.getNextNodes(nextServices)
|
||||
: nodes;
|
||||
|
||||
const nextNodes = this.getNextNodes(connectedNextServices);
|
||||
const notConnectedNodes = this.getNotConnectedNodes(notConnectedNextServices);
|
||||
const nextLinks = this.getNextLinks(nextServices);
|
||||
|
||||
this.setState({
|
||||
services: nextServices,
|
||||
links: nextLinks,
|
||||
nodes: nextNodes,
|
||||
notConnectedNodes
|
||||
}, () => this.forceUpdate());
|
||||
}
|
||||
else {
|
||||
@ -135,6 +141,21 @@ class Topology extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
getNotConnectedNodes(notConnectedServices) {
|
||||
return notConnectedServices.map((notConnectedService, index) => {
|
||||
const svgSize = this.getSvgSize();
|
||||
const x = notConnectedService.isConsul
|
||||
? svgSize.width - Constants.nodeSize.width
|
||||
: (Constants.nodeSize.width + 10)*index;
|
||||
|
||||
return ({
|
||||
id: notConnectedService.id,
|
||||
x,
|
||||
y: 0
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
handleResize(evt) {
|
||||
this.create(this.props);
|
||||
// resize should just rejig the positions
|
||||
@ -144,12 +165,14 @@ class Topology extends React.Component {
|
||||
// other updates should also just update the services rather than recreate the simulation
|
||||
const services = props.services.sort();
|
||||
const connectedServices = services.filter(service => service.connected);
|
||||
const notConnectedServices = services.filter(service => !service.connected && !service.isConsul);
|
||||
const notConnectedServices = services.filter(service => !service.connected);
|
||||
const svgSize = this.getSvgSize();
|
||||
|
||||
const { nodes, links, simulation } = createSimulation(services, svgSize);
|
||||
const { nodes, links, simulation } = createSimulation(connectedServices, svgSize);
|
||||
const notConnectedNodes = this.getNotConnectedNodes(notConnectedServices);
|
||||
|
||||
this.setState({
|
||||
notConnectedNodes,
|
||||
nodes,
|
||||
links,
|
||||
simulation,
|
||||
@ -207,21 +230,16 @@ class Topology extends React.Component {
|
||||
);
|
||||
}
|
||||
|
||||
getConsulNodePosition() {
|
||||
const svgSize = this.getSvgSize();
|
||||
const x = svgSize.width - Constants.nodeSize.width;
|
||||
|
||||
return {
|
||||
x,
|
||||
y: 0
|
||||
};
|
||||
}
|
||||
|
||||
getConstrainedNodePosition(nodeId, children = false) {
|
||||
const node = this.findNode(nodeId);
|
||||
return this.constrainNodePosition(node.x, node.y, children);
|
||||
}
|
||||
|
||||
getNotConnectedNodePosition(nodeId) {
|
||||
return this.state.notConnectedNodes.filter(ncn =>
|
||||
ncn.id === nodeId).shift();
|
||||
}
|
||||
|
||||
findNodeData(nodesData, nodeId) {
|
||||
return nodesData.filter(nodeData => nodeData.id === nodeId).shift();
|
||||
}
|
||||
@ -240,9 +258,9 @@ class Topology extends React.Component {
|
||||
const { nodes, links, services } = this.state;
|
||||
|
||||
const nodesData = services.map((service, index) => {
|
||||
const nodePosition = service.isConsul
|
||||
? this.getConsulNodePosition()
|
||||
: this.getConstrainedNodePosition(service.id, service.children);
|
||||
const nodePosition = service.connected
|
||||
? this.getConstrainedNodePosition(service.id, service.children)
|
||||
: this.getNotConnectedNodePosition(service.id);
|
||||
|
||||
const nodeRect = getNodeRect(service);
|
||||
|
||||
@ -255,12 +273,11 @@ class Topology extends React.Component {
|
||||
|
||||
// TODO links will need to know whether a service has children
|
||||
// if it does, the height of it will be different
|
||||
const t = links
|
||||
const linksData = links
|
||||
.map((link, index) => ({
|
||||
source: this.findNodeData(nodesData, link.source.id),
|
||||
target: this.findNodeData(nodesData, link.target.id)
|
||||
}));
|
||||
const linksData = t
|
||||
}))
|
||||
.map((linkData, index) => {
|
||||
return calculateLineLayout(linkData, index)
|
||||
});
|
||||
|
@ -50,13 +50,8 @@ const GraphNodeContent = ({ child = false, data, index = 0 }) => {
|
||||
|
||||
const nodeInfo =
|
||||
<GraphNodeInfo
|
||||
datacenter={data.datacenter}
|
||||
instances={data.instances}
|
||||
instanceStatuses={data.instanceStatuses}
|
||||
healthy
|
||||
data={data}
|
||||
pos={nodeInfoPos}
|
||||
isConsul={data.isConsul}
|
||||
instancesActive={data.instancesActive}
|
||||
/>;
|
||||
|
||||
return (
|
||||
|
@ -33,10 +33,26 @@ const StyledDataCentresIcon = styled(DataCentresIcon)`
|
||||
`};
|
||||
`;
|
||||
|
||||
const GraphNodeInfo = ({ datacenter, instances, instanceStatuses, healthy, pos, isConsul, instancesActive }) => {
|
||||
const GraphNodeInfo = ({ data, pos }) => {
|
||||
|
||||
const {
|
||||
datacenter,
|
||||
instances,
|
||||
instanceStatuses,
|
||||
healthy,
|
||||
isConsul,
|
||||
instancesActive,
|
||||
transitionalStatus,
|
||||
status
|
||||
} = data;
|
||||
|
||||
const { x, y } = pos;
|
||||
|
||||
const statuses = instanceStatuses.map((instanceStatus, index) =>
|
||||
const statuses = transitionalStatus
|
||||
? <GraphText consul={isConsul} active={instancesActive}>
|
||||
{ status.toLowerCase() }
|
||||
</GraphText>
|
||||
: instanceStatuses.map((instanceStatus, index) =>
|
||||
<GraphText key={index} consul={isConsul} active={instancesActive}>
|
||||
{`${instanceStatus.count}
|
||||
${instanceStatus.status.toLowerCase()}`}
|
||||
@ -69,13 +85,15 @@ const GraphNodeInfo = ({ datacenter, instances, instanceStatuses, healthy, pos,
|
||||
};
|
||||
|
||||
GraphNodeInfo.propTypes = {
|
||||
data: PropTypes.object.isRequired,
|
||||
pos: Point.isRequired/*,
|
||||
datacenter: PropTypes.string,
|
||||
healthy: PropTypes.bool,
|
||||
instances: PropTypes.array,
|
||||
instanceStatuses: PropTypes.array,
|
||||
pos: Point.isRequired,
|
||||
isConsul: PropTypes.bool,
|
||||
instancesActive: PropTypes.bool
|
||||
instancesActive: PropTypes.bool*/
|
||||
};
|
||||
|
||||
export default Baseline(GraphNodeInfo);
|
||||
|
@ -10,7 +10,7 @@ const forcePlayAnimation = (simulation, animationTicks) => {
|
||||
const n =
|
||||
Math.ceil(
|
||||
Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())
|
||||
) - animationTicks;
|
||||
) + 100; // - animationTicks;
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
simulation.tick();
|
||||
@ -41,13 +41,20 @@ const createLinks = services =>
|
||||
const createSimulation = (services, svgSize, animationTicks = 0) => {
|
||||
// This is not going to work given that as well as the d3 layout stuff, other things might be at play too
|
||||
// We should pass two objects to the components - one for positioning and one for data
|
||||
const nodes = services.map((service, index) => ({
|
||||
console.log('createSimulation services = ', services);
|
||||
console.log('createSimulation services.length = ', services.length);
|
||||
const nodes = services.map((service, index) => {
|
||||
console.log('createSimulation services.map service.id = ', service.id);
|
||||
console.log('createSimulation services.map service.connected = ', service.connected);
|
||||
return ({
|
||||
id: service.id,
|
||||
index
|
||||
}));
|
||||
|
||||
})
|
||||
});
|
||||
console.log('createSimulation nodes = ', nodes);
|
||||
console.log('createSimulation nodes.length = ', nodes.length);
|
||||
const links = createLinks(services);
|
||||
|
||||
console.log('createSimulation links = ', links);
|
||||
const { width, height } = svgSize;
|
||||
|
||||
const nodeRadius = rectRadius(Constants.nodeSizeWithChildren);
|
||||
@ -58,6 +65,7 @@ const createSimulation = (services, svgSize, animationTicks = 0) => {
|
||||
.force('center', forceCenter(width / 2, height / 2));
|
||||
|
||||
forcePlayAnimation(simulation, animationTicks);
|
||||
console.log('createSimulation nodes = ', nodes);
|
||||
|
||||
return {
|
||||
nodes,
|
||||
|
Loading…
Reference in New Issue
Block a user