diff --git a/src/components/Graph.jsx b/src/components/Graph.jsx
index 5cc8870..1d2a8c2 100644
--- a/src/components/Graph.jsx
+++ b/src/components/Graph.jsx
@@ -1,5 +1,5 @@
import React, { Component } from 'react';
-import { collapseEdgeNodes, setNodeData, collapseSiblingNodes } from 'utils';
+import { collapseEdgeNodes, setNodeData, collapseSiblingNodes, findGraphPath } from 'utils';
export default class GraphContainer extends Component {
constructor(props){
@@ -53,7 +53,7 @@ export default class GraphContainer extends Component {
function(sigmaInstance){
appStore.spotlightData = {}
var design = this.state.design;
- sigmaInstance = setNodeData(this.state.sigmaInstance);
+ sigmaInstance = setNodeData(this.state.sigmaInstance, params.start, params.end);
if (params.allowCollapse){
sigmaInstance = collapseEdgeNodes(sigmaInstance);
sigmaInstance = collapseSiblingNodes(sigmaInstance);
@@ -89,20 +89,20 @@ export default class GraphContainer extends Component {
doPathQuery(start, end){
var statement = "MATCH (n {name:'{}'}), (m {name:'{}'}), p=allShortestPaths((n)-[*]->(m)) RETURN p".format(start,end)
- appStore.startNode = start
- appStore.endNode = end
this.doQueryNative({
statement: statement,
- allowCollapse: true
+ allowCollapse: true,
+ start: start,
+ end: end
})
}
doGenericQuery(statement, start, end, allowCollapse=true){
- appStore.startNode = start
- appStore.endNode = end
this.doQueryNative({
statement: statement,
allowCollapse: allowCollapse,
+ start: start,
+ end: end
})
}
@@ -192,6 +192,36 @@ export default class GraphContainer extends Component {
sigmaInstance.bind('clickNode', this._nodeClicked.bind(this))
+ sigmaInstance.bind('hovers', function(e){
+ if (e.data.enter.nodes.length > 0) {
+ if (appStore.endNode !== null) {
+ findGraphPath(this.state.sigmaInstance, false, e.data.enter.nodes[0].id)
+ }
+
+ if (appStore.startNode !== null) {
+ findGraphPath(this.state.sigmaInstance, true, e.data.enter.nodes[0].id)
+ }
+ }
+
+ if (e.data.leave.nodes.length > 0) {
+ if (appStore.forwardPath.length > 0) {
+ $.each(appStore.forwardPath, function(index, edge) {
+ edge.color = '#356';
+ });
+ appStore.forwardPath = [];
+ sigmaInstance.refresh({ 'skipIndexation': true });
+ }
+
+ if (appStore.reversePath.length > 0) {
+ $.each(appStore.reversePath, function(index, edge) {
+ edge.color = '#356';
+ });
+ appStore.reversePath = [];
+ sigmaInstance.refresh({ 'skipIndexation': true });
+ }
+ }
+ }.bind(this))
+
var fa = sigma.layouts.configForceLink(sigmaInstance, {
worker: true,
background: true,
diff --git a/src/components/SearchContainer/Tabs/GroupNodeData.jsx b/src/components/SearchContainer/Tabs/GroupNodeData.jsx
index a0d560f..9905768 100644
--- a/src/components/SearchContainer/Tabs/GroupNodeData.jsx
+++ b/src/components/SearchContainer/Tabs/GroupNodeData.jsx
@@ -107,7 +107,9 @@ export default class GroupNodeData extends Component {
+ click={function(){
+ emitter.emit('query', "MATCH (n)-[r:MemberOf]->(m:Group {name:'{}'}) RETURN n,r,m".format(this.state.label))
+ }.bind(this)} />
Unrolled Members
@@ -116,7 +118,10 @@ export default class GroupNodeData extends Component {
+ click={function(){
+ emitter.emit('query', "MATCH (n:User), (m:Group {name:'{}'}), p=allShortestPaths((n)-[:MemberOf*1..]->(m)) RETURN p".format(this.state.label),
+ this.state.label)
+ }.bind(this)} />
@@ -126,7 +131,10 @@ export default class GroupNodeData extends Component {
+ click={function(){
+ emitter.emit('query', "MATCH (n:Group {name:'{}'})-[r:AdminTo]->(m:Computer) RETURN n,r,m".format(this.state.label),
+ this.state.label)
+ }.bind(this)} />
@@ -136,7 +144,10 @@ export default class GroupNodeData extends Component {
+ click={function(){
+ emitter.emit('query', "MATCH (n:Group {name:'{}'}), (target:Computer), p=allShortestPaths((n)-[*]->(target)) RETURN p".format(this.state.label),
+ this.state.label)
+ }.bind(this)} />
Unrolled Member Of
@@ -145,7 +156,10 @@ export default class GroupNodeData extends Component {
+ click={function(){
+ emitter.emit('query', "MATCH (n:Group {name:'{}'}), (target:Group), p=allShortestPaths((n)-[r:MemberOf*1..]->(target)) RETURN p".format(this.state.label),
+ this.state.label)
+ }.bind(this)} />
Sessions
@@ -154,7 +168,10 @@ export default class GroupNodeData extends Component {
+ click={function(){
+ emitter.emit('query', "MATCH (n:User), (m:Group {name: '{}'}), p=allShortestPaths((n)-[r:MemberOf*1..]->(m)) WITH n,m,r MATCH (n)-[s:HasSession]-(o:Computer) RETURN m,n,r,o,s".format(this.state.label),
+ this.state.label)
+ }.bind(this)} />
diff --git a/src/components/SearchContainer/Tabs/UserNodeData.jsx b/src/components/SearchContainer/Tabs/UserNodeData.jsx
index f091eb0..ed761bf 100644
--- a/src/components/SearchContainer/Tabs/UserNodeData.jsx
+++ b/src/components/SearchContainer/Tabs/UserNodeData.jsx
@@ -27,10 +27,6 @@ export default class UserNodeData extends Component {
emitter.on('userNodeClicked', this.getNodeData.bind(this));
}
- placeholder(){
-
- }
-
getNodeData(payload){
this.setState({
label: payload,
diff --git a/src/index.js b/src/index.js
index 35c5589..8f932d5 100644
--- a/src/index.js
+++ b/src/index.js
@@ -33,6 +33,8 @@ Array.prototype.allEdgesSameType = function() {
global.appStore = {
startNode: null,
endNode: null,
+ reversePath: [],
+ forwardPath: [],
spotlightData: {},
queryStack: [],
currentTooltip: null,
diff --git a/src/js/bloodhound.js b/src/js/bloodhound.js
index 7c32363..4b37208 100644
--- a/src/js/bloodhound.js
+++ b/src/js/bloodhound.js
@@ -984,7 +984,7 @@ function reversepath(nid) {
tedge = pos;
}
});
- tedge.color = 'blue';
+ tedge.color = reverse ? 'blue' : 'red';
reversePath.push(tedge);
reversepath(nextnode);
});
diff --git a/src/js/utils.js b/src/js/utils.js
index dcdb46f..c20797b 100644
--- a/src/js/utils.js
+++ b/src/js/utils.js
@@ -10,14 +10,15 @@ export function buildAuthHeader(){
//Graph Utils
export function setNodeData(sigmaInstance, startLabel, endLabel){
- var startNode = null;
- var endNode = null;
+ appStore.startNode = null;
+ appStore.endNode = null;
- startLabel = (typeof startLabel === 'undefined') ? "" : startLabel
- endLabel = (typeof endLabel === 'undefined') ? "" : endLabel
+ startLabel = (typeof startLabel === 'undefined') ? undefined : startLabel
+ endLabel = (typeof endLabel === 'undefined') ? undefined : endLabel
$.each(sigmaInstance.graph.nodes(), function(index, node){
node.degree = sigmaInstance.graph.degree(node.id);
+ node.glyphs = []
});
$.each(sigmaInstance.graph.nodes(), function(index, node){
@@ -41,10 +42,24 @@ export function setNodeData(sigmaInstance, startLabel, endLabel){
if (node.neo4j_data.name === startLabel){
appStore.startNode = node;
+ node.glyphs.push({
+ 'position': 'bottom-right',
+ 'font': 'FontAwesome',
+ 'content': '\uF21D',
+ 'fillColor': '#3399FF',
+ 'fontScale': 1.5
+ })
}
if (node.neo4j_data.name === endLabel){
appStore.endNode = node;
+ node.glyphs.push({
+ 'position': 'bottom-right',
+ 'font': 'FontAwesome',
+ 'fillColor': '#990000',
+ 'content': '\uF05B',
+ 'fontScale': 1.5
+ })
}
});
return sigmaInstance
@@ -87,10 +102,10 @@ export function collapseEdgeNodes(sigmaInstance){
node.folded.edges.push(edge)
appStore.spotlightData[anode.id] = [anode.neo4j_data.name, node.id, node.neo4j_data.name];
sigmaInstance.graph.dropNode(anode.id);
- node.glyphs = [{
+ node.glyphs.push({
'position': 'bottom-left',
'content': node.folded.nodes.length
- }]
+ })
}
});
})
@@ -127,7 +142,7 @@ export function collapseSiblingNodes(sigmaInstance){
//Generate our string to compare other nodes to
//by sorting the parents and turning it into a string
var checkString = parents.sort().join(',')
- var testString;
+ var testString;
//Loop back over nodes in the graph and look for any nodes
//with identical parents
@@ -212,6 +227,29 @@ export function generateUniqueId(sigmaInstance, isNode){
return i
}
+export function findGraphPath(sigmaInstance, reverse, nodeid){
+ var target = reverse ? appStore.startNode : appStore.endNode
+
+ if (nodeid !== target.id){
+ var edges = sigmaInstance.graph.adjacentEdges(nodeid)
+ var nodes = reverse ? sigmaInstance.graph.inboundNodes(nodeid) : sigmaInstance.graph.outboundNodes(nodeid)
+ $.each(nodes, function(index, node){
+ $.each(edges, function(index, edge){
+ var check = reverse ? edge.source : edge.target
+ if (check === node){
+ edge.color = reverse ? 'blue' : 'red';
+ appStore.reversePath.push(edge);
+ findGraphPath(sigmaInstance, reverse, node);
+ }
+ })
+ })
+ }else{
+ sigmaInstance.refresh({'skipIndexation': true})
+ }
+}
+
+
+//Utilities for generating AJAX requests
export function defaultAjaxSettings(){
return {
url: appStore.databaseInfo.url + '/db/data/transaction/commit',