From 898dfd3ba5288222edc3a0f35bb0ea1fe9a8bafb Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 21 May 2012 16:07:11 +0200 Subject: [PATCH 01/11] Sunstone: specifying the target attribute in a VM template image is no longer mandatory --- src/sunstone/public/js/plugins/templates-tab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sunstone/public/js/plugins/templates-tab.js b/src/sunstone/public/js/plugins/templates-tab.js index dcf42eb96c..cc7d356361 100644 --- a/src/sunstone/public/js/plugins/templates-tab.js +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -208,7 +208,7 @@ var create_template_tmpl = '
\ \
'+tr("Type of disk device to emulate: ide, scsi")+'
\
\ -
\ +
\ \ \
'+tr("Device to map image disk. If set, it will overwrite the default device mapping")+'
\ From cb288f39c4aaf973acdbfc7366546eeef05bd43f Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 21 May 2012 16:16:59 +0200 Subject: [PATCH 02/11] Sunstone: fix image select generation for translated states --- src/sunstone/public/js/plugins/templates-tab.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sunstone/public/js/plugins/templates-tab.js b/src/sunstone/public/js/plugins/templates-tab.js index cc7d356361..b31a66accd 100644 --- a/src/sunstone/public/js/plugins/templates-tab.js +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -1999,7 +1999,7 @@ function popUpCreateTemplateDialog(){ 4, //id col - trick -> reference by name! 4, //name col [10,10,10], - ["DISABLED","LOCKED","ERROR"] + [tr("DISABLED"),tr("LOCKED"),tr("ERROR")] ); $('div#disks select#IMAGE',$create_template_dialog).html(im_sel); //Repopulate network select From c959a8f3e4f499ba1a7ed3e74a787006a058550d Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Mon, 21 May 2012 16:25:56 +0200 Subject: [PATCH 03/11] Sunstone: fix some strings --- src/sunstone/public/js/plugins/templates-tab.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/sunstone/public/js/plugins/templates-tab.js b/src/sunstone/public/js/plugins/templates-tab.js index b31a66accd..22171adb2f 100644 --- a/src/sunstone/public/js/plugins/templates-tab.js +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -336,7 +336,7 @@ var create_template_tmpl = '
\
'+tr("Hardware that will emulate this network interface. With Xen this is the type attribute of the vif.")+'
\
\
\ - \ + \ \
'+tr("Permits access to the VM only through the specified ports in the TCP protocol")+'
\
\
\ - \ + \ \
'+tr("Disallow access to the VM through the specified ports in the TCP protocol")+'
\
\
\ - \ + \ \
'+tr("Permits access to the VM only through the specified ports in the UDP protocol")+'
\
\
\ - \ + \ \
'+tr("Disallow access to the VM through the specified ports in the UDP protocol")+'
\
\
\ - \ + \ \ \ \ - \ + \ \ \
\ @@ -398,6 +401,14 @@ var vnet_actions = { notify:true, }, + "Network.help" : { + type: "custom", + call: function() { + hideDialog(); + $('div#vnets_tab div.legend_div').slideToggle(); + } + }, + }; @@ -444,6 +455,12 @@ var vnet_buttons = { "Network.delete" : { type: "confirm", text: tr("Delete") + }, + + "Network.help" : { + type: "action", + text: '?', + alwaysActive: true } } @@ -760,7 +777,7 @@ function setupCreateVNetDialog() { $('select#vlan,label[for="vlan"]',$create_vn_dialog).show(); $('input#vlan_id,label[for="vlan_id"]',$create_vn_dialog).show(); break; - case "etables": + case "ebtables": $('input#bridge,label[for="bridge"]',$create_vn_dialog).show(); break; case "openvswitch": @@ -887,7 +904,7 @@ function setupCreateVNetDialog() { network_json['vlan_id']=vlan_id; }; break; - case "etables": + case "ebtables": if (!bridge){ notifyError("Bridge must be specified"); return false; @@ -1197,4 +1214,6 @@ $(document).ready(function(){ $('div#menu li#li_vnets_tab').live('click',function(){ dataTable_vNetworks.fnFilter('',5); }); + + $('div#vnets_tab div.legend_div').hide(); }); From 6aef096bf90a87994015e775d2a67819ba1126da Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Fri, 1 Jun 2012 09:25:21 +0200 Subject: [PATCH 07/11] Feature #872: Add clone operation to Sunstone templates --- .../models/OpenNebulaJSON/TemplateJSON.rb | 5 ++ src/sunstone/public/js/opennebula.js | 6 +- .../public/js/plugins/templates-tab.js | 89 ++++++++++++++++++- src/sunstone/public/js/sunstone-util.js | 7 ++ 4 files changed, 104 insertions(+), 3 deletions(-) diff --git a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb index 006641a1fc..ce5e1c0f68 100644 --- a/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb +++ b/src/sunstone/models/OpenNebulaJSON/TemplateJSON.rb @@ -48,6 +48,7 @@ module OpenNebulaJSON when "chown" then self.chown(action_hash['params']) when "chmod" then self.chmod_octet(action_hash['params']) when "instantiate" then self.instantiate(action_hash['params']) + when "clone" then self.clone(action_hash['params']) else error_msg = "#{action_hash['perform']} action not " << " available for this resource" @@ -71,5 +72,9 @@ module OpenNebulaJSON super(params['vm_name']) end + def clone(params=Hash.new) + super(params['name']) + end + end end diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index ae4ec5b5ff..2e4cd6a96b 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -849,12 +849,16 @@ var OpenNebula = { "unpublish" : function(params){ OpenNebula.Action.simple_action(params,OpenNebula.Template.resource,"unpublish"); }, - "instantiate" : function(params) { var vm_name = params.data.extra_param ? params.data.extra_param : ""; var action_obj = { "vm_name" : vm_name }; OpenNebula.Action.simple_action(params,OpenNebula.Template.resource, "instantiate",action_obj); + }, + "clone" : function(params) { + var name = params.data.extra_param ? params.data.extra_param : ""; + var action_obj = { "name" : name }; + OpenNebula.Action.simple_action(params,OpenNebula.Template.resource, "clone", action_obj); } }, diff --git a/src/sunstone/public/js/plugins/templates-tab.js b/src/sunstone/public/js/plugins/templates-tab.js index 7b7dda5855..88543322a1 100644 --- a/src/sunstone/public/js/plugins/templates-tab.js +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -781,7 +781,16 @@ var template_actions = { error: onError, notify: true }, - + "Template.clone_dialog" : { + type: "custom", + call: popUpTemplateCloneDialog + }, + "Template.clone" : { + type: "single", + call: OpenNebula.Template.clone, + error: onError, + notify: true + }, "Template.help" : { type: "custom", call: function() { @@ -824,7 +833,10 @@ var template_buttons = { tip: tr("Select the new group")+":", condition: mustBeAdmin }, - + "Template.clone_dialog" : { + type: "action", + text: tr("Clone"), + }, "Template.delete" : { type: "confirm", text: tr("Delete") @@ -2137,6 +2149,78 @@ function popUpTemplateTemplateUpdateDialog(){ }; +function setupTemplateCloneDialog(){ + //Append to DOM + dialogs_context.append('
'); + var dialog = $('#template_clone_dialog',dialogs_context); + + //Put HTML in place + + var html = '
\ +
'+tr("Choose a new name for the template")+':
\ +
'+tr("Several templates are selected, please choose prefix to name the new copies")+':
\ +
\ +\ +\ +\ +
\ + \ +
\ +'; + + dialog.html(html); + + //Convert into jQuery + dialog.dialog({ + autoOpen:false, + width:375, + modal:true, + resizable:false, + }); + + $('button',dialog).button(); + + $('form',dialog).submit(function(){ + var name = $('input', this).val(); + var sel_elems = templateElements(); + if (!name || !sel_elems.length) + notifyError('A name or prefix is needed!'); + if (sel_elems.length > 1){ + for (var i=0; i< sel_elems.length; i++) + Sunstone.runAction('Template.clone', + sel_elems[i], + name+getTemplateName(sel_elems[i])); + } else { + Sunstone.runAction('Template.clone',sel_elems[0],name) + }; + $(this).parents('#template_clone_dialog').dialog('close'); + setTimeout(function(){ + Sunstone.runAction('Template.refresh'); + }, 1500); + return false; + }); +} + +function popUpTemplateCloneDialog(){ + var dialog = $('#template_clone_dialog'); + var sel_elems = templateElements(); + //show different text depending on how many elements are selected + if (sel_elems.length > 1){ + $('.clone_one',dialog).hide(); + $('.clone_several',dialog).show(); + $('input',dialog).val('Copy of '); + } + else { + $('.clone_one',dialog).show(); + $('.clone_several',dialog).hide(); + $('input',dialog).val('Copy of '+getTemplateName(sel_elems[0])); + }; + + $(dialog).dialog('open'); +} + // Set the autorefresh interval for the datatable function setTemplateAutorefresh() { setInterval(function(){ @@ -2182,6 +2266,7 @@ $(document).ready(function(){ setupCreateTemplateDialog(); setupTemplateTemplateUpdateDialog(); + setupTemplateCloneDialog(); setTemplateAutorefresh(); initCheckAllBoxes(dataTable_templates); diff --git a/src/sunstone/public/js/sunstone-util.js b/src/sunstone/public/js/sunstone-util.js index 16484f15ae..f887985a43 100644 --- a/src/sunstone/public/js/sunstone-util.js +++ b/src/sunstone/public/js/sunstone-util.js @@ -464,6 +464,13 @@ function getHostName(id){ return id; }; +function getTemplateName(id){ + if (typeof(dataTable_templates) != "undefined"){ + return getName(id,dataTable_templates,4); + } + return id; +}; + function getName(id,dataTable,name_col){ var name = id; if (typeof(dataTable) == "undefined") { From 0fa08a5eefe9b7118bb86e8c1226e33b8ecf866a Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Fri, 1 Jun 2012 10:03:11 +0200 Subject: [PATCH 08/11] UIs: small improvements in UIs. Added cross browser CSS rules for gradients. Our UIs should work with Opera now. Fixed small alignment issue in images tab. Added 1.5sec timeout to request list of VMs after deploying several ones, instead of requesting right after. --- src/cloud/occi/lib/ui/public/css/layout.css | 54 ++++++------------- src/ozones/Server/public/css/layout.css | 54 ++++++------------- src/sunstone/public/css/layout.css | 55 ++++++-------------- src/sunstone/public/js/plugins/images-tab.js | 2 +- src/sunstone/public/js/plugins/vms-tab.js | 4 +- 5 files changed, 53 insertions(+), 116 deletions(-) diff --git a/src/cloud/occi/lib/ui/public/css/layout.css b/src/cloud/occi/lib/ui/public/css/layout.css index 624e1e39a3..10831a2aaa 100644 --- a/src/cloud/occi/lib/ui/public/css/layout.css +++ b/src/cloud/occi/lib/ui/public/css/layout.css @@ -107,18 +107,14 @@ body { padding-left: 0; border:0; border-right: 1px solid #353735; - background-image: -webkit-gradient( - linear, - left top, - right top, - color-stop(0.95, rgb(99,102,99)), - color-stop(1, rgb(53,55,53)) -); -background-image: -moz-linear-gradient( - left center, - rgb(99,102,99) 95%, - rgb(53,55,53) 100% -); + background: #636663; /* Old browsers */ + background: -moz-linear-gradient(left, #636663 95%, #353735 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, right top, color-stop(95%,#636663), color-stop(100%,#353735)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(left, #636663 95%,#353735 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(left, #636663 95%,#353735 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(left, #636663 95%,#353735 100%); /* IE10+ */ + background: linear-gradient(left, #636663 95%,#353735 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#636663', endColorstr='#353735',GradientType=1 ); /* IE6-9 */ } #navigation { list-style: none; @@ -166,32 +162,14 @@ background-image: -moz-linear-gradient( } #navigation li:hover, .navigation-active-li { - background-image: -webkit-gradient( - linear, - left top, - right top, - color-stop(0.95, #0098C3), - color-stop(1, rgb(53,55,53)) -); -background-image: -moz-linear-gradient( - left center, - #0098C3 95%, - rgb(53,55,53) 100% -); - /* - background-image: -webkit-gradient( - linear, - right top, - left top, - color-stop(0, rgb(0,152,192)), - color-stop(1, rgb(255,255,255)) - ); - background-image: -moz-linear-gradient( - right center, - rgb(0,152,192) 0%, - rgb(255,255,255) 100% - ); - */ + background: #0098c3; /* Old browsers */ + background: -moz-linear-gradient(left, #0098c3 95%, #353735 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, right top, color-stop(95%,#0098c3), color-stop(100%,#353735)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(left, #0098c3 95%,#353735 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(left, #0098c3 95%,#353735 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(left, #0098c3 95%,#353735 100%); /* IE10+ */ + background: linear-gradient(left, #0098c3 95%,#353735 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#0098c3', endColorstr='#353735',GradientType=1 ); /* IE6-9 */ } .navigation-active-li { font-weight: bold; diff --git a/src/ozones/Server/public/css/layout.css b/src/ozones/Server/public/css/layout.css index 5a3762eb53..e5389a3768 100644 --- a/src/ozones/Server/public/css/layout.css +++ b/src/ozones/Server/public/css/layout.css @@ -105,18 +105,14 @@ body { padding-left: 0; border:0; border-right: 1px solid #353735; - background-image: -webkit-gradient( - linear, - left top, - right top, - color-stop(0.95, rgb(99,102,99)), - color-stop(1, rgb(53,55,53)) -); -background-image: -moz-linear-gradient( - left center, - rgb(99,102,99) 95%, - rgb(53,55,53) 100% -); + background: #636663; /* Old browsers */ + background: -moz-linear-gradient(left, #636663 95%, #353735 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, right top, color-stop(95%,#636663), color-stop(100%,#353735)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(left, #636663 95%,#353735 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(left, #636663 95%,#353735 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(left, #636663 95%,#353735 100%); /* IE10+ */ + background: linear-gradient(left, #636663 95%,#353735 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#636663', endColorstr='#353735',GradientType=1 ); /* IE6-9 */ } .navigation { list-style: none; @@ -164,32 +160,14 @@ background-image: -moz-linear-gradient( } .navigation li:hover, .navigation-active-li { - background-image: -webkit-gradient( - linear, - left top, - right top, - color-stop(0.95, #88C140), - color-stop(1, rgb(53,55,53)) -); -background-image: -moz-linear-gradient( - left center, - #88C140 95%, - rgb(53,55,53) 100% -); - /* - background-image: -webkit-gradient( - linear, - right top, - left top, - color-stop(0, rgb(0,152,192)), - color-stop(1, rgb(255,255,255)) - ); - background-image: -moz-linear-gradient( - right center, - rgb(0,152,192) 0%, - rgb(255,255,255) 100% - ); - */ + background: #88c140; /* Old browsers */ + background: -moz-linear-gradient(left, #88c140 95%, #353735 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, right top, color-stop(95%,#88c140), color-stop(100%,#353735)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(left, #88c140 95%,#353735 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(left, #88c140 95%,#353735 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(left, #88c140 95%,#353735 100%); /* IE10+ */ + background: linear-gradient(left, #88c140 95%,#353735 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#88c140', endColorstr='#353735',GradientType=1 ); /* IE6-9 */ } .navigation-active-li { font-weight: bold; diff --git a/src/sunstone/public/css/layout.css b/src/sunstone/public/css/layout.css index 4c28a08978..973b22b522 100644 --- a/src/sunstone/public/css/layout.css +++ b/src/sunstone/public/css/layout.css @@ -111,18 +111,15 @@ body { padding-left: 0; border:0; border-right: 1px solid #353735; - background-image: -webkit-gradient( - linear, - left top, - right top, - color-stop(0.95, rgb(99,102,99)), - color-stop(1, rgb(53,55,53)) -); -background-image: -moz-linear-gradient( - left center, - rgb(99,102,99) 95%, - rgb(53,55,53) 100% -); + + background: #636663; /* Old browsers */ + background: -moz-linear-gradient(left, #636663 95%, #353735 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, right top, color-stop(95%,#636663), color-stop(100%,#353735)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(left, #636663 95%,#353735 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(left, #636663 95%,#353735 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(left, #636663 95%,#353735 100%); /* IE10+ */ + background: linear-gradient(left, #636663 95%,#353735 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#636663', endColorstr='#353735',GradientType=1 ); /* IE6-9 */ } .navigation { @@ -171,32 +168,14 @@ background-image: -moz-linear-gradient( } #navigation li:hover, .navigation-active-li { - background-image: -webkit-gradient( - linear, - left top, - right top, - color-stop(0.95, #E69138), - color-stop(1, rgb(53,55,53)) -); -background-image: -moz-linear-gradient( - left center, - #E69138 95%, - rgb(53,55,53) 100% -); - /* - background-image: -webkit-gradient( - linear, - right top, - left top, - color-stop(0, rgb(0,152,192)), - color-stop(1, rgb(255,255,255)) - ); - background-image: -moz-linear-gradient( - right center, - rgb(0,152,192) 0%, - rgb(255,255,255) 100% - ); - */ + background: #e69138; /* Old browsers */ + background: -moz-linear-gradient(left, #e69138 95%, #353735 100%); /* FF3.6+ */ + background: -webkit-gradient(linear, left top, right top, color-stop(95%,#e69138), color-stop(100%,#353735)); /* Chrome,Safari4+ */ + background: -webkit-linear-gradient(left, #e69138 95%,#353735 100%); /* Chrome10+,Safari5.1+ */ + background: -o-linear-gradient(left, #e69138 95%,#353735 100%); /* Opera 11.10+ */ + background: -ms-linear-gradient(left, #e69138 95%,#353735 100%); /* IE10+ */ + background: linear-gradient(left, #e69138 95%,#353735 100%); /* W3C */ + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e69138', endColorstr='#353735',GradientType=1 ); /* IE6-9 */ } .navigation-active-li { font-weight: bold; diff --git a/src/sunstone/public/js/plugins/images-tab.js b/src/sunstone/public/js/plugins/images-tab.js index cae52bc73c..43a2660033 100644 --- a/src/sunstone/public/js/plugins/images-tab.js +++ b/src/sunstone/public/js/plugins/images-tab.js @@ -120,7 +120,7 @@ var create_image_tmpl = \
\
\ - \ + \ \ \
\ diff --git a/src/sunstone/public/js/plugins/vms-tab.js b/src/sunstone/public/js/plugins/vms-tab.js index 5173b5d4d1..fef0aaf422 100644 --- a/src/sunstone/public/js/plugins/vms-tab.js +++ b/src/sunstone/public/js/plugins/vms-tab.js @@ -1000,7 +1000,9 @@ function setupCreateVMDialog(){ }; }; - Sunstone.runAction("VM.list"); + setTimeout(function(){ + Sunstone.runAction("VM.list"); + },1500); $create_vm_dialog.dialog('close'); return false; }); From ee9750a9eb3965dbbf54830e014464c4e4b4ca20 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Sat, 2 Jun 2012 23:28:27 +0200 Subject: [PATCH 09/11] UIs: Add some FontAwesome icons to menu main items. Added FontAwesome as vendor library. Modified Self-Service, Sunstone and Ozones to use them in the menus. --- install.sh | 45 +++- src/cloud/occi/lib/ui/public/css/layout.css | 7 +- .../occi/lib/ui/public/js/plugins/compute.js | 2 +- .../lib/ui/public/js/plugins/configuration.js | 2 +- .../lib/ui/public/js/plugins/dashboard.js | 2 +- .../occi/lib/ui/public/js/plugins/network.js | 2 +- .../occi/lib/ui/public/js/plugins/storage.js | 2 +- src/cloud/occi/lib/ui/views/index.erb | 3 +- src/ozones/Server/public/css/layout.css | 4 + .../Server/public/js/plugins/dashboard-tab.js | 2 +- .../Server/public/js/plugins/vdcs-tab.js | 2 +- .../Server/public/js/plugins/zones-tab.js | 2 +- src/ozones/Server/templates/index.html | 1 + src/sunstone/public/css/layout.css | 4 + .../public/js/plugins/dashboard-tab.js | 2 +- src/sunstone/public/js/plugins/infra-tab.js | 2 +- src/sunstone/public/js/plugins/system-tab.js | 2 +- .../public/js/plugins/vresources-tab.js | 2 +- src/sunstone/public/vendor/FontAwesome/NOTICE | 5 + .../vendor/FontAwesome/css/font-awesome.css | 239 ++++++++++++++++++ .../FontAwesome/font/fontawesome-webfont.eot | Bin 0 -> 42272 bytes .../FontAwesome/font/fontawesome-webfont.svg | 175 +++++++++++++ .../FontAwesome/font/fontawesome-webfont.svgz | Bin 0 -> 21845 bytes .../FontAwesome/font/fontawesome-webfont.ttf | Bin 0 -> 41916 bytes .../FontAwesome/font/fontawesome-webfont.woff | Bin 0 -> 23416 bytes src/sunstone/views/index.erb | 2 +- 26 files changed, 493 insertions(+), 16 deletions(-) create mode 100644 src/sunstone/public/vendor/FontAwesome/NOTICE create mode 100644 src/sunstone/public/vendor/FontAwesome/css/font-awesome.css create mode 100755 src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.eot create mode 100755 src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svg create mode 100755 src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svgz create mode 100755 src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.ttf create mode 100755 src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.woff diff --git a/install.sh b/install.sh index 8d37222cff..1fd3bfb24b 100755 --- a/install.sh +++ b/install.sh @@ -270,6 +270,9 @@ SUNSTONE_DIRS="$SUNSTONE_LOCATION/models \ $SUNSTONE_LOCATION/public/vendor/jGrowl \ $SUNSTONE_LOCATION/public/vendor/flot \ $SUNSTONE_LOCATION/public/vendor/fileuploader \ + $SUNSTONE_LOCATION/public/vendor/FontAwesome \ + $SUNSTONE_LOCATION/public/vendor/FontAwesome/css \ + $SUNSTONE_LOCATION/public/vendor/FontAwesome/font \ $SUNSTONE_LOCATION/public/images \ $SUNSTONE_LOCATION/templates \ $SUNSTONE_LOCATION/views" @@ -286,6 +289,9 @@ OZONES_DIRS="$OZONES_LOCATION/lib \ $OZONES_LOCATION/public/vendor/jQueryUI \ $OZONES_LOCATION/public/vendor/jQueryUI/images \ $OZONES_LOCATION/public/vendor/jGrowl \ + $OZONES_LOCATION/public/vendor/FontAwesome \ + $OZONES_LOCATION/public/vendor/FontAwesome/css \ + $OZONES_LOCATION/public/vendor/FontAwesome/font \ $OZONES_LOCATION/public/js \ $OZONES_LOCATION/public/js/plugins \ $OZONES_LOCATION/public/images \ @@ -316,7 +322,10 @@ SELF_SERVICE_DIRS="\ $LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/flot \ $LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/crypto-js \ $LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/fileuploader \ - $LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/xml2json" + $LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/xml2json \ + $LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/FontAwesome \ + $LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/FontAwesome/css \ + $LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/FontAwesome/font" OZONES_CLIENT_DIRS="$LIB_LOCATION/ruby \ $LIB_LOCATION/ruby/OpenNebula \ @@ -468,6 +477,9 @@ INSTALL_SUNSTONE_FILES=( SUNSTONE_PUBLIC_VENDOR_JQUERYLAYOUT:$SUNSTONE_LOCATION/public/vendor/jQueryLayout SUNSTONE_PUBLIC_VENDOR_FLOT:$SUNSTONE_LOCATION/public/vendor/flot SUNSTONE_PUBLIC_VENDOR_FILEUPLOADER:$SUNSTONE_LOCATION/public/vendor/fileuploader + SUNSTONE_PUBLIC_VENDOR_FONTAWESOME:$SUNSTONE_LOCATION/public/vendor/FontAwesome + SUNSTONE_PUBLIC_VENDOR_FONTAWESOME_FONT:$SUNSTONE_LOCATION/public/vendor/FontAwesome/font + SUNSTONE_PUBLIC_VENDOR_FONTAWESOME_CSS:$SUNSTONE_LOCATION/public/vendor/FontAwesome/css SUNSTONE_PUBLIC_IMAGES_FILES:$SUNSTONE_LOCATION/public/images SUNSTONE_PUBLIC_LOCALE_EN_US:$SUNSTONE_LOCATION/public/locale/en_US SUNSTONE_PUBLIC_LOCALE_RU:$SUNSTONE_LOCATION/public/locale/ru @@ -498,6 +510,9 @@ INSTALL_OZONES_FILES=( OZONES_PUBLIC_VENDOR_JQUERYUI:$OZONES_LOCATION/public/vendor/jQueryUI OZONES_PUBLIC_VENDOR_JQUERYUIIMAGES:$OZONES_LOCATION/public/vendor/jQueryUI/images OZONES_PUBLIC_VENDOR_JQUERYLAYOUT:$OZONES_LOCATION/public/vendor/jQueryLayout + OZONES_PUBLIC_VENDOR_FONTAWESOME:$OZONES_LOCATION/public/vendor/FontAwesome + OZONES_PUBLIC_VENDOR_FONTAWESOME_FONT:$OZONES_LOCATION/public/vendor/FontAwesome/font + OZONES_PUBLIC_VENDOR_FONTAWESOME_CSS:$OZONES_LOCATION/public/vendor/FontAwesome/css OZONES_PUBLIC_JS_FILES:$OZONES_LOCATION/public/js OZONES_PUBLIC_IMAGES_FILES:$OZONES_LOCATION/public/images OZONES_PUBLIC_CSS_FILES:$OZONES_LOCATION/public/css @@ -530,6 +545,9 @@ INSTALL_SELF_SERVICE_FILES=( SELF_SERVICE_PUBLIC_VENDOR_CRYPTOJS:$LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/crypto-js SELF_SERVICE_PUBLIC_VENDOR_FILEUPLOADER:$LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/fileuploader SELF_SERVICE_PUBLIC_VENDOR_XML2JSON:$LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/xml2json + SELF_SERVICE_PUBLIC_VENDOR_FONTAWESOME:$LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/FontAwesome + SELF_SERVICE_PUBLIC_VENDOR_FONTAWESOME_CSS:$LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/FontAwesome/css + SELF_SERVICE_PUBLIC_VENDOR_FONTAWESOME_FONT:$LIB_LOCATION/ruby/cloud/occi/ui/public/vendor/FontAwesome/font SELF_SERVICE_PUBLIC_IMAGES_FILES:$LIB_LOCATION/ruby/cloud/occi/ui/public/images SELF_SERVICE_PUBLIC_LOCALE_EN_US:$LIB_LOCATION/ruby/cloud/occi/ui/public/locale/en_US SELF_SERVICE_PUBLIC_LOCALE_ES_ES:$LIB_LOCATION/ruby/cloud/occi/ui/public/locale/es_ES @@ -1266,6 +1284,22 @@ SUNSTONE_PUBLIC_VENDOR_XML2JSON="\ src/sunstone/public/vendor/xml2json/NOTICE \ src/sunstone/public/vendor/xml2json/jquery.xml2json.pack.js" +SUNSTONE_PUBLIC_VENDOR_FONTAWESOME="\ +src/sunstone/public/vendor/FontAwesome/NOTICE \ +" + +SUNSTONE_PUBLIC_VENDOR_FONTAWESOME_CSS="\ +src/sunstone/public/vendor/FontAwesome/css/font-awesome.css \ +" + +SUNSTONE_PUBLIC_VENDOR_FONTAWESOME_FONT="\ +src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.eot \ +src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.woff \ +src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.ttf \ +src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svgz \ +src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svg \ +" + SUNSTONE_PUBLIC_IMAGES_FILES="src/sunstone/public/images/ajax-loader.gif \ src/sunstone/public/images/login_over.png \ src/sunstone/public/images/login.png \ @@ -1361,6 +1395,12 @@ OZONES_PUBLIC_VENDOR_JQUERYUIIMAGES=$SUNSTONE_PUBLIC_VENDOR_JQUERYUIIMAGES OZONES_PUBLIC_VENDOR_JQUERYLAYOUT=$SUNSTONE_PUBLIC_VENDOR_JQUERYLAYOUT +OZONES_PUBLIC_VENDOR_FONTAWESOME=$SUNSTONE_PUBLIC_VENDOR_FONTAWESOME + +OZONES_PUBLIC_VENDOR_FONTAWESOME_FONT=$SUNSTONE_PUBLIC_VENDOR_FONTAWESOME_FONT + +OZONES_PUBLIC_VENDOR_FONTAWESOME_CSS=$SUNSTONE_PUBLIC_VENDOR_FONTAWESOME_CSS + OZONES_PUBLIC_JS_FILES="src/ozones/Server/public/js/ozones.js \ src/ozones/Server/public/js/login.js \ src/ozones/Server/public/js/ozones-util.js \ @@ -1435,6 +1475,9 @@ SELF_SERVICE_PUBLIC_VENDOR_FLOT=$SUNSTONE_PUBLIC_VENDOR_FLOT SELF_SERVICE_PUBLIC_VENDOR_CRYPTOJS=$SUNSTONE_PUBLIC_VENDOR_CRYPTOJS SELF_SERVICE_PUBLIC_VENDOR_FILEUPLOADER=$SUNSTONE_PUBLIC_VENDOR_FILEUPLOADER SELF_SERVICE_PUBLIC_VENDOR_XML2JSON=$SUNSTONE_PUBLIC_VENDOR_XML2JSON +SELF_SERVICE_PUBLIC_VENDOR_FONTAWESOME=$SUNSTONE_PUBLIC_VENDOR_FONTAWESOME +SELF_SERVICE_PUBLIC_VENDOR_FONTAWESOME_FONT=$SUNSTONE_PUBLIC_VENDOR_FONTAWESOME_FONT +SELF_SERVICE_PUBLIC_VENDOR_FONTAWESOME_CSS=$SUNSTONE_PUBLIC_VENDOR_FONTAWESOME_CSS SELF_SERVICE_PUBLIC_IMAGES_FILES="\ src/cloud/occi/lib/ui/public/images/ajax-loader.gif \ diff --git a/src/cloud/occi/lib/ui/public/css/layout.css b/src/cloud/occi/lib/ui/public/css/layout.css index 10831a2aaa..8859755b76 100644 --- a/src/cloud/occi/lib/ui/public/css/layout.css +++ b/src/cloud/occi/lib/ui/public/css/layout.css @@ -116,11 +116,16 @@ body { background: linear-gradient(left, #636663 95%,#353735 100%); /* W3C */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#636663', endColorstr='#353735',GradientType=1 ); /* IE6-9 */ } -#navigation { + +.navigation { list-style: none; padding: 0; } +.navigation i { + margin-right: 5px; +} + .navigation li.topTab { line-height: 2em; text-align: left; diff --git a/src/cloud/occi/lib/ui/public/js/plugins/compute.js b/src/cloud/occi/lib/ui/public/js/plugins/compute.js index 59a46d4ad9..c9d123334b 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/compute.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/compute.js @@ -406,7 +406,7 @@ var vm_create_panel = { }; var vms_tab = { - title: tr("Compute"), + title: ''+tr("Compute"), content: vms_tab_content, buttons: vm_buttons } diff --git a/src/cloud/occi/lib/ui/public/js/plugins/configuration.js b/src/cloud/occi/lib/ui/public/js/plugins/configuration.js index ac6d4e0200..1ac9aae7b8 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/configuration.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/configuration.js @@ -53,7 +53,7 @@ var config_actions = { }; var config_tab = { - title: tr("Configuration"), + title: ''+tr("Configuration"), content: config_tab_content } diff --git a/src/cloud/occi/lib/ui/public/js/plugins/dashboard.js b/src/cloud/occi/lib/ui/public/js/plugins/dashboard.js index 960f93d49c..d5c090134e 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/dashboard.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/dashboard.js @@ -117,7 +117,7 @@ var dashboard_tab_content = '; var dashboard_tab = { - title: tr("Dashboard"), + title: ''+tr("Dashboard"), content: dashboard_tab_content } diff --git a/src/cloud/occi/lib/ui/public/js/plugins/network.js b/src/cloud/occi/lib/ui/public/js/plugins/network.js index a19f9046bc..5b409b09d7 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/network.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/network.js @@ -196,7 +196,7 @@ var vnet_create_panel = { } var vnets_tab = { - title: tr("Networks"), + title: ''+tr("Networks"), content: vnets_tab_content, buttons: vnet_buttons } diff --git a/src/cloud/occi/lib/ui/public/js/plugins/storage.js b/src/cloud/occi/lib/ui/public/js/plugins/storage.js index c42a3ab7dc..2fb749a85f 100644 --- a/src/cloud/occi/lib/ui/public/js/plugins/storage.js +++ b/src/cloud/occi/lib/ui/public/js/plugins/storage.js @@ -261,7 +261,7 @@ var image_create_panel = { }; var images_tab = { - title: tr("Storage"), + title: ''+tr("Storage"), content: images_tab_content, buttons: image_buttons } diff --git a/src/cloud/occi/lib/ui/views/index.erb b/src/cloud/occi/lib/ui/views/index.erb index 86dd776731..294d996071 100644 --- a/src/cloud/occi/lib/ui/views/index.erb +++ b/src/cloud/occi/lib/ui/views/index.erb @@ -2,13 +2,14 @@ OpenNebula Self-Service - + + diff --git a/src/ozones/Server/public/css/layout.css b/src/ozones/Server/public/css/layout.css index e5389a3768..17d3708045 100644 --- a/src/ozones/Server/public/css/layout.css +++ b/src/ozones/Server/public/css/layout.css @@ -119,6 +119,10 @@ body { padding: 0; } +.navigation i { + margin-right: 5px; +} + .navigation li.topTab { line-height: 2em; text-align: left; diff --git a/src/ozones/Server/public/js/plugins/dashboard-tab.js b/src/ozones/Server/public/js/plugins/dashboard-tab.js index 012e690d91..ef5f4b5d73 100644 --- a/src/ozones/Server/public/js/plugins/dashboard-tab.js +++ b/src/ozones/Server/public/js/plugins/dashboard-tab.js @@ -192,7 +192,7 @@ var dashboard_tab_content = var dashboard_tab = { - title: 'Dashboard', + title: ''+'Dashboard', content: dashboard_tab_content } diff --git a/src/ozones/Server/public/js/plugins/vdcs-tab.js b/src/ozones/Server/public/js/plugins/vdcs-tab.js index 773417ab31..e4c5ea9780 100644 --- a/src/ozones/Server/public/js/plugins/vdcs-tab.js +++ b/src/ozones/Server/public/js/plugins/vdcs-tab.js @@ -276,7 +276,7 @@ var vdc_buttons = { }; var vdcs_tab = { - title: "VDCs", + title: ''+"VDCs", content: vdcs_tab_content, buttons: vdc_buttons } diff --git a/src/ozones/Server/public/js/plugins/zones-tab.js b/src/ozones/Server/public/js/plugins/zones-tab.js index 8402f2f5d4..c6011247f5 100644 --- a/src/ozones/Server/public/js/plugins/zones-tab.js +++ b/src/ozones/Server/public/js/plugins/zones-tab.js @@ -215,7 +215,7 @@ var zone_buttons = { }; var zones_tab = { - title: "Zones", + title: ''+"Zones", content: zones_tab_content, buttons: zone_buttons } diff --git a/src/ozones/Server/templates/index.html b/src/ozones/Server/templates/index.html index cf434eab15..3a5e018a1a 100644 --- a/src/ozones/Server/templates/index.html +++ b/src/ozones/Server/templates/index.html @@ -9,6 +9,7 @@ + diff --git a/src/sunstone/public/css/layout.css b/src/sunstone/public/css/layout.css index 973b22b522..fca154e949 100644 --- a/src/sunstone/public/css/layout.css +++ b/src/sunstone/public/css/layout.css @@ -127,6 +127,10 @@ body { padding: 0; } +.navigation i { + margin-right: 5px; +} + .navigation li.topTab { line-height: 2em; text-align: left; diff --git a/src/sunstone/public/js/plugins/dashboard-tab.js b/src/sunstone/public/js/plugins/dashboard-tab.js index 33db3ed62c..2cf395e157 100644 --- a/src/sunstone/public/js/plugins/dashboard-tab.js +++ b/src/sunstone/public/js/plugins/dashboard-tab.js @@ -159,7 +159,7 @@ var dashboard_tab_content = '; var dashboard_tab = { - title: tr("Dashboard"), + title: ''+tr("Dashboard"), content: dashboard_tab_content, showOnTopMenu: false, } diff --git a/src/sunstone/public/js/plugins/infra-tab.js b/src/sunstone/public/js/plugins/infra-tab.js index 5f4eddadbe..768e9a308c 100644 --- a/src/sunstone/public/js/plugins/infra-tab.js +++ b/src/sunstone/public/js/plugins/infra-tab.js @@ -89,7 +89,7 @@ var infra_tab_content = '; var infra_tab = { - title: tr("Infrastructure"), + title: ''+tr("Infrastructure"), content: infra_tab_content } diff --git a/src/sunstone/public/js/plugins/system-tab.js b/src/sunstone/public/js/plugins/system-tab.js index 7a4636db06..6e93b1278f 100644 --- a/src/sunstone/public/js/plugins/system-tab.js +++ b/src/sunstone/public/js/plugins/system-tab.js @@ -84,7 +84,7 @@ var system_tab_content = '; var system_tab = { - title: tr("System"), + title: ''+tr("System"), content: system_tab_content } diff --git a/src/sunstone/public/js/plugins/vresources-tab.js b/src/sunstone/public/js/plugins/vresources-tab.js index 6e3436d551..5b38ce2fe3 100644 --- a/src/sunstone/public/js/plugins/vresources-tab.js +++ b/src/sunstone/public/js/plugins/vresources-tab.js @@ -93,7 +93,7 @@ var vres_tab_content = '; var vres_tab = { - title: tr("Virtual Resources"), + title: ''+tr("Virtual Resources"), content: vres_tab_content } diff --git a/src/sunstone/public/vendor/FontAwesome/NOTICE b/src/sunstone/public/vendor/FontAwesome/NOTICE new file mode 100644 index 0000000000..9e757895cd --- /dev/null +++ b/src/sunstone/public/vendor/FontAwesome/NOTICE @@ -0,0 +1,5 @@ +THIRD-PARTY SOFTWARE + + * Author: Dave Gandy (dave@davegandy.com) + * Info: http://fortawesome.github.com/Font-Awesome/ + * License: Creative Commons-BY 3.0. See http://creativecommons.org/licenses/by/3.0/ diff --git a/src/sunstone/public/vendor/FontAwesome/css/font-awesome.css b/src/sunstone/public/vendor/FontAwesome/css/font-awesome.css new file mode 100644 index 0000000000..2e868934e4 --- /dev/null +++ b/src/sunstone/public/vendor/FontAwesome/css/font-awesome.css @@ -0,0 +1,239 @@ +/* Font Awesome + the iconic font designed for use with Twitter Bootstrap + ------------------------------------------------------- + The full suite of pictographic icons, examples, and documentation + can be found at: http://fortawesome.github.com/Font-Awesome/ + + License + ------------------------------------------------------- + The Font Awesome webfont, CSS, and LESS files are licensed under CC BY 3.0: + http://creativecommons.org/licenses/by/3.0/ A mention of + 'Font Awesome - http://fortawesome.github.com/Font-Awesome' in human-readable + source code is considered acceptable attribution (most common on the web). + If human readable source code is not available to the end user, a mention in + an 'About' or 'Credits' screen is considered acceptable (most common in desktop + or mobile software). + + Contact + ------------------------------------------------------- + Email: dave@davegandy.com + Twitter: http://twitter.com/fortaweso_me + Work: http://lemonwi.se co-founder + + */ + +@font-face { + font-family: 'FontAwesome'; + src: url('../font/fontawesome-webfont.eot'); + src: url('../font/fontawesome-webfont.eot?#iefix') format('embedded-opentype'), url('../font/fontawesome-webfont.woff') format('woff'), url('../font/fontawesome-webfont.ttf') format('truetype'), url('../font/fontawesome-webfont.svgz#FontAwesomeRegular') format('svg'), url('../font/fontawesome-webfont.svg#FontAwesomeRegular') format('svg'); + font-weight: normal; + font-style: normal; +} +/* sprites.less reset */ +[class^="icon-"], [class*=" icon-"] { + display: inline; + width: auto; + height: auto; + line-height: inherit; + vertical-align: baseline; + background-image: none; + background-position: 0% 0%; + background-repeat: repeat; +} +li[class^="icon-"], li[class*=" icon-"] { + display: block; +} +/* Font Awesome styles + ------------------------------------------------------- */ +[class^="icon-"]:before, [class*=" icon-"]:before { + font-family: FontAwesome; + font-weight: normal; + font-style: normal; + display: inline-block; + text-decoration: inherit; +} +a [class^="icon-"], a [class*=" icon-"] { + display: inline-block; + text-decoration: inherit; +} +/* makes the font 33% larger relative to the icon container */ +.icon-large:before { + vertical-align: top; + font-size: 1.3333333333333333em; +} +.btn [class^="icon-"], .btn [class*=" icon-"] { + /* keeps button heights with and without icons the same */ + line-height: .9em; +} +li [class^="icon-"], li [class*=" icon-"] { + display: inline-block; + width: 1.25em; + text-align: center; +} +li .icon-large[class^="icon-"], li .icon-large[class*=" icon-"] { + /* 1.5 increased font size for icon-large * 1.25 width */ + width: 1.875em; +} +li[class^="icon-"], li[class*=" icon-"] { + margin-left: 0; + list-style-type: none; +} +li[class^="icon-"]:before, li[class*=" icon-"]:before { + text-indent: -2em; + text-align: center; +} +li[class^="icon-"].icon-large:before, li[class*=" icon-"].icon-large:before { + text-indent: -1.3333333333333333em; +} +/* Font Awesome uses the Unicode Private Use Area (PUA) to ensure screen + readers do not read off random characters that represent icons */ +.icon-glass:before { content: "\f000"; } +.icon-music:before { content: "\f001"; } +.icon-search:before { content: "\f002"; } +.icon-envelope:before { content: "\f003"; } +.icon-heart:before { content: "\f004"; } +.icon-star:before { content: "\f005"; } +.icon-star-empty:before { content: "\f006"; } +.icon-user:before { content: "\f007"; } +.icon-film:before { content: "\f008"; } +.icon-th-large:before { content: "\f009"; } +.icon-th:before { content: "\f00a"; } +.icon-th-list:before { content: "\f00b"; } +.icon-ok:before { content: "\f00c"; } +.icon-remove:before { content: "\f00d"; } +.icon-zoom-in:before { content: "\f00e"; } + +.icon-zoom-out:before { content: "\f010"; } +.icon-off:before { content: "\f011"; } +.icon-signal:before { content: "\f012"; } +.icon-cog:before { content: "\f013"; } +.icon-trash:before { content: "\f014"; } +.icon-home:before { content: "\f015"; } +.icon-file:before { content: "\f016"; } +.icon-time:before { content: "\f017"; } +.icon-road:before { content: "\f018"; } +.icon-download-alt:before { content: "\f019"; } +.icon-download:before { content: "\f01a"; } +.icon-upload:before { content: "\f01b"; } +.icon-inbox:before { content: "\f01c"; } +.icon-play-circle:before { content: "\f01d"; } +.icon-repeat:before { content: "\f01e"; } + +/* \f020 is not a valid unicode character. all shifted one down */ +.icon-refresh:before { content: "\f021"; } +.icon-list-alt:before { content: "\f022"; } +.icon-lock:before { content: "\f023"; } +.icon-flag:before { content: "\f024"; } +.icon-headphones:before { content: "\f025"; } +.icon-volume-off:before { content: "\f026"; } +.icon-volume-down:before { content: "\f027"; } +.icon-volume-up:before { content: "\f028"; } +.icon-qrcode:before { content: "\f029"; } +.icon-barcode:before { content: "\f02a"; } +.icon-tag:before { content: "\f02b"; } +.icon-tags:before { content: "\f02c"; } +.icon-book:before { content: "\f02d"; } +.icon-bookmark:before { content: "\f02e"; } +.icon-print:before { content: "\f02f"; } + +.icon-camera:before { content: "\f030"; } +.icon-font:before { content: "\f031"; } +.icon-bold:before { content: "\f032"; } +.icon-italic:before { content: "\f033"; } +.icon-text-height:before { content: "\f034"; } +.icon-text-width:before { content: "\f035"; } +.icon-align-left:before { content: "\f036"; } +.icon-align-center:before { content: "\f037"; } +.icon-align-right:before { content: "\f038"; } +.icon-align-justify:before { content: "\f039"; } +.icon-list:before { content: "\f03a"; } +.icon-indent-left:before { content: "\f03b"; } +.icon-indent-right:before { content: "\f03c"; } +.icon-facetime-video:before { content: "\f03d"; } +.icon-picture:before { content: "\f03e"; } + +.icon-pencil:before { content: "\f040"; } +.icon-map-marker:before { content: "\f041"; } +.icon-adjust:before { content: "\f042"; } +.icon-tint:before { content: "\f043"; } +.icon-edit:before { content: "\f044"; } +.icon-share:before { content: "\f045"; } +.icon-check:before { content: "\f046"; } +.icon-move:before { content: "\f047"; } +.icon-step-backward:before { content: "\f048"; } +.icon-fast-backward:before { content: "\f049"; } +.icon-backward:before { content: "\f04a"; } +.icon-play:before { content: "\f04b"; } +.icon-pause:before { content: "\f04c"; } +.icon-stop:before { content: "\f04d"; } +.icon-forward:before { content: "\f04e"; } + +.icon-fast-forward:before { content: "\f050"; } +.icon-step-forward:before { content: "\f051"; } +.icon-eject:before { content: "\f052"; } +.icon-chevron-left:before { content: "\f053"; } +.icon-chevron-right:before { content: "\f054"; } +.icon-plus-sign:before { content: "\f055"; } +.icon-minus-sign:before { content: "\f056"; } +.icon-remove-sign:before { content: "\f057"; } +.icon-ok-sign:before { content: "\f058"; } +.icon-question-sign:before { content: "\f059"; } +.icon-info-sign:before { content: "\f05a"; } +.icon-screenshot:before { content: "\f05b"; } +.icon-remove-circle:before { content: "\f05c"; } +.icon-ok-circle:before { content: "\f05d"; } +.icon-ban-circle:before { content: "\f05e"; } + +.icon-arrow-left:before { content: "\f060"; } +.icon-arrow-right:before { content: "\f061"; } +.icon-arrow-up:before { content: "\f062"; } +.icon-arrow-down:before { content: "\f063"; } +.icon-share-alt:before { content: "\f064"; } +.icon-resize-full:before { content: "\f065"; } +.icon-resize-small:before { content: "\f066"; } +.icon-plus:before { content: "\f067"; } +.icon-minus:before { content: "\f068"; } +.icon-asterisk:before { content: "\f069"; } +.icon-exclamation-sign:before { content: "\f06a"; } +.icon-gift:before { content: "\f06b"; } +.icon-leaf:before { content: "\f06c"; } +.icon-fire:before { content: "\f06d"; } +.icon-eye-open:before { content: "\f06e"; } + +.icon-eye-close:before { content: "\f070"; } +.icon-warning-sign:before { content: "\f071"; } +.icon-plane:before { content: "\f072"; } +.icon-calendar:before { content: "\f073"; } +.icon-random:before { content: "\f074"; } +.icon-comment:before { content: "\f075"; } +.icon-magnet:before { content: "\f076"; } +.icon-chevron-up:before { content: "\f077"; } +.icon-chevron-down:before { content: "\f078"; } +.icon-retweet:before { content: "\f079"; } +.icon-shopping-cart:before { content: "\f07a"; } +.icon-folder-close:before { content: "\f07b"; } +.icon-folder-open:before { content: "\f07c"; } +.icon-resize-vertical:before { content: "\f07d"; } +.icon-resize-horizontal:before { content: "\f07e"; } + +.icon-bar-chart:before { content: "\f080"; } +.icon-twitter-sign:before { content: "\f081"; } +.icon-facebook-sign:before { content: "\f082"; } +.icon-camera-retro:before { content: "\f083"; } +.icon-key:before { content: "\f084"; } +.icon-cogs:before { content: "\f085"; } +.icon-comments:before { content: "\f086"; } +.icon-thumbs-up:before { content: "\f087"; } +.icon-thumbs-down:before { content: "\f088"; } +.icon-star-half:before { content: "\f089"; } +.icon-heart-empty:before { content: "\f08a"; } +.icon-signout:before { content: "\f08b"; } +.icon-linkedin-sign:before { content: "\f08c"; } +.icon-pushpin:before { content: "\f08d"; } +.icon-external-link:before { content: "\f08e"; } + +.icon-signin:before { content: "\f090"; } +.icon-trophy:before { content: "\f091"; } +.icon-github-sign:before { content: "\f092"; } +.icon-upload-alt:before { content: "\f093"; } +.icon-lemon:before { content: "\f094"; } diff --git a/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.eot b/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.eot new file mode 100755 index 0000000000000000000000000000000000000000..3f669a7eb607c214d66477c7a2c5a454c64c1a98 GIT binary patch literal 42272 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 literal 0 HcmV?d00001 diff --git a/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svg b/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svg new file mode 100755 index 0000000000..73c0ad9a91 --- /dev/null +++ b/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svg @@ -0,0 +1,175 @@ + + + + +This is a custom SVG webfont generated by Font Squirrel. +Designer : Dave Gandy +Foundry : Fort Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svgz b/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.svgz new file mode 100755 index 0000000000000000000000000000000000000000..2a73cd7c10f25c9ca99aa864ba1fdccce215c990 GIT binary patch literal 21845 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 literal 0 HcmV?d00001 diff --git a/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.ttf b/src/sunstone/public/vendor/FontAwesome/font/fontawesome-webfont.ttf new file mode 100755 index 0000000000000000000000000000000000000000..4972eb453fcbbb87e2da55f2910ee2333f08c8a7 GIT binary patch literal 41916 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 z - + From a626e0b84f8c21026efe47646b80023f6aae2e87 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Wed, 6 Jun 2012 00:00:31 +0200 Subject: [PATCH 10/11] Feature #1299: New plots for Sunstone dashboard (unfinished) Added a new monitoring plugin and enabled new plots in Sunstone. Current code its not final, need to better organize as plugin, add comments, make sure current methods can be reused easily when upgrading the cluster dashboards. --- install.sh | 2 + src/sunstone/public/css/application.css | 10 +- src/sunstone/public/js/monitoring.js | 392 +++++++++++++++++ src/sunstone/public/js/opennebula.js | 4 +- src/sunstone/public/js/plugins/acls-tab.js | 2 +- src/sunstone/public/js/plugins/config-tab.js | 4 +- .../public/js/plugins/dashboard-tab.js | 395 +++++++++--------- .../public/js/plugins/datastores-tab.js | 2 +- src/sunstone/public/js/plugins/groups-tab.js | 2 +- src/sunstone/public/js/plugins/hosts-tab.js | 6 +- src/sunstone/public/js/plugins/images-tab.js | 2 +- .../public/js/plugins/templates-tab.js | 4 +- src/sunstone/public/js/plugins/users-tab.js | 4 +- src/sunstone/public/js/plugins/vms-tab.js | 4 +- src/sunstone/public/js/plugins/vnets-tab.js | 2 +- .../public/vendor/flot/jquery.flot.pie.min.js | 1 + src/sunstone/views/index.erb | 2 + 17 files changed, 628 insertions(+), 210 deletions(-) create mode 100644 src/sunstone/public/js/monitoring.js create mode 100644 src/sunstone/public/vendor/flot/jquery.flot.pie.min.js diff --git a/install.sh b/install.sh index 267c08ad26..d8bb4bd872 100755 --- a/install.sh +++ b/install.sh @@ -1194,6 +1194,7 @@ SUNSTONE_PUBLIC_JS_FILES="src/sunstone/public/js/layout.js \ src/sunstone/public/js/sunstone.js \ src/sunstone/public/js/sunstone-util.js \ src/sunstone/public/js/opennebula.js \ + src/sunstone/public/js/monitoring.js \ src/sunstone/public/js/locale.js" SUNSTONE_PUBLIC_JS_PLUGINS_FILES="\ @@ -1268,6 +1269,7 @@ SUNSTONE_PUBLIC_VENDOR_JQUERYLAYOUT="\ SUNSTONE_PUBLIC_VENDOR_FLOT="\ src/sunstone/public/vendor/flot/jquery.flot.min.js \ src/sunstone/public/vendor/flot/jquery.flot.navigate.min.js \ +src/sunstone/public/vendor/flot/jquery.flot.pie.min.js \ src/sunstone/public/vendor/flot/LICENSE.txt \ src/sunstone/public/vendor/flot/NOTICE \ src/sunstone/public/vendor/flot/README.txt" diff --git a/src/sunstone/public/css/application.css b/src/sunstone/public/css/application.css index 89339e91ca..e4e8781bee 100644 --- a/src/sunstone/public/css/application.css +++ b/src/sunstone/public/css/application.css @@ -644,7 +644,7 @@ ul.action_list li a:hover{ font-family: serif; } -.legend { +.legend_p { color: #636663; margin-left: 10px; margin-top: 3px; @@ -653,6 +653,12 @@ ul.action_list li a:hover{ /* border-bottom: 1px solid #A3A3A3; */ } -.legend:before { +.legend_p:before { content: '⇨ '; +} + +.big_text { + color: #333333; + font-size: 2em; + font-family: serif; } \ No newline at end of file diff --git a/src/sunstone/public/js/monitoring.js b/src/sunstone/public/js/monitoring.js new file mode 100644 index 0000000000..b8651da5fc --- /dev/null +++ b/src/sunstone/public/js/monitoring.js @@ -0,0 +1,392 @@ +var SunstoneMonitoring = { + monitor : function(resource, list){ + + if (!SunstoneMonitoringConfig[resource]) + return false + + var monConfigs = SunstoneMonitoringConfig[resource].monitor + var monitoring = {} + for (conf in monConfigs){ + var conf_obj = monConfigs[conf] + var plotID = conf + var series = conf_obj.operation(resource, list, conf_obj) + monitoring[plotID]=series + } + + //Call back after monitorization is done + SunstoneMonitoringConfig[resource].plot(monitoring) + }, + plot : function(resource,plotID,container,series){ + var config = SunstoneMonitoringConfig[resource].monitor[plotID] + var options = config.plotOptions + $.plot(container,series,options) + }, + ops : { + partition : function(resource,list,config){ + var path = config.path + var partitionPath = config.partitionPath + var dataType = config.dataType + var partitions = {} + for (var i=0; i< list.length; i++){ + var elem = list[i][resource] + var value = path ? parseInt(explore_path(elem,path),10) : 1 + var partition = explore_path(elem, partitionPath) + + //Things on cluster none + if (partitionPath == "CLUSTER" && !partition.length) + partition = "none" + + if (!partitions[partition]) + partitions[partition] = value + else + partitions[partition] += value + } + + var series = [] + var i = 0; + for (partition in partitions) { + var value = partitions[partition] + var data; + switch (dataType){ + case "pie": + data = value; break + case "bars": + data = [[i,value]]; break + case "horizontal_bars": + data = [[value,i]]; break + default: + data = value; + } + var color = config.colorize ? config.colorize(partition) : null + series.push({ label: partition, + data: data, + color: color + }) + i++ + } + + return series + }, + hostCpuUsagePartition : function(resource,list,config){ + partitions = { + "Idle" : 0, + "Ok" : 0, + "Used" : 0, + "Working" : 0, + "Overloaded" : 0 + } + + for (var i=0; i< list.length; i++){ + var elem = list[i].HOST + var value = elem.HOST_SHARE.USED_CPU * 100 / + elem.HOST_SHARE.MAX_CPU + if (value > 80) + partitions["Overloaded"]++ + else if (value > 60) + partitions["Working"]++ + else if (value > 40) + partitions["Used"]++ + else if (value > 20) + partitions["Ok"]++ + else + partitions["Idle"]++ + } + + series = []; + for (partition in partitions) { + var data = partitions[partition] + var color = config.colorize ? config.colorize(partition) : null + series.push({ label: partition, + data: data, + }) + } + return series + }, + totalize : function(resource,list,config){ + return list.length + }, + singleBar : function(resource,list,config){ + var paths = config.paths + + var totals = new Array(paths.length) + for (var i=0; i< totals.length; i++) totals[i] = 0 + + var series = [] + + for (var i=0; i< list.length; i++){ + var elem = list[i][resource] + for (var j=0; j< paths.length; j++) + totals[j] += parseInt(explore_path(elem,paths[j]),10) + } + + for (var i=0; i< totals.length; i++){ + series.push({ + data: [[totals[i],0]], + label: paths[i], + color: config.colorize? config.colorize(paths[i]) : null + }) + } + return series + } + } +} + + +var SunstoneMonitoringConfig = { + "HOST" : { + plot: function(mon){ + plotHostMonitoring(mon) //not defined at parsing moment + }, + monitor : { + "statePie" : { + partitionPath: "STATE", + operation: SunstoneMonitoring.ops.partition, + dataType: "pie", + colorize: function(state){ + switch (state) { + case '0': return "rgb(239,201,86)" //yellow + case '1': return "rgb(175,216,248)" //blue + case '2': return "rgb(108,183,108)" //green + case '3': return "rgb(203,75,75)" //red + case '4': return "rgb(71,71,71)" //gray + case '5': return "rgb(160,160,160)" //light gray + } + }, + plotOptions : { + series: { pie: { show: true } }, + legend : { + labelFormatter: function(label, series){ + return OpenNebula.Helper.resource_state("host_simple",label) + + ' - ' + series.data[0][1] + ' (' + + Math.floor(series.percent) + '%' + ')'; + } + } + } + }, + "cpuPerCluster" : { + path: ["HOST_SHARE","CPU_USAGE"], + partitionPath: "CLUSTER_ID", + operation: SunstoneMonitoring.ops.partition, + dataType: "bars", + plotOptions: { + series: { bars: {show: true, barWidth: 0.5 }}, + xaxis: { show: false }, + yaxis: { min: 0 }, + legend : { + noColumns: 2, + labelFormatter: function(label){ + if (label == "-1") return "none" + return getClusterName(label) + } + } + } + }, + "memoryPerCluster" : { + path: ["HOST_SHARE","MEM_USAGE"], + partitionPath: "CLUSTER_ID", + operation: SunstoneMonitoring.ops.partition, + dataType: "bars", + plotOptions: { + series: { bars: {show: true, barWidth: 0.5 }}, + xaxis: { show: false }, + yaxis: { + tickFormatter : function(val,axis) { + return humanize_size(val); + }, + min: 0 + }, + legend : { + noColumns: 2, + labelFormatter: function(label){ + if (label == "-1") return "none" + return getClusterName(label) + } + } + } + }, + "globalCpuUsage" : { + partitionPath: ["HOST_SHARE", "USED_CPU"], + dataType: "pie", + operation: SunstoneMonitoring.ops.hostCpuUsagePartition, + plotOptions: { + series: { pie: { show: true } }, + } + }, + "totalHosts" : { + operation: SunstoneMonitoring.ops.totalize + }, + "cpuUsageBar" : { + paths: [ + ["HOST_SHARE","MAX_CPU"], + ["HOST_SHARE","USED_CPU"], + ["HOST_SHARE","CPU_USAGE"], + ], + operation: SunstoneMonitoring.ops.singleBar, + plotOptions: { + series: { bars: { show: true, + horizontal: true, + barWidth: 0.5 } + }, + yaxis: { show: false }, + xaxis: { min:0 }, + legend: { + noColumns: 1, + container: '#cpuUsageBar_legend', + labelFormatter: function(label, series){ + return label[1].toLowerCase() + } + } + } + }, + "memoryUsageBar" : { + paths: [ + ["HOST_SHARE","MAX_MEM"], + ["HOST_SHARE","USED_MEM"], + ["HOST_SHARE","MEM_USAGE"], + ], + operation: SunstoneMonitoring.ops.singleBar, + plotOptions: { + series: { bars: { show: true, + horizontal: true, + barWidth: 0.5 } + }, + yaxis: { show: false }, + xaxis: { + tickFormatter : function(val,axis) { + return humanize_size(val); + }, + min: 0 + }, + legend: { + noColumns: 1, + container: '#memoryUsageBar_legend', + labelFormatter: function(label, series){ + return label[1].toLowerCase() + } + } + } + }, + } + }, + "USER" : { + plot: function(mon){ + plotUserMonitoring(mon) + }, + monitor: { + "usersPerGroup" : { + partitionPath: "GNAME", + operation: SunstoneMonitoring.ops.partition, + dataType: "bars", + plotOptions: { + series: { bars: {show: true, barWidth: 0.5 }}, + xaxis: { show: false }, + yaxis: { tickDecimals: 0, + min: 0 }, + legend : { + noColumns: 2, + } + } + }, + "totalUsers" : { + operation: SunstoneMonitoring.ops.totalize + }, + } + }, + "ACL" : { + plot: function(mon){ + plotAclMonitoring(mon) + }, + monitor: { + "totalAcls" : { + operation: SunstoneMonitoring.ops.totalize + } + }, + }, + "GROUP" : { + plot: function(mon){ + plotGroupMonitoring(mon) + }, + monitor: { + "totalGroups" : { + operation: SunstoneMonitoring.ops.totalize + } + }, + }, + "VM" : { + plot: function(mon){ + plotVMMonitoring(mon) + }, + monitor: { + "totalVMs" : { + operation: SunstoneMonitoring.ops.totalize + }, + "statePie" : { + partitionPath: "STATE", + operation: SunstoneMonitoring.ops.partition, + dataType: "pie", + colorize: function(state){ + switch (state) { + case '0': return "rgb(160,160,160)" //light gray - init + case '1': return "rgb(239,201,86)" //yellow - pending + case '2': return "rgb(237,154,64)" //orange - hold + case '3': return "rgb(108,183,108)" //green - active + case '4': return "rgb(175,216,248)" //blue - stopped + case '5': return "rgb(112,164,205)" //dark blue - suspended + case '6': return "rgb(71,71,71)" //gray - done + case '7': return "rgb(203,75,75)" //red - failed + + } + }, + plotOptions : { + series: { pie: { show: true } }, + legend : { + labelFormatter: function(label, series){ + return OpenNebula.Helper.resource_state("vm",label) + + ' - ' + series.data[0][1] + ' (' + + Math.floor(series.percent) + '%' + ')'; + } + } + } + }, + "netUsageBar" : { + paths: [ "NET_RX", "NET_TX" ], + operation: SunstoneMonitoring.ops.singleBar, + plotOptions: { + series: { bars: { show: true, + horizontal: true, + barWidth: 0.5 } + }, + yaxis: { show: false }, + xaxis: { + min: 0, + tickFormatter : function(val,axis) { + return humanize_size(val); + }, + }, + legend: { + noColumns: 1, + container: '#netUsageBar_legend', + labelFormatter: function(label, series){ + return label + " - " + humanize_size(series.data[0][0]) + } + } + } + }, + } + } +} + + + + +function explore_path(elem,path){ + if (!$.isArray(path)) //base case - non array + return elem[path] + else if (path.length == 1) //base case - array + return elem[path[0]] + else {//recurse + var array = path.slice(0) //clone path + var p = array.splice(0,1) + return explore_path(elem[p],array) + } +} \ No newline at end of file diff --git a/src/sunstone/public/js/opennebula.js b/src/sunstone/public/js/opennebula.js index 2e4cd6a96b..1324599362 100644 --- a/src/sunstone/public/js/opennebula.js +++ b/src/sunstone/public/js/opennebula.js @@ -249,8 +249,10 @@ var OpenNebula = { data: {timeout: timeout}, dataType: "json", success: function(response){ + var list = OpenNebula.Helper.pool(resource,response) + SunstoneMonitoring.monitor(resource, list) return callback ? - callback(request, OpenNebula.Helper.pool(resource,response)) : null; + callback(request, list) : null; }, error: function(response) { diff --git a/src/sunstone/public/js/plugins/acls-tab.js b/src/sunstone/public/js/plugins/acls-tab.js index 877ccf0012..2e54bf4147 100644 --- a/src/sunstone/public/js/plugins/acls-tab.js +++ b/src/sunstone/public/js/plugins/acls-tab.js @@ -40,7 +40,7 @@ var acls_tab_content = '\ \
\ ?\ -

\ +

\ '+tr("This table shows the ACLs rules broken down to easier the reading and meaning of each one. You can show the ACL original string by clicking on Show/Hide columns.")+'\

\
\ diff --git a/src/sunstone/public/js/plugins/config-tab.js b/src/sunstone/public/js/plugins/config-tab.js index 8e583f9ddd..7907a523c6 100644 --- a/src/sunstone/public/js/plugins/config-tab.js +++ b/src/sunstone/public/js/plugins/config-tab.js @@ -51,10 +51,10 @@ var config_tab_content = \
\ ?\ -

\ +

\ '+tr("These options are stored in your OpenNebula user template.")+'\

\ -

\ +

\ '+tr("WSS connection requires additional configuration of Sunstone Server and that the SSL certificate is considered valid by your browser.")+'\

\
\ diff --git a/src/sunstone/public/js/plugins/dashboard-tab.js b/src/sunstone/public/js/plugins/dashboard-tab.js index 2cf395e157..948571b664 100644 --- a/src/sunstone/public/js/plugins/dashboard-tab.js +++ b/src/sunstone/public/js/plugins/dashboard-tab.js @@ -14,142 +14,159 @@ /* limitations under the License. */ /* -------------------------------------------------------------------------- */ -/** HISTORY_LENGTH currently ignored on server, but it does not harm to have it**/ -var HISTORY_LENGTH=40; -var GRAPH_AUTOREFRESH_INTERVAL=60000; //60 secs - -var graph1 = { - title : "graph1", - monitor_resources : "HOST_SHARE/CPU_USAGE,HOST_SHARE/USED_CPU,HOST_SHARE/MAX_CPU", - history_length : HISTORY_LENGTH -}; - -var graph2 = { - title : "graph2", - monitor_resources : "HOST_SHARE/MEM_USAGE,HOST_SHARE/USED_MEM,HOST_SHARE/MAX_MEM", - history_length : HISTORY_LENGTH -}; - -var graph3 = { - title : "graph3", - monitor_resources : "total,active,error", - history_length : HISTORY_LENGTH -}; - -var graph4 = { - title : "graph4", - monitor_resources : "NET_TX,NET_RX", - history_length : HISTORY_LENGTH -}; - var dashboard_tab_content = '\ \ -
\ -\ +\ +\ -
\ +\ \ \ \ +
\
\ -

' + tr("Summary of resources") + '

\ +

' + tr("Hosts") + '

\
\ \ \ \ - \ - \ + \ + \ + \ +\ + \ + \ + \ \ \ - \ - \ + \ + \ +\ + \ + \ + \ \ \ - \ - \ + \ + \ +\ + \ + \ + \ \ \ - \ - \ + \ + \ +\ +\ + \ + \ + \ \ \ - \ - \ + \ \ \ - \ - \ + \ + \ \ \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ - \ + \ \ +\
' + tr("Hosts (total/active)") + '' + tr("Total Hosts") + '
' + tr("State") + '' + tr("Global CPU Usage") + '
' + tr("Clusters") + '
' + tr("Used vs. Max CPU") + '
' + tr("Groups") + '\ +
\ +
\ +
' + tr("Allocated CPU per cluster") + '
' + tr("VM Templates") + '
' + tr("Used vs. Max Memory") + '
' + - tr("VM Instances")+ ' (' + - tr("total") + '/' + - tr("running") + '/' + - tr("failed") + ')\ +
\ +
\ +
' + tr("Virtual Networks") + '' + tr("Allocated Memory per cluster") + '
' + tr("Datastores") + '
' + tr("Images") + '
' + tr("Users")+'
' + tr("ACL Rules") + '
\ \
\
\
\ +
\ +\ + \ + \ + \ \ \ - \ -
\ +
\ +

' + tr("Virtual Machines") + '

\ +
\ + \ +\ + \ + \ + \ + \ +\ +\ + \ + \ + \ + \ + \ + \ + \ +\ + \ + \ + \ + \ + \ + \ + \ +\ + \ + \ + \ + \ + \ + \ + \ +\ +
' + tr("Total VMs") + '
' + tr("State") + '
' + tr("Global transfer rates") + '
\ +
\ +
\ +
' + tr("Estimated global bandwidth - Upload") + '' + tr("Download") + '
\ +
\ +
\ +
\ +
\ +
\ +
\ \ -
\ -
\ -\ - \ - \ @@ -166,6 +183,90 @@ var dashboard_tab = { Sunstone.addMainTab('dashboard_tab',dashboard_tab); +var $dashboard; + +function updateDashboard(){ + //mock +} + +function plotHostMonitoring(monitoring){ + $('#totalHosts', $dashboard).text(monitoring['totalHosts']) + delete monitoring['totalHosts'] + + if (!$dashboard.is(':visible')) return; + + for (plotID in monitoring){ + var container = $('div#'+plotID,$dashboard); + SunstoneMonitoring.plot("HOST", + plotID, + container, + monitoring[plotID]); + }; +} + +function plotUserMonitoring(monitoring){ + $('#totalUsers', $dashboard).text(monitoring['totalUsers']) + + if (!$dashboard.is(':visible')) return; + + var container = $('div#usersPerGroup',$dashboard); + SunstoneMonitoring.plot('USER', + 'usersPerGroup', + container, + monitoring['usersPerGroup']); +} + +function plotAclMonitoring(monitoring){ + $('#totalAcls', $dashboard).text(monitoring['totalAcls']) +} + +function plotGroupMonitoring(monitoring){ + $('#totalGroups', $dashboard).text(monitoring['totalGroups']) +} + +//Permanent storage for last value of aggregated network usage +//Used to calculate bandwidth +var netUsage = { + time : new Date().getTime(), + up : 0, + down : 0 +} + +function plotVMMonitoring(monitoring){ + $('#totalVMs', $dashboard).text(monitoring['totalVMs']) + + var t = ((new Date().getTime()) - netUsage.time) / 1000 //in secs + var bandwidth_up = monitoring['netUsageBar'][1].data[0][0] - netUsage.up + bandwidth_up /= t + var bandwidth_up_str = humanize_size(bandwidth_up) + "/s" //bytes /sec + var bandwidth_down = monitoring['netUsageBar'][0].data[0][0] - netUsage.down + bandwidth_down /= t + var bandwidth_down_str = humanize_size(bandwidth_down) + "/s" //bytes /sec + + if (bandwidth_up >= 0) + $('#bandwidth_up', $dashboard).text(bandwidth_up_str) + if (bandwidth_down >= 0) + $('#bandwidth_down', $dashboard).text(bandwidth_down_str) + + netUsage.time = new Date().getTime() + netUsage.up = monitoring['netUsageBar'][1].data[0][0] + netUsage.down = monitoring['netUsageBar'][0].data[0][0] + + if (!$dashboard.is(':visible')) return; + + var container = $('div#vmStatePie',$dashboard); + SunstoneMonitoring.plot('VM', + 'statePie', + container, + monitoring['statePie']); + + container = $('div#netUsageBar',$dashboard); + SunstoneMonitoring.plot('VM', + 'netUsageBar', + container, + monitoring['netUsageBar']); +} + function plot_global_graph(data,info){ var context = $('#historical_table',main_tabs_context); var id = info.title; @@ -212,95 +313,7 @@ function plot_global_graph(data,info){ $.plot($('#'+id+'_graph',context),series,options); } -function graph_autorefresh(){ - setInterval(function(){ - refresh_graphs(); - },GRAPH_AUTOREFRESH_INTERVAL+someTime()); - -} - -function refresh_graphs(){ - Sunstone.runAction("Host.monitor_all", graph1); - Sunstone.runAction("Host.monitor_all", graph2); - Sunstone.runAction("VM.monitor_all", graph3); - Sunstone.runAction("VM.monitor_all", graph4); -} $(document).ready(function(){ - emptyDashboard(); - -// refresh_graphs(); -// graph_autorefresh(); - -}); - -//puts the dashboard values into "retrieving" -function emptyDashboard(){ - $("#dashboard_tab .value_td span",main_tabs_context).html(spinner); -} - - -function updateDashboard(what,json_info){ - var db = $('#dashboard_tab',main_tabs_context); - switch (what){ - case "hosts": - var total_hosts=json_info.length; - var active_hosts=0; - $.each(json_info,function(){ - if (parseInt(this.HOST.STATE) < 3){ - active_hosts++;} - }); - $('#total_hosts',db).html(total_hosts+' / '); - $('#active_hosts',db).html(active_hosts); - break; - case "groups": - var total_groups=json_info.length; - $('#total_groups',db).html(total_groups); - break; - case "vms": - var total_vms=json_info.length; - var running_vms=0; - failed_vms=0; - $.each(json_info,function(){ - vm_state = parseInt(this.VM.STATE); - if (vm_state == 3){ - running_vms++; - } - else if (vm_state == 7) { - failed_vms++; - } - }); - $('#total_vms',db).html(total_vms+' / '); - $('#running_vms',db).html(running_vms+' / '); - $('#failed_vms',db).html(failed_vms); - break; - case "vnets": - var total_vnets=json_info.length; - $('#total_vnets',db).html(total_vnets); - break; - case "users": - var total_users=json_info.length; - $('#total_users',db).html(total_users); - break; - case "images": - var total_images=json_info.length; - $('#total_images',db).html(total_images); - break; - case "templates": - var total_templates=json_info.length; - $('#total_templates',db).html(total_templates); - break; - case "acls": - var total_acls=json_info.length; - $('#total_acls',db).html(total_acls); - break; - case "clusters": - var total_clusters=json_info.length; - $('#total_clusters',db).html(total_clusters); - break; - case "datastores": - var total_datastores=json_info.length; - $('#total_datastores',db).html(total_datastores); - break; - } -}; + $dashboard = $('#dashboard_tab', main_tabs_context); +}); \ No newline at end of file diff --git a/src/sunstone/public/js/plugins/datastores-tab.js b/src/sunstone/public/js/plugins/datastores-tab.js index 0cd99ff457..195eb2a750 100644 --- a/src/sunstone/public/js/plugins/datastores-tab.js +++ b/src/sunstone/public/js/plugins/datastores-tab.js @@ -41,7 +41,7 @@ var datastores_tab_content = '\
\ -
\ -

' + tr("Historical monitoring information") + '

\ +

' + tr("System Information") + '

\
\ -\
\
\
\
\ ?\ -

\ +

\ '+tr("Datatables are sets of images which share a common transfer driver. i.e. Images in a SSH datastore will be copied to the hosts using SSH when deploying a Virtual Machine.")+'\

\
\ diff --git a/src/sunstone/public/js/plugins/groups-tab.js b/src/sunstone/public/js/plugins/groups-tab.js index d0e3834c6b..307e868ced 100644 --- a/src/sunstone/public/js/plugins/groups-tab.js +++ b/src/sunstone/public/js/plugins/groups-tab.js @@ -37,7 +37,7 @@ var groups_tab_content = '\
\
\ ?\ -

\ +

\ '+tr("Tip: Refresh the list if it only shows user ids in the Users column.")+'\

\
\ diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index 32a5316ba0..7ce1947885 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -59,13 +59,13 @@ var hosts_tab_content = '\
\
\ ?\ -

\ +

\ '+tr("CPU Use is calculated as the minimum between (total CPU - real CPU usage) and (allocated CPU). Real CPU usage is provided by the hosts monitoring driver. Available CPU is calculated using the information from the CPU setting of the VMs running on that host (allocated CPU)")+'\

\ -

\ +

\ '+tr("Memory use is calculated according to the information provided by the host monitoring driver.")+'\

\ -

\ +

\ '+tr("You can get monitoring graphs by clicking in the desired host and visiting the monitoring information tab. Note that oneacctd must be running for this information to be updated/available.")+'\

\
\ diff --git a/src/sunstone/public/js/plugins/images-tab.js b/src/sunstone/public/js/plugins/images-tab.js index 43a2660033..61e0e1d83a 100644 --- a/src/sunstone/public/js/plugins/images-tab.js +++ b/src/sunstone/public/js/plugins/images-tab.js @@ -44,7 +44,7 @@ var images_tab_content = '\ \
\ ?\ -

\ +

\ '+tr("Size and registration time are hidden colums. Note that persistent images can only be used by 1 VM. To change image datastore, please re-register the image.")+'\

\
\ diff --git a/src/sunstone/public/js/plugins/templates-tab.js b/src/sunstone/public/js/plugins/templates-tab.js index 88543322a1..2870cd6209 100644 --- a/src/sunstone/public/js/plugins/templates-tab.js +++ b/src/sunstone/public/js/plugins/templates-tab.js @@ -37,10 +37,10 @@ var templates_tab_content = '\ \
\ ?\ -

\ +

\ '+tr("Clicking `instantiate` will instantly create new Virtual Machines from the selected templates and name one-id. If you want to assign a specific name to a new VM, or launch several instances at once, use Virtual Machines->New button.")+'\

\ -

\ +

\ '+tr("You can clone a template to obtain a copy from an existing template. This copy will be owned by you.")+'\

\
\ diff --git a/src/sunstone/public/js/plugins/users-tab.js b/src/sunstone/public/js/plugins/users-tab.js index 34001fafd7..78563dfaab 100644 --- a/src/sunstone/public/js/plugins/users-tab.js +++ b/src/sunstone/public/js/plugins/users-tab.js @@ -41,12 +41,12 @@ var users_tab_content = '\ \
\ ?\ -

\ +

\ '+ tr("Tip: You can save any information in the user template, in the form of VAR=VAL.")+ '\

\ -

\ +

\ '+ tr("Tip: SSH authentication method is not available for web UI access.")+ '\ diff --git a/src/sunstone/public/js/plugins/vms-tab.js b/src/sunstone/public/js/plugins/vms-tab.js index fef0aaf422..922af774ff 100644 --- a/src/sunstone/public/js/plugins/vms-tab.js +++ b/src/sunstone/public/js/plugins/vms-tab.js @@ -74,10 +74,10 @@ var vms_tab_content = '\ \

\ ?\ -

\ +

\ '+tr("CPU, Memory and Start time are hidden columns by default. You can get monitoring graphs by clicking on the desired VM and visiting the monitoring information tab.")+'\

\ -

\ +

\ '+tr("VNC console requires previous install of the noVNC addon. Check Sunstone documentation for more information.")+'\

\
\ diff --git a/src/sunstone/public/js/plugins/vnets-tab.js b/src/sunstone/public/js/plugins/vnets-tab.js index 31f68bb3c1..e67ab575e5 100644 --- a/src/sunstone/public/js/plugins/vnets-tab.js +++ b/src/sunstone/public/js/plugins/vnets-tab.js @@ -40,7 +40,7 @@ var vnets_tab_content = '\ \
\ ?\ -

\ +

\ '+tr("Tip: edit the leases of a network by clicking on one and going to the lease management tab.")+'\

\
\ diff --git a/src/sunstone/public/vendor/flot/jquery.flot.pie.min.js b/src/sunstone/public/vendor/flot/jquery.flot.pie.min.js new file mode 100644 index 0000000000..b7bf870d75 --- /dev/null +++ b/src/sunstone/public/vendor/flot/jquery.flot.pie.min.js @@ -0,0 +1 @@ +(function(b){function c(D){var h=null;var L=null;var n=null;var B=null;var p=null;var M=0;var F=true;var o=10;var w=0.95;var A=0;var d=false;var z=false;var j=[];D.hooks.processOptions.push(g);D.hooks.bindEvents.push(e);function g(O,N){if(N.series.pie.show){N.grid.show=false;if(N.series.pie.label.show=="auto"){if(N.legend.show){N.series.pie.label.show=false}else{N.series.pie.label.show=true}}if(N.series.pie.radius=="auto"){if(N.series.pie.label.show){N.series.pie.radius=3/4}else{N.series.pie.radius=1}}if(N.series.pie.tilt>1){N.series.pie.tilt=1}if(N.series.pie.tilt<0){N.series.pie.tilt=0}O.hooks.processDatapoints.push(E);O.hooks.drawOverlay.push(H);O.hooks.draw.push(r)}}function e(P,N){var O=P.getOptions();if(O.series.pie.show&&O.grid.hoverable){N.unbind("mousemove").mousemove(t)}if(O.series.pie.show&&O.grid.clickable){N.unbind("click").click(l)}}function G(O){var P="";function N(S,T){if(!T){T=0}for(var R=0;Rh.width-n){B=h.width-n}}}function v(O){for(var N=0;N0){R.push({data:[[1,P]],color:N,label:a.series.pie.combine.label,angle:(P*(Math.PI*2))/M,percent:(P/M*100)})}return R}function r(S,Q){if(!L){return}ctx=Q;I();var T=S.getData();var P=0;while(F&&P0){n*=w}P+=1;N();if(a.series.pie.tilt<=0.8){O()}R()}if(P>=o){N();L.prepend('
Could not draw pie with labels contained inside canvas
')}if(S.setSeries&&S.insertLegend){S.setSeries(T);S.insertLegend()}function N(){ctx.clearRect(0,0,h.width,h.height);L.children().filter(".pieLabel, .pieLabelBackground").remove()}function O(){var Z=5;var Y=15;var W=10;var X=0.02;if(a.series.pie.radius>1){var U=a.series.pie.radius}else{var U=n*a.series.pie.radius}if(U>=(h.width/2)-Z||U*a.series.pie.tilt>=(h.height/2)-Y||U<=W){return}ctx.save();ctx.translate(Z,Y);ctx.globalAlpha=X;ctx.fillStyle="#000";ctx.translate(B,p);ctx.scale(1,a.series.pie.tilt);for(var V=1;V<=W;V++){ctx.beginPath();ctx.arc(0,0,U,0,Math.PI*2,false);ctx.fill();U-=V}ctx.restore()}function R(){startAngle=Math.PI*a.series.pie.startAngle;if(a.series.pie.radius>1){var U=a.series.pie.radius}else{var U=n*a.series.pie.radius}ctx.save();ctx.translate(B,p);ctx.scale(1,a.series.pie.tilt);ctx.save();var Y=startAngle;for(var W=0;W1e-9){ctx.moveTo(0,0)}else{if(b.browser.msie){ab-=0.0001}}ctx.arc(0,0,U,Y,Y+ab,false);ctx.closePath();Y+=ab;if(aa){ctx.fill()}else{ctx.stroke()}}function V(){var ac=startAngle;if(a.series.pie.label.radius>1){var Z=a.series.pie.label.radius}else{var Z=n*a.series.pie.label.radius}for(var ab=0;ab=a.series.pie.label.threshold*100){aa(T[ab],ac,ab)}ac+=T[ab].angle}function aa(ap,ai,ag){if(ap.data[0][1]==0){return}var ar=a.legend.labelFormatter,aq,ae=a.series.pie.label.formatter;if(ar){aq=ar(ap.label,ap)}else{aq=ap.label}if(ae){aq=ae(aq,ap)}var aj=((ai+ap.angle)+ai)/2;var ao=B+Math.round(Math.cos(aj)*Z);var am=p+Math.round(Math.sin(aj)*Z)*a.series.pie.tilt;var af=''+aq+"";L.append(af);var an=L.children("#pieLabel"+ag);var ad=(am-an.height()/2);var ah=(ao-an.width()/2);an.css("top",ad);an.css("left",ah);if(0-ad>0||0-ah>0||h.height-(ad+an.height())<0||h.width-(ah+an.width())<0){F=true}if(a.series.pie.label.background.opacity!=0){var ak=a.series.pie.label.background.color;if(ak==null){ak=ap.color}var al="top:"+ad+"px;left:"+ah+"px;";b('
').insertBefore(an).css("opacity",a.series.pie.label.background.opacity)}}}}}function J(N){if(a.series.pie.innerRadius>0){N.save();innerRadius=a.series.pie.innerRadius>1?a.series.pie.innerRadius:n*a.series.pie.innerRadius;N.globalCompositeOperation="destination-out";N.beginPath();N.fillStyle=a.series.pie.stroke.color;N.arc(0,0,innerRadius,0,Math.PI*2,false);N.fill();N.closePath();N.restore();N.save();N.beginPath();N.strokeStyle=a.series.pie.stroke.color;N.arc(0,0,innerRadius,0,Math.PI*2,false);N.stroke();N.closePath();N.restore()}}function s(Q,R){for(var S=false,P=-1,N=Q.length,O=N-1;++P1?O.series.pie.radius:n*O.series.pie.radius;for(var Q=0;Q1?P.series.pie.radius:n*P.series.pie.radius;R.save();R.translate(B,p);R.scale(1,P.series.pie.tilt);for(i=0;i1e-9){R.moveTo(0,0)}R.arc(0,0,N,S.startAngle,S.startAngle+S.angle,false);R.closePath();R.fill()}}}var a={series:{pie:{show:false,radius:"auto",innerRadius:0,startAngle:3/2,tilt:1,offset:{top:0,left:"auto"},stroke:{color:"#FFF",width:1},label:{show:"auto",formatter:function(d,e){return'
'+d+"
"+Math.round(e.percent)+"%
"},radius:1,background:{color:null,opacity:0},threshold:0},combine:{threshold:-1,color:null,label:"Other"},highlight:{opacity:0.5}}}};b.plot.plugins.push({init:c,options:a,name:"pie",version:"1.0"})})(jQuery); \ No newline at end of file diff --git a/src/sunstone/views/index.erb b/src/sunstone/views/index.erb index 979c687c09..62abea7888 100644 --- a/src/sunstone/views/index.erb +++ b/src/sunstone/views/index.erb @@ -20,6 +20,7 @@ + @@ -37,6 +38,7 @@ + <% @plugins["plugins"].each do |plugin| %> From 386e6cb78db4d197929f022fe355f571a9efb0c9 Mon Sep 17 00:00:00 2001 From: Hector Sanjuan Date: Fri, 8 Jun 2012 10:19:34 +0200 Subject: [PATCH 11/11] Feature #1299: Reorganize dashboard graphs. --- src/sunstone/public/css/application.css | 4 +- src/sunstone/public/js/monitoring.js | 6 +- .../public/js/plugins/dashboard-tab.js | 113 +++++++++--------- 3 files changed, 64 insertions(+), 59 deletions(-) diff --git a/src/sunstone/public/css/application.css b/src/sunstone/public/css/application.css index e4e8781bee..bed2567dca 100644 --- a/src/sunstone/public/css/application.css +++ b/src/sunstone/public/css/application.css @@ -659,6 +659,8 @@ ul.action_list li a:hover{ .big_text { color: #333333; - font-size: 2em; + font-size: 5em; font-family: serif; + text-align:center; + vertical-align:middle; } \ No newline at end of file diff --git a/src/sunstone/public/js/monitoring.js b/src/sunstone/public/js/monitoring.js index b8651da5fc..6bf9369f2f 100644 --- a/src/sunstone/public/js/monitoring.js +++ b/src/sunstone/public/js/monitoring.js @@ -230,7 +230,7 @@ var SunstoneMonitoringConfig = { yaxis: { show: false }, xaxis: { min:0 }, legend: { - noColumns: 1, + noColumns: 3, container: '#cpuUsageBar_legend', labelFormatter: function(label, series){ return label[1].toLowerCase() @@ -258,7 +258,7 @@ var SunstoneMonitoringConfig = { min: 0 }, legend: { - noColumns: 1, + noColumns: 3, container: '#memoryUsageBar_legend', labelFormatter: function(label, series){ return label[1].toLowerCase() @@ -364,7 +364,7 @@ var SunstoneMonitoringConfig = { }, }, legend: { - noColumns: 1, + noColumns: 3, container: '#netUsageBar_legend', labelFormatter: function(label, series){ return label + " - " + humanize_size(series.data[0][0]) diff --git a/src/sunstone/public/js/plugins/dashboard-tab.js b/src/sunstone/public/js/plugins/dashboard-tab.js index 948571b664..c9588b59e2 100644 --- a/src/sunstone/public/js/plugins/dashboard-tab.js +++ b/src/sunstone/public/js/plugins/dashboard-tab.js @@ -17,64 +17,76 @@ var dashboard_tab_content = '\ \ -\ -
\ +\ \ \ \ + \ + \ + \
\
\ -

' + tr("Hosts") + '

\ +

' + tr("Hosts") + '

\
\ -\ \ +\ \ \ - \ - \ -\ - \ \ \ \ \ - \ + \ + \ \ \ \ \ - \ + \ + \ \ \ - \ + \ +\ + \ + \ + \ + \ + \ + \ + \ \ +\ +
' + tr("Total Hosts") + '
' + tr("State") + '' + tr("Global CPU Usage") + '
\ +
' + tr("Used vs. Max CPU") + '
\ -
\ -
\ +
\ +
\ +
' + tr("Used vs. Max Memory") + '
\ +
\
\ +\ +
\ +
\ +
\ +
\ +

' + tr("Clusters") + '

\ +
\ +\ + \ \ \ \ \ \ \ - \ + \ \ \ -\ - \ - \ - \ - \ - \ - \ - \ \ \ \ \ \ - \ + \ \ \
' + tr("Allocated CPU per cluster") + '
' + tr("Used vs. Max Memory") + '
\ -
\ -
\ -
' + tr("Allocated Memory per cluster") + '
\ @@ -85,7 +97,7 @@ var dashboard_tab_content =
\
\ +\ \ \ \ \ - \ + \ + \ \ \ + \ + \ + \ + \ + \ \ \ \ \ + \ \ \ - \ + \ \ \ \ \ - \ + \ \ \ - \ - \ -\ - \ - \ - \ - \ - \ - \ \ \ @@ -144,27 +151,23 @@ var dashboard_tab_content = \ \ \ - \ - \ -\ - \ \ - \ - \ -\ - \ \ - \ \ \ \ - \ + \ + \ + \ + \ +\ + \ + \ \ \ \ - \ + \ \ -\ \
\ @@ -96,37 +108,32 @@ var dashboard_tab_content = \
' + tr("Total VMs") + '' + tr("Bandwidth - Upload") + '' + tr("Bandwidth - Download") + '
' + tr("State") + '
' + tr("Global transfer rates") + '
\ -
\ -
\ -
' + tr("Estimated global bandwidth - Upload") + '' + tr("Download") + '
\ -
\ -
\ +
\ +
\
' + tr("Total Users") + '
' + tr("Total Groups") + '
' + tr("Total ACLs") + '
' + tr("Users per group") + '
' + tr("Users per group") + '
\ \