mirror of https://github.com/EdgeVPNio/portal.git
Towards sidebar details
parent
a808cbee5f
commit
28bf24ce7d
|
@ -54,8 +54,8 @@ class Sidebar extends React.Component {
|
||||||
<div id="searchBar" style={{ margin: "20px 0" }}>
|
<div id="searchBar" style={{ margin: "20px 0" }}>
|
||||||
{this.renderTypeahead()}
|
{this.renderTypeahead()}
|
||||||
</div>
|
</div>
|
||||||
<div id="sidebarDetails" style={{ padding: "8px" }}>
|
<div id="sideBarContent" style={{ padding: "8px" }}>
|
||||||
{this.renderDetails()}
|
{this.props.sidebarDetails}
|
||||||
</div>
|
</div>
|
||||||
</Slidebar>
|
</Slidebar>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
import ReactDOM from "react-dom";
|
||||||
//import cytoscape from "cytoscape";
|
//import cytoscape from "cytoscape";
|
||||||
import Cytoscape from "react-cytoscapejs";
|
import Cytoscape from "react-cytoscapejs";
|
||||||
//import CytoscapeComponent from "react-cytoscapejs";
|
//import CytoscapeComponent from "react-cytoscapejs";
|
||||||
|
@ -10,9 +11,9 @@ import SideBar from "./Sidebar";
|
||||||
import { connect } from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import { setCyElements } from "../features/evio/evioSlice";
|
import { setCyElements } from "../features/evio/evioSlice";
|
||||||
import {
|
import {
|
||||||
setSelectedElement,
|
//setSelectedElement,
|
||||||
clearSelectedElement,
|
//clearSelectedElement,
|
||||||
elementTypes,
|
//elementTypes,
|
||||||
setRedrawGraph,
|
setRedrawGraph,
|
||||||
} from "../features/evio/evioSlice";
|
} from "../features/evio/evioSlice";
|
||||||
import { setCurrentView } from "../features/view/viewSlice";
|
import { setCurrentView } from "../features/view/viewSlice";
|
||||||
|
@ -70,25 +71,172 @@ class TopologyView extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buildCyElements = (topologies) => {
|
||||||
|
var elements = [];
|
||||||
|
var nodeDetails = {};
|
||||||
|
|
||||||
|
if (topologies.length < 1) return elements;
|
||||||
|
var topology = topologies[0];
|
||||||
|
|
||||||
|
for (var nid in topology.Nodes) {
|
||||||
|
var node = topology.Nodes[nid];
|
||||||
|
var nodeData = {
|
||||||
|
group: "nodes",
|
||||||
|
data: {
|
||||||
|
id: node.NodeId,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
if (node.hasOwnProperty("NodeName"))
|
||||||
|
nodeData["data"]["label"] = node.NodeName;
|
||||||
|
else nodeData["data"]["label"] = node.NodeId.slice(0, 12);
|
||||||
|
if (node.hasOwnProperty("Version"))
|
||||||
|
nodeData["data"]["version"] = node.Version;
|
||||||
|
else nodeData["data"]["version"] = "0.0.0";
|
||||||
|
if (node.hasOwnProperty("GeoCoordinates"))
|
||||||
|
nodeData["data"]["coords"] = node.GeoCoordinates;
|
||||||
|
else nodeData["data"]["coords"] = "0,0";
|
||||||
|
if (node.hasOwnProperty("Edges")) {
|
||||||
|
nodeData["data"]["edges"] = node.Edges;
|
||||||
|
if (node.Edges.length === 0) {
|
||||||
|
nodeData["data"]["state"] = nodeStates.noTunnels;
|
||||||
|
nodeData["data"]["color"] = "#F2BE22";
|
||||||
|
} else {
|
||||||
|
nodeData["data"]["state"] = nodeStates.connected;
|
||||||
|
nodeData["data"]["color"] = "#8AA626";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodeData["data"]["state"] = nodeStates.notReporting;
|
||||||
|
nodeData["data"]["color"] = "#ADD8E6";
|
||||||
|
}
|
||||||
|
nodeDetails[node.NodeId] = nodeData;
|
||||||
|
}
|
||||||
|
for (var edgeId in topology.Edges) {
|
||||||
|
var edge = topology.Edges[edgeId];
|
||||||
|
if (edge["Descriptor"].length > 2) {
|
||||||
|
console.error(
|
||||||
|
"Too many edge descriptors reported ",
|
||||||
|
JSON.stringify(edge["Descriptor"])
|
||||||
|
);
|
||||||
|
}
|
||||||
|
var edgeData = {
|
||||||
|
group: "edges",
|
||||||
|
data: {},
|
||||||
|
};
|
||||||
|
edgeData["data"]["id"] = edge.EdgeId;
|
||||||
|
edgeData["data"]["descriptor"] = edge["Descriptor"];
|
||||||
|
edgeData["data"]["label"] = edge.EdgeId.slice(0, 12);
|
||||||
|
edgeData["data"]["source"] = edge["Descriptor"][0].Source;
|
||||||
|
edgeData["data"]["target"] = edge["Descriptor"][0].Target;
|
||||||
|
edgeData["data"]["color"] = this.getLinkColor(edge["Descriptor"][0].Type);
|
||||||
|
edgeData["data"]["style"] = this.getLinkStyle(
|
||||||
|
edge["Descriptor"][0].State
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
edge["Descriptor"].length === 2 &&
|
||||||
|
edge["Descriptor"][0].Source > edge["Descriptor"][1].Source
|
||||||
|
) {
|
||||||
|
edgeData["data"]["source"] = edge["Descriptor"][1].Source;
|
||||||
|
edgeData["data"]["target"] = edge["Descriptor"][1].Target;
|
||||||
|
edgeData["data"]["color"] = this.getLinkColor(
|
||||||
|
edge["Descriptor"][1].Type
|
||||||
|
);
|
||||||
|
edgeData["data"]["style"] = this.getLinkStyle(
|
||||||
|
edge["Descriptor"][1].State
|
||||||
|
);
|
||||||
|
}
|
||||||
|
elements.push(edgeData);
|
||||||
|
}
|
||||||
|
var nodes = Object.keys(nodeDetails).sort();
|
||||||
|
nodes.forEach((nodeId) => elements.push(nodeDetails[nodeId]));
|
||||||
|
|
||||||
|
return elements;
|
||||||
|
};
|
||||||
|
|
||||||
|
getLinkColor(type) {
|
||||||
|
var linkColor;
|
||||||
|
switch (type) {
|
||||||
|
case "CETypeILongDistance":
|
||||||
|
linkColor = "#5E4FA2";
|
||||||
|
break;
|
||||||
|
case "CETypeLongDistance":
|
||||||
|
linkColor = "#5E4FA2";
|
||||||
|
break;
|
||||||
|
case "CETypePredecessor":
|
||||||
|
linkColor = "#01665E";
|
||||||
|
break;
|
||||||
|
case "CETypeSuccessor":
|
||||||
|
linkColor = "#01665E";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return linkColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
getLinkStyle(state) {
|
||||||
|
var linkStyle;
|
||||||
|
switch (state) {
|
||||||
|
case "CEStateInitialized":
|
||||||
|
case "CEStatePreAuth":
|
||||||
|
case "CEStateAuthorized":
|
||||||
|
case "CEStateCreated":
|
||||||
|
linkStyle = "dotted";
|
||||||
|
break;
|
||||||
|
case "CEStateConnected":
|
||||||
|
linkStyle = "solid";
|
||||||
|
break;
|
||||||
|
case "CEStateDisconnected":
|
||||||
|
case "CEStateDeleting":
|
||||||
|
linkStyle = "dashed";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return linkStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
partitionElements(selectedElement) {
|
||||||
|
var neighborhood;
|
||||||
|
var excluded;
|
||||||
|
if (selectedElement.isNode()) {
|
||||||
|
neighborhood = selectedElement
|
||||||
|
.outgoers()
|
||||||
|
.union(selectedElement.incomers())
|
||||||
|
.union(selectedElement);
|
||||||
|
excluded = this.cy
|
||||||
|
.elements()
|
||||||
|
.difference(
|
||||||
|
selectedElement.outgoers().union(selectedElement.incomers())
|
||||||
|
)
|
||||||
|
.not(selectedElement);
|
||||||
|
let adj = selectedElement.neighborhood();
|
||||||
|
let abscomp = adj.absoluteComplement();
|
||||||
|
// console.log("nei", neighborhood, "adj", adj);
|
||||||
|
// console.log("excluded", excluded, "abscomp", abscomp);
|
||||||
|
} else if (selectedElement.isEdge()) {
|
||||||
|
neighborhood = selectedElement.connectedNodes().union(selectedElement);
|
||||||
|
excluded = this.cy
|
||||||
|
.elements()
|
||||||
|
.difference(selectedElement.connectedNodes())
|
||||||
|
.not(selectedElement);
|
||||||
|
}
|
||||||
|
return { neighborhood, excluded };
|
||||||
|
}
|
||||||
|
|
||||||
async queryGeoCoordinates(coordinates) {
|
async queryGeoCoordinates(coordinates) {
|
||||||
coordinates = coordinates.split(",");
|
coordinates = coordinates.split(",");
|
||||||
|
if (coordinates.length < 2) return "Unknown";
|
||||||
try {
|
try {
|
||||||
const url = `https://maps.googleapis.com/maps/api/geocode/json?latlng=${coordinates[0]},${coordinates[1]}&key=AIzaSyBjkkk4UyMh4-ihU1B1RR7uGocXpKECJhs&language=en`;
|
const res = await fetch(
|
||||||
const res = await fetch(url);
|
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${coordinates[0]},${coordinates[1]}&key=AIzaSyBjkkk4UyMh4-ihU1B1RR7uGocXpKECJhs&language=en`
|
||||||
console.log("res.ok", res.ok);
|
|
||||||
var data = await res.json();
|
|
||||||
console.log("data", data);
|
|
||||||
console.log("data.results", data.results);
|
|
||||||
console.log("data.results.length", data.results.length);
|
|
||||||
console.log(
|
|
||||||
"data.results[data.results.length - 1].formatted_address",
|
|
||||||
data.results[data.results.length - 1].formatted_address
|
|
||||||
);
|
);
|
||||||
|
var data = await res.json();
|
||||||
var nodeLocation =
|
var nodeLocation =
|
||||||
data.results[data.results.length - 1].formatted_address;
|
data.results[data.results.length - 1].formatted_address;
|
||||||
|
console.log("formatted_address", nodeLocation);
|
||||||
return nodeLocation.slice(7, nodeLocation.length);
|
return nodeLocation.slice(7, nodeLocation.length);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
return "-";
|
return "Unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +247,7 @@ class TopologyView extends React.Component {
|
||||||
onChange={(selected) => {
|
onChange={(selected) => {
|
||||||
if (selected.length > 0) {
|
if (selected.length > 0) {
|
||||||
let selectedEle = this.cy
|
let selectedEle = this.cy
|
||||||
.elements()
|
//.elements()
|
||||||
.getElementById(selected[0].data.id);
|
.getElementById(selected[0].data.id);
|
||||||
this.cy.elements().unselect();
|
this.cy.elements().unselect();
|
||||||
selectedEle.select();
|
selectedEle.select();
|
||||||
|
@ -152,55 +300,36 @@ class TopologyView extends React.Component {
|
||||||
);
|
);
|
||||||
return nodeContent;
|
return nodeContent;
|
||||||
}
|
}
|
||||||
getConnectedLinkDetails(source, tgt, connectedEdges) {
|
|
||||||
for (var edge of connectedEdges) {
|
|
||||||
if (
|
|
||||||
(source.data().id === edge._private.data.source &&
|
|
||||||
tgt.id === edge._private.data.target) ||
|
|
||||||
(source.data().id === edge._private.data.target &&
|
|
||||||
tgt.id === edge._private.data.source)
|
|
||||||
) {
|
|
||||||
for (var descriptorItem of edge._private.data.descriptor) {
|
|
||||||
if (
|
|
||||||
source.data().id === descriptorItem.Source &&
|
|
||||||
tgt.id === descriptorItem.Target
|
|
||||||
) {
|
|
||||||
return [descriptorItem, edge._private.data.id];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getConnectedNodeDetails(sourceNode, connectedNodes, connectedEdges) {
|
getConnectedNodeDetails(cyNode, connectedNodes, connectedEdges) {
|
||||||
var sidebarNodeslist = [];
|
var sidebarNodeslist = [];
|
||||||
for (var el of connectedNodes) {
|
for (var el of connectedNodes) {
|
||||||
if (sourceNode.data() !== el._private.data) {
|
if (cyNode.data() !== el.data()) {
|
||||||
sidebarNodeslist.push(el._private.data);
|
sidebarNodeslist.push(el.data());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var nodeContent = (
|
var nodeContent = (
|
||||||
<CollapsibleButton
|
<CollapsibleButton
|
||||||
id={sourceNode.data().label + "Btn"}
|
id={cyNode.data().label + "Btn"}
|
||||||
className="detailsNodeBtn"
|
className="detailsNodeBtn"
|
||||||
key={sourceNode.data().label + "Btn"}
|
key={cyNode.data().label + "Btn"}
|
||||||
name={sourceNode.data().label}
|
name={cyNode.data().label}
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h5>{sourceNode.data().label}</h5>
|
<h5>{cyNode.data().label}</h5>
|
||||||
<div id="DetailsLabel">Node ID</div>
|
<div id="DetailsLabel">Node ID</div>
|
||||||
<label id="valueLabel">{sourceNode.data().id}</label>
|
<label id="valueLabel">{cyNode.data().id}</label>
|
||||||
<div className="DetailsLabel">State</div>
|
<div className="DetailsLabel">State</div>
|
||||||
<label id="valueLabel">{sourceNode.data().state}</label>
|
<label id="valueLabel">{cyNode.data().state}</label>
|
||||||
<div className="DetailsLabel">Location</div>
|
<div className="DetailsLabel">Location</div>
|
||||||
<label id="valueLabel">{"Unknown"}</label>
|
<label id="valueLabel">{cyNode.data().location}</label>
|
||||||
<hr style={{ backgroundColor: "#486186" }} />
|
<hr style={{ backgroundColor: "#486186" }} />
|
||||||
<div id="connectedNode" style={{ overflow: "auto" }}>
|
<div id="connectedNode" style={{ overflow: "auto" }}>
|
||||||
{sidebarNodeslist.map((connectedNode) => {
|
{sidebarNodeslist.map((connectedNode) => {
|
||||||
try {
|
try {
|
||||||
let [connectedlinkDetail, tunnelId] =
|
let [connectedlinkDetail, tunnelId] =
|
||||||
this.getConnectedLinkDetails(
|
this.getConnectedLinkDetails(
|
||||||
sourceNode,
|
cyNode,
|
||||||
connectedNode,
|
connectedNode,
|
||||||
connectedEdges
|
connectedEdges
|
||||||
);
|
);
|
||||||
|
@ -239,7 +368,7 @@ class TopologyView extends React.Component {
|
||||||
|
|
||||||
return connectedNodeBtn;
|
return connectedNodeBtn;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
//console.log(e)
|
console.log(e);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
|
@ -250,24 +379,24 @@ class TopologyView extends React.Component {
|
||||||
return nodeContent;
|
return nodeContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
getNotConnectedNodeDetails(notConnectedNode) {
|
getNotConnectedNodeDetails(cyNode) {
|
||||||
var nodeContent = (
|
var nodeContent = (
|
||||||
//No tunnels node
|
//No tunnels node
|
||||||
<CollapsibleButton
|
<CollapsibleButton
|
||||||
id={notConnectedNode.data().id + "Btn"}
|
id={cyNode.data().id + "Btn"}
|
||||||
className="detailsNodeBtn"
|
className="detailsNodeBtn"
|
||||||
key={notConnectedNode.data().id + "Btn"}
|
key={cyNode.data().id + "Btn"}
|
||||||
name={notConnectedNode.data().label}
|
name={cyNode.data().label}
|
||||||
isOpen
|
isOpen
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<h5>{notConnectedNode.data().label}</h5>
|
<h5>{cyNode.data().label}</h5>
|
||||||
<div className="DetailsLabel">Node ID</div>
|
<div className="DetailsLabel">Node ID</div>
|
||||||
<label id="valueLabel">{notConnectedNode.data().id}</label>
|
<label id="valueLabel">{cyNode.data().id}</label>
|
||||||
<div className="DetailsLabel">State</div>
|
<div className="DetailsLabel">State</div>
|
||||||
<label id="valueLabel">{notConnectedNode.data().state}</label>
|
<label id="valueLabel">{cyNode.data().state}</label>
|
||||||
<div className="DetailsLabel">Location</div>
|
<div className="DetailsLabel">Location</div>
|
||||||
<label id="valueLabel">{"Unknown"}</label>
|
<label id="valueLabel">{cyNode.data().location}</label>
|
||||||
<hr style={{ backgroundColor: "#486186" }} />
|
<hr style={{ backgroundColor: "#486186" }} />
|
||||||
</div>
|
</div>
|
||||||
</CollapsibleButton>
|
</CollapsibleButton>
|
||||||
|
@ -275,52 +404,72 @@ class TopologyView extends React.Component {
|
||||||
return nodeContent;
|
return nodeContent;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderNodeDetails = () => {
|
renderNodeDetails = (cyNode, adj) => {
|
||||||
var selectedEle = JSON.parse(this.props.selectedCyElementData);
|
var connectedNodes = adj.nodes();
|
||||||
var selectedNode = this.cy.getElementById(selectedEle.id);
|
var connectedEdges = adj.edges();
|
||||||
var partitionElements = this.partitionElements(selectedNode);
|
|
||||||
var nodeDetails = null;
|
var nodeDetails = null;
|
||||||
var connectedNodes = partitionElements.neighborhood.filter((ele) =>
|
this.queryGeoCoordinates(cyNode.data("coords"))
|
||||||
ele.isNode()
|
.then((loc) => {
|
||||||
);
|
cyNode.data("location", loc);
|
||||||
var connectedEdges = partitionElements.neighborhood.filter((ele) =>
|
if (cyNode.data("state") === nodeStates.notReporting) {
|
||||||
ele.isEdge()
|
nodeDetails = this.getNotReportingNodeDetails(cyNode);
|
||||||
);
|
} else if (cyNode.data("state") === nodeStates.connected) {
|
||||||
if (selectedEle.state === nodeStates.notReporting) {
|
nodeDetails = this.getConnectedNodeDetails(
|
||||||
nodeDetails = this.getNotReportingNodeDetails(selectedNode); //Not reporting nodes
|
cyNode,
|
||||||
} else if (selectedEle.state === nodeStates.connected) {
|
connectedNodes,
|
||||||
nodeDetails = this.getConnectedNodeDetails(
|
connectedEdges
|
||||||
selectedNode,
|
);
|
||||||
connectedNodes,
|
} else if (cyNode.data("state") === nodeStates.noTunnels) {
|
||||||
connectedEdges
|
nodeDetails = this.getNotConnectedNodeDetails(cyNode);
|
||||||
); //Connected nodes
|
}
|
||||||
} else if (selectedEle.state === nodeStates.noTunnels) {
|
ReactDOM.render(
|
||||||
nodeDetails = this.getNotConnectedNodeDetails(selectedNode); //Not connected node
|
<div>
|
||||||
}
|
<div> Node Details </div>
|
||||||
return (
|
<div> {nodeDetails} </div>
|
||||||
<div>
|
</div>,
|
||||||
<div> Node Details </div>
|
document.getElementById("sideBarContent")
|
||||||
<div> {nodeDetails} </div>
|
);
|
||||||
</div>
|
})
|
||||||
);
|
.catch((err) => {
|
||||||
|
console.warn(err);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
getSourceAndTargetDetails(selectedTunnel) {
|
getConnectedLinkDetails(source, tgt, connectedEdges) {
|
||||||
|
for (var edge of connectedEdges) {
|
||||||
|
if (
|
||||||
|
(source.data().id === edge.data("source") &&
|
||||||
|
tgt.id === edge.data("target")) ||
|
||||||
|
(source.data().id === edge.data.target &&
|
||||||
|
tgt.id === edge.data("source"))
|
||||||
|
) {
|
||||||
|
for (var descriptorItem of edge.data("descriptor")) {
|
||||||
|
if (
|
||||||
|
source.data().id === descriptorItem.Source &&
|
||||||
|
tgt.id === descriptorItem.Target
|
||||||
|
) {
|
||||||
|
return [descriptorItem, edge.data("id")];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getSourceAndTargetDetails(cyEdge) {
|
||||||
var sourceNodeLinkDetails;
|
var sourceNodeLinkDetails;
|
||||||
var targetNodeLinkDetails;
|
var targetNodeLinkDetails;
|
||||||
var srcNode;
|
var srcNode;
|
||||||
var tgtNode;
|
var tgtNode;
|
||||||
|
var selectedTunnel = cyEdge.data();
|
||||||
for (var descriptor of selectedTunnel.descriptor) {
|
for (var descriptor of selectedTunnel.descriptor) {
|
||||||
if (
|
if (
|
||||||
descriptor.Source === selectedTunnel.source &&
|
descriptor.Source === selectedTunnel.source &&
|
||||||
descriptor.Target === selectedTunnel.target
|
descriptor.Target === selectedTunnel.target
|
||||||
) {
|
) {
|
||||||
sourceNodeLinkDetails = descriptor;
|
sourceNodeLinkDetails = descriptor;
|
||||||
srcNode = this.cy.getElementById(sourceNodeLinkDetails.Source)._private
|
srcNode = this.cy.getElementById(sourceNodeLinkDetails.Source).data();
|
||||||
.data;
|
|
||||||
if (selectedTunnel.descriptor.length === 1) {
|
if (selectedTunnel.descriptor.length === 1) {
|
||||||
tgtNode = this.cy.getElementById(sourceNodeLinkDetails.Target)
|
tgtNode = this.cy.getElementById(sourceNodeLinkDetails.Target).data();
|
||||||
._private.data;
|
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
descriptor.Target === selectedTunnel.source &&
|
descriptor.Target === selectedTunnel.source &&
|
||||||
|
@ -341,10 +490,6 @@ class TopologyView extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSwitch = () => {
|
|
||||||
this.setState({ isSwapToggle: !this.state.isSwapToggle });
|
|
||||||
};
|
|
||||||
|
|
||||||
getTunnelWithBothReportingNodes(selectedTunnel) {
|
getTunnelWithBothReportingNodes(selectedTunnel) {
|
||||||
var LocalEndpointInternal;
|
var LocalEndpointInternal;
|
||||||
var [sourceNodeLinkDetails, srcNode, tgtNode] =
|
var [sourceNodeLinkDetails, srcNode, tgtNode] =
|
||||||
|
@ -584,252 +729,75 @@ class TopologyView extends React.Component {
|
||||||
return linkContentNR;
|
return linkContentNR;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderTunnelDetails = () => {
|
renderTunnelDetails = (cyEdge) => {
|
||||||
|
var tunnelDetails;
|
||||||
var selectedTunnelNodesDetails = [];
|
var selectedTunnelNodesDetails = [];
|
||||||
var selectedEle = JSON.parse(this.props.selectedCyElementData);
|
try {
|
||||||
var selectedTunnel = this.cy.getElementById(selectedEle.id);
|
var partitionElements = this.partitionElements(cyEdge);
|
||||||
var partitionElements = this.partitionElements(selectedTunnel);
|
for (var node of partitionElements.neighborhood) {
|
||||||
for (var node of partitionElements.neighborhood) {
|
if (node._private.group === "nodes") {
|
||||||
if (node._private.group === "nodes") {
|
selectedTunnelNodesDetails.push(node.data());
|
||||||
selectedTunnelNodesDetails.push(node._private.data);
|
}
|
||||||
}
|
}
|
||||||
}
|
if (
|
||||||
if (
|
selectedTunnelNodesDetails[0].state === nodeStates.connected &&
|
||||||
selectedTunnelNodesDetails[0].state === nodeStates.connected &&
|
selectedTunnelNodesDetails[1].state === nodeStates.connected
|
||||||
selectedTunnelNodesDetails[1].state === nodeStates.connected
|
) {
|
||||||
) {
|
tunnelDetails = this.getTunnelWithBothReportingNodes(cyEdge);
|
||||||
return this.getTunnelWithBothReportingNodes(selectedEle);
|
} else if (
|
||||||
} else if (
|
(selectedTunnelNodesDetails[0].state === nodeStates.connected &&
|
||||||
(selectedTunnelNodesDetails[0].state === nodeStates.connected &&
|
selectedTunnelNodesDetails[1].state === nodeStates.notReporting) ||
|
||||||
selectedTunnelNodesDetails[1].state === nodeStates.notReporting) ||
|
(selectedTunnelNodesDetails[0].state === nodeStates.notReporting &&
|
||||||
(selectedTunnelNodesDetails[0].state === nodeStates.notReporting &&
|
selectedTunnelNodesDetails[1].state === nodeStates.connected)
|
||||||
selectedTunnelNodesDetails[1].state === nodeStates.connected)
|
) {
|
||||||
) {
|
tunnelDetails = this.getTunnelWithEitherOneReportingNodes(cyEdge);
|
||||||
return this.getTunnelWithEitherOneReportingNodes(selectedEle);
|
} else if (
|
||||||
} else if (
|
selectedTunnelNodesDetails[0].state === nodeStates.notReporting &&
|
||||||
selectedTunnelNodesDetails[0].state === nodeStates.notReporting &&
|
selectedTunnelNodesDetails[1].state === nodeStates.notReporting
|
||||||
selectedTunnelNodesDetails[1].state === nodeStates.notReporting
|
) {
|
||||||
) {
|
tunnelDetails = this.getTunnelWithNoReportingNodes();
|
||||||
return this.getTunnelWithNoReportingNodes();
|
}
|
||||||
|
ReactDOM.render(
|
||||||
|
<div>
|
||||||
|
<div> Tunnel Details </div>
|
||||||
|
<div> {tunnelDetails} </div>
|
||||||
|
</div>,
|
||||||
|
document.getElementById("sideBarContent")
|
||||||
|
);
|
||||||
|
} catch (err) {
|
||||||
|
console.warn(err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
renderSidebarDetails() {
|
handleSwitch = () => {
|
||||||
try {
|
this.setState({ isSwapToggle: !this.state.isSwapToggle });
|
||||||
if (this.props.selectedElementType === elementTypes.eleNode)
|
};
|
||||||
return this.renderNodeDetails();
|
|
||||||
else if (this.props.selectedElementType === elementTypes.eleTunnel)
|
|
||||||
return this.renderTunnelDetails();
|
|
||||||
return <null />;
|
|
||||||
} catch (e) {
|
|
||||||
return <null />; //when selected tunnel broken on refresh then returns null
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
renderTopologyContent() {
|
|
||||||
const topologyContent = (
|
|
||||||
<Cytoscape
|
|
||||||
id="cy"
|
|
||||||
cy={(cy) => {
|
|
||||||
this.cy = cy;
|
|
||||||
this.cy
|
|
||||||
.layout({
|
|
||||||
name: "circle",
|
|
||||||
clockwise: true,
|
|
||||||
animate: true,
|
|
||||||
animationDuration: 400,
|
|
||||||
})
|
|
||||||
.run();
|
|
||||||
this.cy.on("click", this.handleCytoClick.bind(this));
|
|
||||||
this.cy.maxZoom(this.props.zoomMax);
|
|
||||||
this.cy.minZoom(this.props.zoomMin);
|
|
||||||
this.cy.zoom(this.props.zoomValue); // has to be set after the other operations or it gets reset
|
|
||||||
//this.cy.center();
|
|
||||||
}}
|
|
||||||
wheelSensitivity={0.1}
|
|
||||||
elements={JSON.parse(JSON.stringify(this.props.cyElements))} //props.cyElements are frozen
|
|
||||||
stylesheet={cytoscapeStyle}
|
|
||||||
style={{ width: window.innerWidth, height: window.innerHeight }}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
return topologyContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
handleWheel(e) {
|
handleWheel(e) {
|
||||||
this.props.setZoomValue(this.cy.zoom());
|
this.props.setZoomValue(this.cy.zoom());
|
||||||
}
|
}
|
||||||
|
|
||||||
buildCyElements = (topologies) => {
|
|
||||||
var elements = [];
|
|
||||||
var nodeDetails = {};
|
|
||||||
|
|
||||||
if (topologies.length < 1) return elements;
|
|
||||||
var topology = topologies[0];
|
|
||||||
|
|
||||||
for (var nid in topology.Nodes) {
|
|
||||||
var node = topology.Nodes[nid];
|
|
||||||
var nodeData = {
|
|
||||||
group: "nodes",
|
|
||||||
data: {
|
|
||||||
id: node.NodeId,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
if (node.hasOwnProperty("NodeName"))
|
|
||||||
nodeData["data"]["label"] = node.NodeName;
|
|
||||||
else nodeData["data"]["label"] = node.NodeId.slice(0, 12);
|
|
||||||
if (node.hasOwnProperty("Version"))
|
|
||||||
nodeData["data"]["version"] = node.Version;
|
|
||||||
if (node.hasOwnProperty("GeoCoordinates"))
|
|
||||||
nodeData["data"]["coords"] = node.GeoCoordinates;
|
|
||||||
if (node.hasOwnProperty("Edges")) {
|
|
||||||
nodeData["data"]["edges"] = node.Edges;
|
|
||||||
if (node.Edges.length === 0) {
|
|
||||||
nodeData["data"]["state"] = nodeStates.noTunnels;
|
|
||||||
nodeData["data"]["color"] = "#F2BE22";
|
|
||||||
} else {
|
|
||||||
nodeData["data"]["state"] = nodeStates.connected;
|
|
||||||
nodeData["data"]["color"] = "#8AA626";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
nodeData["data"]["state"] = nodeStates.notReporting;
|
|
||||||
nodeData["data"]["color"] = "#ADD8E6";
|
|
||||||
}
|
|
||||||
nodeDetails[node.NodeId] = nodeData;
|
|
||||||
}
|
|
||||||
for (var edgeId in topology.Edges) {
|
|
||||||
var edge = topology.Edges[edgeId];
|
|
||||||
if (edge["Descriptor"].length > 2) {
|
|
||||||
console.error(
|
|
||||||
"Too many edge descriptors reported ",
|
|
||||||
JSON.stringify(edge["Descriptor"])
|
|
||||||
);
|
|
||||||
}
|
|
||||||
var edgeData = {
|
|
||||||
group: "edges",
|
|
||||||
data: {},
|
|
||||||
};
|
|
||||||
edgeData["data"]["id"] = edge.EdgeId;
|
|
||||||
edgeData["data"]["descriptor"] = edge["Descriptor"];
|
|
||||||
edgeData["data"]["label"] = edge.EdgeId.slice(0, 12);
|
|
||||||
edgeData["data"]["source"] = edge["Descriptor"][0].Source;
|
|
||||||
edgeData["data"]["target"] = edge["Descriptor"][0].Target;
|
|
||||||
edgeData["data"]["color"] = this.getLinkColor(edge["Descriptor"][0].Type);
|
|
||||||
edgeData["data"]["style"] = this.getLinkStyle(
|
|
||||||
edge["Descriptor"][0].State
|
|
||||||
);
|
|
||||||
if (
|
|
||||||
edge["Descriptor"].length === 2 &&
|
|
||||||
edge["Descriptor"][0].Source > edge["Descriptor"][1].Source
|
|
||||||
) {
|
|
||||||
edgeData["data"]["source"] = edge["Descriptor"][1].Source;
|
|
||||||
edgeData["data"]["target"] = edge["Descriptor"][1].Target;
|
|
||||||
edgeData["data"]["color"] = this.getLinkColor(
|
|
||||||
edge["Descriptor"][1].Type
|
|
||||||
);
|
|
||||||
edgeData["data"]["style"] = this.getLinkStyle(
|
|
||||||
edge["Descriptor"][1].State
|
|
||||||
);
|
|
||||||
}
|
|
||||||
elements.push(edgeData);
|
|
||||||
}
|
|
||||||
var nodes = Object.keys(nodeDetails).sort();
|
|
||||||
nodes.forEach((nodeId) => elements.push(nodeDetails[nodeId]));
|
|
||||||
|
|
||||||
return elements;
|
|
||||||
};
|
|
||||||
|
|
||||||
getLinkColor(type) {
|
|
||||||
var linkColor;
|
|
||||||
switch (type) {
|
|
||||||
case "CETypeILongDistance":
|
|
||||||
linkColor = "#5E4FA2";
|
|
||||||
break;
|
|
||||||
case "CETypeLongDistance":
|
|
||||||
linkColor = "#5E4FA2";
|
|
||||||
break;
|
|
||||||
case "CETypePredecessor":
|
|
||||||
linkColor = "#01665E";
|
|
||||||
break;
|
|
||||||
case "CETypeSuccessor":
|
|
||||||
linkColor = "#01665E";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return linkColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
getLinkStyle(state) {
|
|
||||||
var linkStyle;
|
|
||||||
switch (state) {
|
|
||||||
case "CEStateInitialized":
|
|
||||||
case "CEStatePreAuth":
|
|
||||||
case "CEStateAuthorized":
|
|
||||||
case "CEStateCreated":
|
|
||||||
linkStyle = "dotted";
|
|
||||||
break;
|
|
||||||
case "CEStateConnected":
|
|
||||||
linkStyle = "solid";
|
|
||||||
break;
|
|
||||||
case "CEStateDisconnected":
|
|
||||||
case "CEStateDeleting":
|
|
||||||
linkStyle = "dashed";
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return linkStyle;
|
|
||||||
}
|
|
||||||
|
|
||||||
partitionElements(selectedElement) {
|
|
||||||
var neighborhood;
|
|
||||||
var excluded;
|
|
||||||
if (selectedElement.isNode()) {
|
|
||||||
this.props.setSelectedElement({
|
|
||||||
selectedElementType: elementTypes.eleNode,
|
|
||||||
selectedCyElementData: selectedElement.data(),
|
|
||||||
});
|
|
||||||
neighborhood = selectedElement
|
|
||||||
.outgoers()
|
|
||||||
.union(selectedElement.incomers())
|
|
||||||
.union(selectedElement);
|
|
||||||
excluded = this.cy
|
|
||||||
.elements()
|
|
||||||
.difference(
|
|
||||||
selectedElement.outgoers().union(selectedElement.incomers())
|
|
||||||
)
|
|
||||||
.not(selectedElement);
|
|
||||||
} else if (selectedElement.isEdge()) {
|
|
||||||
this.props.setSelectedElement({
|
|
||||||
selectedElementType: elementTypes.eleTunnel,
|
|
||||||
selectedCyElementData: selectedElement.data(),
|
|
||||||
});
|
|
||||||
neighborhood = selectedElement.connectedNodes().union(selectedElement);
|
|
||||||
excluded = this.cy
|
|
||||||
.elements()
|
|
||||||
.difference(selectedElement.connectedNodes())
|
|
||||||
.not(selectedElement);
|
|
||||||
}
|
|
||||||
return { neighborhood, excluded };
|
|
||||||
}
|
|
||||||
|
|
||||||
handleCytoClick(event) {
|
handleCytoClick(event) {
|
||||||
var selectedElement = event.target[0];
|
var cyEle = event.target[0];
|
||||||
var part;
|
|
||||||
try {
|
try {
|
||||||
if (event.target === this.cy) {
|
if (event.target === this.cy) {
|
||||||
this.props.clearSelectedElement();
|
//this.props.clearSelectedElement();
|
||||||
this.cy.elements().removeClass("transparent");
|
this.cy.elements().removeClass("transparent");
|
||||||
this._typeahead.clear();
|
this._typeahead.clear();
|
||||||
} else {
|
return;
|
||||||
part = this.partitionElements(selectedElement);
|
}
|
||||||
part.neighborhood.removeClass("transparent");
|
var part = this.partitionElements(cyEle);
|
||||||
part.excluded.addClass("transparent");
|
part.neighborhood.removeClass("transparent");
|
||||||
|
part.excluded.addClass("transparent");
|
||||||
|
if (cyEle.isNode()) {
|
||||||
|
this.renderNodeDetails(cyEle, cyEle.neighborhood());
|
||||||
|
} else if (cyEle.isEdge()) {
|
||||||
|
this.renderTunnelDetails(cyEle, part.neighborhood);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.props.clearSelectedElement();
|
//this.props.clearSelectedElement();
|
||||||
this.cy.elements().removeClass("transparent");
|
this.cy.elements().removeClass("transparent");
|
||||||
|
console.warn(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -865,10 +833,40 @@ class TopologyView extends React.Component {
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
this.autoRefresh = false;
|
this.autoRefresh = false;
|
||||||
clearTimeout(this.timeoutId);
|
clearTimeout(this.timeoutId);
|
||||||
this.props.clearSelectedElement();
|
//this.props.clearSelectedElement();
|
||||||
this.props.setCyElements([]);
|
this.props.setCyElements([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderTopologyContent() {
|
||||||
|
const topologyContent = (
|
||||||
|
<Cytoscape
|
||||||
|
id="cy"
|
||||||
|
cy={(cy) => {
|
||||||
|
this.cy = cy;
|
||||||
|
this.cy
|
||||||
|
.layout({
|
||||||
|
name: "circle",
|
||||||
|
clockwise: true,
|
||||||
|
animate: true,
|
||||||
|
animationDuration: 400,
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
this.cy.on("click", this.handleCytoClick.bind(this));
|
||||||
|
this.cy.maxZoom(this.props.zoomMax);
|
||||||
|
this.cy.minZoom(this.props.zoomMin);
|
||||||
|
this.cy.zoom(this.props.zoomValue); // has to be set after the other operations or it gets reset
|
||||||
|
//this.cy.center();
|
||||||
|
}}
|
||||||
|
wheelSensitivity={0.1}
|
||||||
|
elements={JSON.parse(JSON.stringify(this.props.cyElements))} //props.cyElements are frozen
|
||||||
|
stylesheet={cytoscapeStyle}
|
||||||
|
style={{ width: window.innerWidth, height: window.innerHeight }}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
return topologyContent;
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -879,13 +877,7 @@ class TopologyView extends React.Component {
|
||||||
<div id="cyArea">{this.renderTopologyContent()}</div>
|
<div id="cyArea">{this.renderTopologyContent()}</div>
|
||||||
</section>
|
</section>
|
||||||
<div id="SidePanel">
|
<div id="SidePanel">
|
||||||
<SideBar
|
<SideBar typeahead={this.renderTypeahead()} />
|
||||||
typeahead={this.renderTypeahead()}
|
|
||||||
sidebarDetails={this.renderSidebarDetails()}
|
|
||||||
/>
|
|
||||||
{/* <div id="bottomTools">
|
|
||||||
<Toolbar />
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
@ -894,8 +886,8 @@ class TopologyView extends React.Component {
|
||||||
|
|
||||||
const mapStateToProps = (state) => ({
|
const mapStateToProps = (state) => ({
|
||||||
currentOverlayId: state.evio.selectedOverlayId,
|
currentOverlayId: state.evio.selectedOverlayId,
|
||||||
selectedElementType: state.evio.selectedElementType,
|
//selectedElementType: state.evio.selectedElementType,
|
||||||
selectedCyElementData: state.evio.selectedCyElementData,
|
//selectedCyElementData: state.evio.selectedCyElementData,
|
||||||
cyElements: state.evio.cyElements,
|
cyElements: state.evio.cyElements,
|
||||||
currentView: state.view.current,
|
currentView: state.view.current,
|
||||||
selectedView: state.view.selected,
|
selectedView: state.view.selected,
|
||||||
|
@ -910,8 +902,8 @@ const mapDispatchToProps = {
|
||||||
setCurrentView,
|
setCurrentView,
|
||||||
setZoomValue,
|
setZoomValue,
|
||||||
setCyElements,
|
setCyElements,
|
||||||
setSelectedElement,
|
//setSelectedElement,
|
||||||
clearSelectedElement,
|
//clearSelectedElement,
|
||||||
setRedrawGraph,
|
setRedrawGraph,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue