Improve style of network topology

fixes bug 1129190
- display a message when there is no router, network or instance to show
- remove link from not owned network
- improve layout algorithm
- improve css to change router icon
- fix auto update layout

Change-Id: Ibbbf55a53939ab1446f3cb36165a5cf45c27c28c
This commit is contained in:
Toshiyuki Hayashi 2013-02-20 14:01:52 -08:00 committed by Nachi Ueno
parent f754398492
commit 1cb3dc768e
6 changed files with 114 additions and 106 deletions

View File

@ -2,6 +2,7 @@
horizon.network_topology = {
model: null,
network_margin: 270,
topologyCanvas_padding: 120,
min_network_height:500,
port_margin: 20,
device_initial_position : 40,
@ -20,15 +21,16 @@ horizon.network_topology = {
var self = this;
$("#topologyCanvas").spin(horizon.conf.spinner_options.modal);
self.retrieve_network_info();
setInterval(horizon.network_topology.retrieve_network_info,
horizon.network_topology.reload_duration);
setInterval(function(){
self.retrieve_network_info();
}, self.reload_duration);
},
retrieve_network_info: function(){
var self = this;
if($("#networktopology").length === 0) {
return;
}
$.getJSON($("#networktopology").data('networktopology'),
$.getJSON($("#networktopology").data("networktopology"),
function(data) {
self.draw_graph(data);
}
@ -40,19 +42,27 @@ horizon.network_topology = {
draw_graph: function(data){
var canvas = $("#topologyCanvas");
var networks = $("#topologyCanvas > .networks");
var nodata = $("#topologyCanvas > .nodata");
networks.show();
nodata.hide();
canvas.spin(false);
networks.empty();
this.model = data;
this.device_last_position = this.device_initial_position;
this.draw_networks();
this.draw_routers();
this.draw_servers();
canvas.height(
Math.max(this.device_last_position,this.min_network_height)
);
networks.width(
this.model.networks.length * this.network_margin
);
var network_elements = this.draw_networks();
var router_elements = this.draw_routers();
var server_elements = this.draw_servers();
if ((network_elements + router_elements + server_elements) <= 0){
networks.hide();
nodata.show();
} else {
canvas.height(
Math.max(this.device_last_position + this.topologyCanvas_padding, this.min_network_height)
);
networks.width(
this.model.networks.length * this.network_margin
);
}
},
network_color: function(network_id){
var max_hue = 360;
@ -115,18 +125,24 @@ horizon.network_topology = {
if(network['router:external']){
label += " (external) ";
}
label += self.select_cidr(network.id);
self.network_index[network.id] = index;
var network_html = $("<div class='network' />").attr("id", network.id);
var nicname_html = $("<div class='nicname'><h3>" + label + "</h3></div>");
var nicname_html = $("<div class='nicname'><h3>" + label +
"</h3><span class='ip'>" + self.select_cidr(network.id) + "</span></div>");
if (network.url == undefined) {
nicname_html.addClass("nourl");
} else {
nicname_html.click(function (){
window.location.href = network.url;
});
}
nicname_html
.click(function (){
window.location.href = network.url;})
.css (
{'background-color':self.network_color(network.id)})
.appendTo(network_html);
networks.append(network_html);
});
return self.model.networks.length;
},
select_cidr:function(network_id){
var cidr = "";
@ -134,13 +150,13 @@ horizon.network_topology = {
if(subnet.network_id != network_id){
return;
}
cidr += " <span class=\"ip\">[ " + subnet.cidr + " ]</span>";
cidr += subnet.cidr;
});
return cidr;
},
draw_devices: function(type){
var self = this;
$.each(self.model[type + 's'], function(index, device){
$.each(self.model[type + 's'], function(index, device){
var id = device.id;
var name = (device.name != "")? device.name : device.id;
var ports = self.select_port(id);
@ -176,6 +192,7 @@ horizon.network_topology = {
self.device_last_position += device_html.height() + self.device_margin;
$("#" + parent_network).append(device_html);
});
return self.model[type + 's'].length;
},
sum_port_length: function(network_id, ports){
var self = this;
@ -200,10 +217,10 @@ horizon.network_topology = {
return ports[main_port_index];
},
draw_routers: function(){
this.draw_devices('router');
return this.draw_devices('router');
},
draw_servers: function(){
this.draw_devices('server');
return this.draw_devices('server');
},
select_port: function(device_id){
return $.map(this.model.ports,function(port, index){

View File

@ -20,7 +20,7 @@ div.network .device:hover div.port {
}
</style>
<noscript>
{%trans "This pane needs javascript support." %}
{% trans "This pane needs javascript support." %}
</noscript>
<div class="launchButtons">
<a href="{% url horizon:project:instances:launch %}" id="instances__action_launch" class="btn btn-small btn-launch ajax-modal">{%trans "Launch Instance" %}</a>
@ -30,6 +30,7 @@ div.network .device:hover div.port {
<div id="topologyCanvas">
<div class="networks"></div>
<div class="nodata">{% blocktrans %}There are no networks, routers, or connected instances to display. {% endblocktrans %}</div>
</div>
<span data-networktopology="{% url horizon:project:network_topology:json %}" id="networktopology"></span>
{% endblock %}

View File

@ -33,7 +33,11 @@ class NetworkTopology(TemplateView):
class JSONView(View):
def add_resource_url(self, view, resources):
tenant_id = self.request.user.tenant_id
for resource in resources:
if (resource.get('tenant_id')
and tenant_id != resource.get('tenant_id')):
continue
resource['url'] = reverse(view, None, [str(resource['id'])])
def _select_port_by_network_id(self, ports, network_id):

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -1824,6 +1824,13 @@ label.log-length {
padding: 25px;
padding-left: 50px;
background: #efefef;
div.nodata {
font-size: 150%;
font-weight: bold;
text-align: center;
padding-top: 200px;
display: none;
}
}
div.networks {
height: 100%;
@ -1853,12 +1860,18 @@ div.network {
background-image: linear-gradient(rgba(0, 0, 0, 0.15), rgba(0, 0, 0, 0.15));
background-size: 10px 10px;
}
&.nourl {
cursor: auto;
&:hover {
background-image:none;
}
}
h3 {
font-size: 12px;
line-height: 1;
position: relative;
font-weight: normal;
top:60%;
top:55%;
color:#fff;
left:-1px;
letter-spacing: 0.2em;
@ -1867,71 +1880,83 @@ div.network {
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
white-space: nowrap;
text-shadow: 0px 0px 5px #000;
span.ip {
margin-left: 0.5em;
color: #000;
font-weight: normal;
font-size: 90%;
text-shadow: 0px 0px 0px #000;
}
}
span.ip {
position: absolute;
bottom:-10px;
left:20px;
color: #000;
display: block;
font-weight: normal;
font-size: 90%;
letter-spacing: 0.2em;
-webkit-transform: rotate(-90deg);
-moz-transform: rotate(-90deg);
-ms-transform: rotate(-90deg);
-o-transform: rotate(-90deg);
transform: rotate(-90deg);
-webkit-transform-origin: 0% 0%;
-moz-transform-origin: 0% 0%;
-ms-transform-origin: 0% 0%;
-o-transform-origin: 0% 0%;
transform-origin: 0% 0%;
white-space: nowrap;
text-shadow: 0px 0px 2px #fff,0px 0px 2px #fff;
}
}
.router, .server, .device {
.box-sizing();
cursor: pointer;
width: 90px;
border: 3px solid #666;
border: 3px solid #444;
position: absolute;
top:30px;
left:90px;
color:#fff;
padding: 0 3px;
background: #666;
margin-bottom: 20px;
&:before,&:after {
border-radius: 8px;
&:before {
content: "";
width: 90px;
height: 34px;
text-align: center;
width: 20px;
height: 20px;
border: 2px solid #444;
line-height: 1.2;
position: absolute;
border: 3px solid #666;
.box-sizing();
background: #fff;
border-radius:50%;
top:-19px;
left:-3px;
border-radius: 20px;
top:-10px;
left:-10px;
background:#fff url(/static/dashboard/img/router.png) no-repeat center center;
background-size: 16px 16px;
}
&:after {
content:"";
content: "";
width: 100%;
line-height: 1.2;
position: absolute;
text-align: center;
border-radius: 0;
background: #444;
color: #fff;
background:#666;
border-radius:50%;
top:auto;
bottom:-19px;
font-size: 11px;
line-height: 30px;
height: 1.5em;
bottom:0px;
left: 0px;
}
span.devicename {
position: absolute;
color: #fff;
bottom: -10px;
bottom: 0px;
font-size: 12px;
line-height: 14px;
left:-4px;
width: 100%;
text-align: center;
z-index:300;
i {
display: inline-block;
width: 14px;
height:14px;
background: #fff url(/static/dashboard/img/router.png) no-repeat center center;
background-size: 12px 12px;
margin-right: 3px;
vertical-align: middle;
border-radius: 20px;
}
left:-2px;
}
span.name {
overflow: hidden;
@ -1942,7 +1967,7 @@ div.network {
position: relative;
z-index:10;
text-align: center;
top:-10px;
top:4px;
padding: 0 3px;
}
div.port {
@ -1962,6 +1987,7 @@ div.network {
z-index:100;
span.ip {
.box-sizing();
color: #333;
font-size: 9px;
line-height: 1;
text-shadow: 0px -1px #fff;
@ -2000,14 +2026,10 @@ div.network {
animation: progress-bar-stripes 0.3s linear infinite;
}
}
background-color: #444;
border-color: #444;
&:before {
border-color: #444;
}
border-color: #222;
&:after {
background-color: #444;
border-color: #444;
background-color: #222;
border-color: #222;
}
}
}
@ -2016,48 +2038,12 @@ div.network {
background: transparent;
}
.server {
border-radius: 5px;
background: #fff;
span.devicename {
bottom: 0px;
font-size: 12px;
line-height: 14px;
left:-4px;
i {
display: inline-block;
width: 14px;
height:14px;
background: url(/static/dashboard/img/server.png) no-repeat center center;
background-size: 12px 12px;
margin-right: 3px;
vertical-align: middle;
}
}
span.name {
top:5px;
padding: 0 3px;
}
&:before {
border:none;
background: transparent;
}
&:after {
content: "";
width: 100%;
line-height: 1.2;
position: absolute;
text-align: center;
border-radius: 0;
background: #666;
color: #fff;
font-size: 11px;
height: 1.5em;
bottom:0px;
left: 0px;
}
&:hover {
background: #fff;
background:#fff url(/static/dashboard/img/server.png) no-repeat center center;
background-size: 14px 14px;
}
background: #fff;
color:#333;
}
}