From 24fead79cbe5ef168a42f08da6fd99b4ec2b1bab Mon Sep 17 00:00:00 2001 From: Petr Vobornik Date: Thu, 12 Nov 2015 18:17:50 +0100 Subject: [PATCH] webui: topology graph component https://fedorahosted.org/freeipa/ticket/4286 Reviewed-By: Martin Babinsky --- install/ui/doc/categories.json | 4 +- install/ui/jsl.conf | 2 +- install/ui/less/widgets.less | 45 ++- install/ui/src/freeipa/topology_graph.js | 380 +++++++++++++++++++++++ 4 files changed, 428 insertions(+), 3 deletions(-) create mode 100644 install/ui/src/freeipa/topology_graph.js diff --git a/install/ui/doc/categories.json b/install/ui/doc/categories.json index 93cadfe5d..7e9e19e9a 100644 --- a/install/ui/doc/categories.json +++ b/install/ui/doc/categories.json @@ -193,7 +193,8 @@ "widget.alert_helper", "IPA.option_widget_base", "IPA.column", - "IPA.html_util" + "IPA.html_util", + "topology_graph.TopoGraph" ] }, { @@ -257,6 +258,7 @@ "radiusproxy", "stageuser", "topology", + "topology_graph", "user", "plugins.api_browser", "plugins.caacl", diff --git a/install/ui/jsl.conf b/install/ui/jsl.conf index 3e3bec05a..14d56810d 100644 --- a/install/ui/jsl.conf +++ b/install/ui/jsl.conf @@ -33,7 +33,7 @@ +octal_number # leading zeros make an octal number +nested_comment # nested comment +misplaced_regex # regular expressions should be preceded by a left parenthesis, assignment, colon, or comma -+ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement +-ambiguous_newline # unexpected end of line; it is ambiguous whether these lines are part of the same statement +empty_statement # empty statement or extra semicolon -missing_option_explicit # the "option explicit" control comment is missing +partial_option_explicit # the "option explicit" control comment, if used, must be in the first script tag diff --git a/install/ui/less/widgets.less b/install/ui/less/widgets.less index 99b22068d..0f9bc8c17 100644 --- a/install/ui/less/widgets.less +++ b/install/ui/less/widgets.less @@ -144,4 +144,47 @@ } // workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=409254 -tbody:empty { display: none; } \ No newline at end of file +tbody:empty { display: none; } + +// Topology Graph + +.topology-view { + svg { + background-color: #FFF; + cursor: default; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + } + + path.link { + fill: none; + stroke-width: 4px; + cursor: pointer; + } + + .marker { + stroke: rgba(0, 0, 0); + } + + path.link.selected { + stroke-dasharray: 10,2; + } + + circle.node { + stroke-width: 1.5px; + cursor: pointer; + } + + text { + font: 16px sans-serif; + pointer-events: none; + } + + text.id { + text-anchor: middle; + font-weight: bold; + } +} diff --git a/install/ui/src/freeipa/topology_graph.js b/install/ui/src/freeipa/topology_graph.js new file mode 100644 index 000000000..94d0aa6bf --- /dev/null +++ b/install/ui/src/freeipa/topology_graph.js @@ -0,0 +1,380 @@ +// +// Copyright (C) 2015 FreeIPA Contributors see COPYING for license +// + +'use strict'; + +define([ + 'dojo/_base/lang', + 'dojo/_base/declare', + 'dojo/on', + 'dojo/Evented', + './jquery', + 'libs/d3' +], + function(lang, declare, on, Evented, $, d3) { +/** + * Topology Graph module + * @class + * @singleton + */ +var topology_graph = { +}; + +/** + * Topology graph visualization + * + * @class + */ +topology_graph.TopoGraph = declare([Evented], { + width: 960, + height: 500, + _colors: d3.scale.category10(), + _svg : null, + _path: null, + _circle: null, + + _selected_link: null, + _mousedown_link: null, + + /** + * Nodes - IPA servers + * id - int + * + * @property {Array} + */ + nodes: [], + + /** + * Links between nodes + * @property {Array} + */ + links: [], + + /** + * List of suffices + * @property {Array} + */ + suffices: [], + + /** + * Initializes the graph + * @param {HTMLElement} container container where to put the graph svg element + */ + initialize: function(container) { + this._create_svg(container); + this.update(this.nodes, this.links, this.suffices); + return; + }, + + /** + * Update the graph + * @param {Array} nodes array of node objects + * @param {Array} links array of link objects + * @param {Array} suffices array of suffices + */ + update: function(nodes, links, suffices) { + // delete all from svg + this._svg.selectAll("*").remove(); + this._svg.attr('width', this.width) + .attr('height', this.height); + + this.links = links; + this.nodes = nodes; + this.suffices = suffices; + + // load saved coordinates + for (var i=0,l=nodes.length; i 1 ? 1 : 0, // shift from center? + spad = d.left ? 18 : 18, // source padding + tpad = d.right ? 18 : 18, // target padding + sourceX = d.source.x + (spad * ux) + off * nx * ns * s, + sourceY = d.source.y + (spad * uy) + off * ny * ns * s, + targetX = d.target.x - (tpad * ux) + off * nx * ns * s, + targetY = d.target.y - (tpad * uy) + off * ny * ns * s, + dr = s ? dist * Math.log10(dist) : 0; + + return 'M' + sourceX + ',' + sourceY + + 'A' + dr + " " + dr + " 0 0 " + dir +" " + + targetX + " " + targetY; + }); + + this._circle.attr('transform', function(d) { + self._save_node_info(d); + return 'translate(' + d.x + ',' + d.y + ')'; + }); + }, + + _get_marker_name: function(suffix, start) { + + var name = suffix ? suffix.cn[0] : 'drag'; + var arrow = start ? 'start-arrow' : 'end-arrow'; + return name + '-' + arrow; + }, + + /** + * Markers on the end of links + */ + _add_marker: function(name, color, refX) { + this._svg.append('svg:defs') + .append('svg:marker') + .attr('id', name) + .attr('viewBox', '0 -5 10 10') + .attr('refX', 6) + .attr('markerWidth', 3) + .attr('markerHeight', 3) + .attr('orient', 'auto') + .append('svg:path') + .attr('d', refX) + .attr('fill', color); + }, + + /** + * Suffix hint so user will know which links belong to which suffix + */ + _append_suffix_hint: function(suffix, x, y) { + var color = d3.rgb(this._colors(suffix.cn[0])); + this._svg.append('svg:text') + .attr('x', x) + .attr('y', y) + .attr('class', 'suffix') + .attr('fill', color) + .text(suffix.cn[0]); + }, + + /** + * Defines link arrows and colors of suffices(links) and nodes + */ + _define_shapes: function() { + + var name, color; + + var defs = this._svg.selectAll('defs'); + defs.remove(); + + var x = 10; + var y = 20; + + for (var i=0,l=this.suffices.length; i