mirror of
https://github.com/yldio/copilot.git
synced 2024-11-28 14:10:04 +02:00
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 }) => ({
|
props: ({ mutate }) => ({
|
||||||
deleteServices: serviceId =>
|
deleteServices: serviceId =>
|
||||||
mutate({
|
mutate({
|
||||||
variables: { ids: [serviceId] },
|
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
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
@ -126,6 +126,7 @@ const UiConnect = connect(mapStateToProps, mapDispatchToProps);
|
|||||||
const ServicesGql = graphql(ServicesQuery, {
|
const ServicesGql = graphql(ServicesQuery, {
|
||||||
options(props) {
|
options(props) {
|
||||||
return {
|
return {
|
||||||
|
pollInterval: 1000,
|
||||||
variables: {
|
variables: {
|
||||||
deploymentGroupSlug: props.match.params.deploymentGroup
|
deploymentGroupSlug: props.match.params.deploymentGroup
|
||||||
}
|
}
|
||||||
|
@ -158,12 +158,23 @@ const processServicesForTopology = services => {
|
|||||||
const processedServices = processServices(services);
|
const processedServices = processServices(services);
|
||||||
|
|
||||||
const connectedServices = processedServices.reduce(
|
const connectedServices = processedServices.reduce(
|
||||||
(connections, service) =>
|
(connections, service) => {
|
||||||
service.connections && service.connections.length
|
if(!service.connections || !service.connections.length) {
|
||||||
? connections.concat(service.connections).concat(service.id)
|
return connections;
|
||||||
: 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 => ({
|
return processedServices.map(service => ({
|
||||||
...service,
|
...service,
|
||||||
|
@ -99,15 +99,21 @@ const calculateLineLayout = ({ source, target }) => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getStatusesLength = (data) =>
|
||||||
|
data.transitionalStatus
|
||||||
|
? 1
|
||||||
|
: data.instanceStatuses.length;
|
||||||
|
|
||||||
const getNodeRect = (data) => {
|
const getNodeRect = (data) => {
|
||||||
const nodeSize = data.children
|
const nodeSize = data.children
|
||||||
? Constants.nodeSizeWithChildren
|
? Constants.nodeSizeWithChildren
|
||||||
: Constants.nodeSize;
|
: Constants.nodeSize;
|
||||||
|
|
||||||
const statuses = data.children
|
const statuses = data.children
|
||||||
? data.children.reduce((statuses, child) =>
|
? data.children.reduce((statuses, child) => {
|
||||||
statuses + child.instanceStatuses.length, 0)
|
return statuses + getStatusesLength(child), 0
|
||||||
: data.instanceStatuses.length;
|
})
|
||||||
|
: getStatusesLength(data);
|
||||||
|
|
||||||
const { width, height } = nodeSize;
|
const { width, height } = nodeSize;
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ class Topology extends React.Component {
|
|||||||
|
|
||||||
getNextNodes(nextServices) {
|
getNextNodes(nextServices) {
|
||||||
const nodes = this.state.nodes;
|
const nodes = this.state.nodes;
|
||||||
|
let notConnectedX = 0;
|
||||||
return nodes.reduce((nextNodes, node) => {
|
return nodes.reduce((nextNodes, node) => {
|
||||||
const keep = nextServices.filter(nextService => nextService.id === node.id).length;
|
const keep = nextServices.filter(nextService => nextService.id === node.id).length;
|
||||||
if(keep) {
|
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
|
// on other updates, we should update the services on the state and that's it
|
||||||
// we should forceUpdate once the state has been updated
|
// we should forceUpdate once the state has been updated
|
||||||
const nextServices = nextProps.services.sort();
|
const nextServices = nextProps.services.sort();
|
||||||
|
const connectedNextServices = nextServices.filter(service => service.connected);
|
||||||
|
const notConnectedNextServices = nextServices.filter(service => !service.connected);
|
||||||
|
|
||||||
const { services, nodes } = this.state;
|
const { services, nodes } = this.state;
|
||||||
if(nextServices.length > services.length) {
|
if(nextServices.length > services.length) {
|
||||||
// new service added, we need to redraw
|
// new service added, we need to redraw
|
||||||
@ -117,14 +121,16 @@ class Topology extends React.Component {
|
|||||||
this.create(nextProps);
|
this.create(nextProps);
|
||||||
}
|
}
|
||||||
else if(servicesRemoved.length || changedConnections.removed) {
|
else if(servicesRemoved.length || changedConnections.removed) {
|
||||||
const nextNodes = servicesRemoved.length
|
|
||||||
? this.getNextNodes(nextServices)
|
const nextNodes = this.getNextNodes(connectedNextServices);
|
||||||
: nodes;
|
const notConnectedNodes = this.getNotConnectedNodes(notConnectedNextServices);
|
||||||
const nextLinks = this.getNextLinks(nextServices);
|
const nextLinks = this.getNextLinks(nextServices);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
services: nextServices,
|
services: nextServices,
|
||||||
links: nextLinks,
|
links: nextLinks,
|
||||||
nodes: nextNodes,
|
nodes: nextNodes,
|
||||||
|
notConnectedNodes
|
||||||
}, () => this.forceUpdate());
|
}, () => this.forceUpdate());
|
||||||
}
|
}
|
||||||
else {
|
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) {
|
handleResize(evt) {
|
||||||
this.create(this.props);
|
this.create(this.props);
|
||||||
// resize should just rejig the positions
|
// 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
|
// other updates should also just update the services rather than recreate the simulation
|
||||||
const services = props.services.sort();
|
const services = props.services.sort();
|
||||||
const connectedServices = services.filter(service => service.connected);
|
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 svgSize = this.getSvgSize();
|
||||||
|
|
||||||
const { nodes, links, simulation } = createSimulation(services, svgSize);
|
const { nodes, links, simulation } = createSimulation(connectedServices, svgSize);
|
||||||
|
const notConnectedNodes = this.getNotConnectedNodes(notConnectedServices);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
notConnectedNodes,
|
||||||
nodes,
|
nodes,
|
||||||
links,
|
links,
|
||||||
simulation,
|
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) {
|
getConstrainedNodePosition(nodeId, children = false) {
|
||||||
const node = this.findNode(nodeId);
|
const node = this.findNode(nodeId);
|
||||||
return this.constrainNodePosition(node.x, node.y, children);
|
return this.constrainNodePosition(node.x, node.y, children);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNotConnectedNodePosition(nodeId) {
|
||||||
|
return this.state.notConnectedNodes.filter(ncn =>
|
||||||
|
ncn.id === nodeId).shift();
|
||||||
|
}
|
||||||
|
|
||||||
findNodeData(nodesData, nodeId) {
|
findNodeData(nodesData, nodeId) {
|
||||||
return nodesData.filter(nodeData => nodeData.id === nodeId).shift();
|
return nodesData.filter(nodeData => nodeData.id === nodeId).shift();
|
||||||
}
|
}
|
||||||
@ -240,9 +258,9 @@ class Topology extends React.Component {
|
|||||||
const { nodes, links, services } = this.state;
|
const { nodes, links, services } = this.state;
|
||||||
|
|
||||||
const nodesData = services.map((service, index) => {
|
const nodesData = services.map((service, index) => {
|
||||||
const nodePosition = service.isConsul
|
const nodePosition = service.connected
|
||||||
? this.getConsulNodePosition()
|
? this.getConstrainedNodePosition(service.id, service.children)
|
||||||
: this.getConstrainedNodePosition(service.id, service.children);
|
: this.getNotConnectedNodePosition(service.id);
|
||||||
|
|
||||||
const nodeRect = getNodeRect(service);
|
const nodeRect = getNodeRect(service);
|
||||||
|
|
||||||
@ -255,12 +273,11 @@ class Topology extends React.Component {
|
|||||||
|
|
||||||
// TODO links will need to know whether a service has children
|
// TODO links will need to know whether a service has children
|
||||||
// if it does, the height of it will be different
|
// if it does, the height of it will be different
|
||||||
const t = links
|
const linksData = links
|
||||||
.map((link, index) => ({
|
.map((link, index) => ({
|
||||||
source: this.findNodeData(nodesData, link.source.id),
|
source: this.findNodeData(nodesData, link.source.id),
|
||||||
target: this.findNodeData(nodesData, link.target.id)
|
target: this.findNodeData(nodesData, link.target.id)
|
||||||
}));
|
}))
|
||||||
const linksData = t
|
|
||||||
.map((linkData, index) => {
|
.map((linkData, index) => {
|
||||||
return calculateLineLayout(linkData, index)
|
return calculateLineLayout(linkData, index)
|
||||||
});
|
});
|
||||||
|
@ -50,13 +50,8 @@ const GraphNodeContent = ({ child = false, data, index = 0 }) => {
|
|||||||
|
|
||||||
const nodeInfo =
|
const nodeInfo =
|
||||||
<GraphNodeInfo
|
<GraphNodeInfo
|
||||||
datacenter={data.datacenter}
|
data={data}
|
||||||
instances={data.instances}
|
|
||||||
instanceStatuses={data.instanceStatuses}
|
|
||||||
healthy
|
|
||||||
pos={nodeInfoPos}
|
pos={nodeInfoPos}
|
||||||
isConsul={data.isConsul}
|
|
||||||
instancesActive={data.instancesActive}
|
|
||||||
/>;
|
/>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -33,15 +33,31 @@ 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 { x, y } = pos;
|
||||||
|
|
||||||
const statuses = instanceStatuses.map((instanceStatus, index) =>
|
const statuses = transitionalStatus
|
||||||
<GraphText key={index} consul={isConsul} active={instancesActive}>
|
? <GraphText consul={isConsul} active={instancesActive}>
|
||||||
{`${instanceStatus.count}
|
{ status.toLowerCase() }
|
||||||
${instanceStatus.status.toLowerCase()}`}
|
</GraphText>
|
||||||
</GraphText>
|
: instanceStatuses.map((instanceStatus, index) =>
|
||||||
);
|
<GraphText key={index} consul={isConsul} active={instancesActive}>
|
||||||
|
{`${instanceStatus.count}
|
||||||
|
${instanceStatus.status.toLowerCase()}`}
|
||||||
|
</GraphText>
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<g transform={`translate(${x}, ${y})`}>
|
<g transform={`translate(${x}, ${y})`}>
|
||||||
@ -69,13 +85,15 @@ const GraphNodeInfo = ({ datacenter, instances, instanceStatuses, healthy, pos,
|
|||||||
};
|
};
|
||||||
|
|
||||||
GraphNodeInfo.propTypes = {
|
GraphNodeInfo.propTypes = {
|
||||||
|
data: PropTypes.object.isRequired,
|
||||||
|
pos: Point.isRequired/*,
|
||||||
datacenter: PropTypes.string,
|
datacenter: PropTypes.string,
|
||||||
healthy: PropTypes.bool,
|
healthy: PropTypes.bool,
|
||||||
instances: PropTypes.array,
|
instances: PropTypes.array,
|
||||||
instanceStatuses: PropTypes.array,
|
instanceStatuses: PropTypes.array,
|
||||||
pos: Point.isRequired,
|
pos: Point.isRequired,
|
||||||
isConsul: PropTypes.bool,
|
isConsul: PropTypes.bool,
|
||||||
instancesActive: PropTypes.bool
|
instancesActive: PropTypes.bool*/
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Baseline(GraphNodeInfo);
|
export default Baseline(GraphNodeInfo);
|
||||||
|
@ -10,7 +10,7 @@ const forcePlayAnimation = (simulation, animationTicks) => {
|
|||||||
const n =
|
const n =
|
||||||
Math.ceil(
|
Math.ceil(
|
||||||
Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())
|
Math.log(simulation.alphaMin()) / Math.log(1 - simulation.alphaDecay())
|
||||||
) - animationTicks;
|
) + 100; // - animationTicks;
|
||||||
|
|
||||||
for (let i = 0; i < n; ++i) {
|
for (let i = 0; i < n; ++i) {
|
||||||
simulation.tick();
|
simulation.tick();
|
||||||
@ -41,13 +41,20 @@ const createLinks = services =>
|
|||||||
const createSimulation = (services, svgSize, animationTicks = 0) => {
|
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
|
// 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
|
// 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);
|
||||||
id: service.id,
|
console.log('createSimulation services.length = ', services.length);
|
||||||
index
|
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);
|
const links = createLinks(services);
|
||||||
|
console.log('createSimulation links = ', links);
|
||||||
const { width, height } = svgSize;
|
const { width, height } = svgSize;
|
||||||
|
|
||||||
const nodeRadius = rectRadius(Constants.nodeSizeWithChildren);
|
const nodeRadius = rectRadius(Constants.nodeSizeWithChildren);
|
||||||
@ -58,6 +65,7 @@ const createSimulation = (services, svgSize, animationTicks = 0) => {
|
|||||||
.force('center', forceCenter(width / 2, height / 2));
|
.force('center', forceCenter(width / 2, height / 2));
|
||||||
|
|
||||||
forcePlayAnimation(simulation, animationTicks);
|
forcePlayAnimation(simulation, animationTicks);
|
||||||
|
console.log('createSimulation nodes = ', nodes);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
nodes,
|
nodes,
|
||||||
|
Loading…
Reference in New Issue
Block a user