blob: 0ce6d1f586746e2c2aed6d8695b49cc296532383 [file] [log] [blame]
var mercury = require('mercury');
var insertCss = require('insert-css');
var vis = require('vis');
var css = require('./index.css');
var namespaceService = require('../../services/namespace/service');
var log = require('../../lib/log')('components:visualize');
module.exports = create;
module.exports.render = render;
// Maximum number of levels that are automatically shown
var MAX_AUTO_LOAD_DEPTH = 3;
/*
* Visualize view
*/
function create() {}
function render(browseState) {
insertCss(css);
return [
new TreeWidget(browseState)
];
}
function TreeWidget(browseState) {
if (!(this instanceof TreeWidget)) {
return new TreeWidget(browseState);
}
this.browseState = browseState;
this.nodes = new vis.DataSet();
this.edges = new vis.DataSet();
}
TreeWidget.prototype.type = 'Widget';
TreeWidget.prototype.init = function() {
var elem = document.createElement('div');
elem.className = 'tree';
requestAnimationFrame(this.initNetwork.bind(this, elem));
return elem;
};
TreeWidget.prototype.initNetwork = function(elem) {
var self = this;
// Add the initial node.
var rootNodeId = this.browseState.namespace;
this.nodes.add({
id: rootNodeId,
label: rootNodeId || '<root>',
level: 0
});
// Load the subnodes.
this.rootNode = this.nodes.get(rootNodeId);
this.loadSubNodes(this.rootNode);
var options = {
hover: false,
selectable: true, // Need this or nodes won't be click-able
smoothCurves: true,
stabilize: false,
edges: {
width: 1
},
nodes: {
radiusMin: 16,
radiusMax: 32,
fontColor: '#333333',
shape: 'dot',
color: {
background: '#03a9f4',
border: '#0288d1'
}
}
};
// Start drawing the network.
var network = new vis.Network(elem, {
nodes: this.nodes,
edges: this.edges
}, options);
// Event listeners.
network.on('click', function onClick(data) {
var nodeId = data.nodes[0];
var node = network.nodes[nodeId];
if (node && !node.subNodesLoaded) {
self.loadSubNodes(node);
}
});
return network;
};
TreeWidget.prototype.loadSubNodes = function(node) {
var namespace = node.id;
node.subNodesLoaded = true;
node.title = undefined;
var self = this;
namespaceService.getChildren(namespace).then(function(resultObservable) {
mercury.watch(resultObservable, function(results) {
// TODO(aghassemi) support removed and updated nodes when we switch to
// watchGlob
var existingIds = self.nodes.getIds();
var nodesToAdd = results.filter(function(item) {
var isNew = existingIds.indexOf(item.objectName) === -1;
return isNew;
});
var newNodes = nodesToAdd.map(function(item) {
var shape = 'dot';
var color;
if (item.isServer) {
shape = 'triangle';
color = '#ffab40';
}
return {
id: item.objectName,
label: item.mountedName,
level: node.level + 1,
shape: shape,
color: color,
isGlobbable: item.isGlobbable
};
});
var newEdges = nodesToAdd.map(function(item) {
return {
from: namespace,
to: item.objectName,
color: '#cccccc'
};
});
newNodes.forEach(function(item) {
// recurse if within the MAX_AUTO_LOAD_DEPTH
if (!item.isGlobbable) {
return;
}
if (item.level - self.rootNode.level < MAX_AUTO_LOAD_DEPTH) {
self.loadSubNodes(item);
} else {
item.title = 'Click to expand';
}
});
self.nodes.add(newNodes);
self.edges.add(newEdges);
});
}).catch(function(err) {
log.error('glob failed', err);
});
};
TreeWidget.prototype.update = function(prev, elem) {};