diff --git a/src/sunstone/public/js/plugins/dashboard-tab.js b/src/sunstone/public/js/plugins/dashboard-tab.js new file mode 100644 index 0000000000..aae302f487 --- /dev/null +++ b/src/sunstone/public/js/plugins/dashboard-tab.js @@ -0,0 +1,232 @@ +/* -------------------------------------------------------------------------- */ +/* Copyright 2002-2011, OpenNebula Project Leads (OpenNebula.org) */ +/* */ +/* Licensed under the Apache License, Version 2.0 (the "License"); you may */ +/* not use this file except in compliance with the License. You may obtain */ +/* a copy of the License at */ +/* */ +/* http://www.apache.org/licenses/LICENSE-2.0 */ +/* */ +/* Unless required by applicable law or agreed to in writing, software */ +/* distributed under the License is distributed on an "AS IS" BASIS, */ +/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ +/* See the License for the specific language governing permissions and */ +/* limitations under the License. */ +/* -------------------------------------------------------------------------- */ + +var dashboard_tab_content = +'\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
\ +
\ +

Hosts\ +
\ + +\ +
\ +

\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
Total
Active
\ +
\ +
\ +
\ +
\ +

Clusters\ +
\ + +\ +
\ +

\ +
\ + \ + \ + \ + \ + \ +
Total
\ +
\ +
\ +
\ +
\ +

Virtual Machines\ +
\ + +\ +
\ +

\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
Total
Running
Failed
\ +
\ +
\ +
\ +
\ +

Virtual Networks\ +
\ + +\ +
\ +

\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
Total
Public
\ +
\ +
\ + \ +
\ +
\ +

\ + Images\ +
\ + +\ +
\ +

\ +
\ + \ + \ + \ + \ + \ + \ + \ + \ + \ +
Total
Public
\ +
\ +
\ +
\ +
\ +

Users\ +
\ + +\ +
\ +

\ +
\ + \ + \ + \ + \ + \ +
Total
\ +
\ +
\ +
'; + + +Sunstone.addMainTab('Dashboard',dashboard_tab_content,null,'dashboard_tab'); + +$(document).ready(function(){ + //Dashboard link listener + $("#dashboard_table h3 a").live("click", function (){ + var tab = $(this).attr('href'); + showTab(tab); + return false; + }); + + emptyDashboard(); + + +}); + +//puts the dashboard values into "retrieving" +function emptyDashboard(){ + $("#dashboard_tab .value_td span").html(spinner); +} + + +function updateDashboard(what,json_info){ + db = $('#dashboard_tab'); + switch (what){ + case "hosts": + total_hosts=json_info.length; + 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 "clusters": + total_clusters=json_info.length; + $('#total_clusters',db).html(total_clusters); + break; + case "vms": + total_vms=json_info.length; + 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": + public_vnets=0; + total_vnets=json_info.length; + $.each(json_info,function(){ + if (parseInt(this.VNET.PUBLIC)){ + public_vnets++;} + }); + $('#total_vnets',db).html(total_vnets); + $('#public_vnets',db).html(public_vnets); + break; + case "users": + total_users=json_info.length; + $('#total_users',db).html(total_users); + break; + case "images": + total_images=json_info.length; + public_images=0; + $.each(json_info,function(){ + if (parseInt(this.IMAGE.PUBLIC)){ + public_images++;} + }); + $('#total_images',db).html(total_images); + $('#public_images',db).html(public_images); + break; + } +} diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js index a1abcefe54..f96c1c66a3 100644 --- a/src/sunstone/public/js/plugins/hosts-tab.js +++ b/src/sunstone/public/js/plugins/hosts-tab.js @@ -16,7 +16,7 @@ /*Host tab plugin*/ -var host_tab_content = +var hosts_tab_content = '
\
\
\ @@ -39,7 +39,10 @@ var host_tab_content =
'; var hosts_select=""; +var clusters_select=""; var host_list_json = {}; +var cluster_list_json = {}; +var dataTable_hosts = null; //Setup actions @@ -47,87 +50,78 @@ var host_actions = { "Host.create" : { type: "create", call : OpenNebula.Host.create, - callback = addHostElement, + callback : addHostElement, error : onError, notify:true, - condition: true }, - "Host.enable" = { + "Host.enable" : { type: "multiple", call : OpenNebula.Host.enable, - callback = host_update_callback, + callback : host_update_callback, error : onError, notify:true, - condition:true }, - "Host.disable" = { + "Host.disable" : { type: "multiple", call : OpenNebula.Host.disable, - callback = host_update_callback, + callback : host_update_callback, error : onError, notify:true, - condition:true }, - "Host.delete" = { + "Host.delete" : { type: "multiple", call : OpenNebula.Host.create, - callback = deleteHostElement, + callback : deleteHostElement, error : onError, notify:true, - condition:true }, - "Host.list" = { + "Host.list" : { type: "custom", call : function() { OpenNebula.Host.list({success: updateHostsView, error: onError}); OpenNebula.Cluster.list({success: updateClustersView, error: onError}); - } - callback: null, + }, + callback: function(){}, error: onError, notify:true, - condition:true }, - "Cluster.create" = { + "Cluster.create" : { type: "create", call : OpenNebula.Cluster.create, - callback = addClusterElement + callback : function(){ + OpenNebula.Cluster.list({success: updateClustersView, error: onError}); + }, error : onError, notify:true, - condition : true }, - "Cluster.delete" = { + "Cluster.delete" : { type: "multiple", call : OpenNebula.Host.create, - callback = addHostElement, + callback : addHostElement, error : onError, notify:true, - condition:true }, - "Cluster.addhost" = { - type: "confirm_with_select", - select: cluster_select, - tip: "Select the cluster in which you would like to place the hosts", + "Cluster.addhost" : { + type: "multiple", call : OpenNebula.Cluster.addhost, - callback = updateHostElement, + callback : updateHostElement, error : onError, notify:true, - condition : true }, - "Cluster.removehost" = { + "Cluster.removehost" : { type: "multiple", call : OpenNebula.Cluster.removehost, - callback = deleteHostElement, + callback : deleteHostElement, error : onError, notify:true, - condition:true } }; @@ -137,61 +131,60 @@ var host_buttons = [ type: "create", text: "+ New host", action: "Host.create", - condition : true + condition :True }, { type: "action", text: "Enable", action: "Host.enable", - condition : true + condition : True }, { - type: "action", + type: "confirm", text: "Disable", action: "Host.disable", - condition : true + tip: "Confirm disable", + condition : True }, { type: "create", text: "+ New Cluster", action: "Cluster.create", - condition : true + condition : True }, { type: "action", text: "Delete cluster", action: "Cluster.delete", - condition : true - } + condition : True + }, { type: "select", - action: [{ text: "Add host to cluster", + action: [{ type: "confirm_with_select", + text: "Add host to cluster", value: "Cluster.addhost", - condition: true}, - { text: "Remove host from cluster", + select: "cluster_select", + tip: "Select the cluster in which you would like to place the hosts", + condition: True}, + { type: "action", + text: "Remove host from cluster", value: "Cluster.removehost", - condition: true}], - condition : true + condition: True}], + condition : True }, { type: "action", text: "Delete host", value: "Host.delete", - condition : true - }]}; + condition : True + }]; for (action in host_actions){ Sunstone.addAction(action,host_actions[action]); } -Sunstone.addMainTab(hosts_tab_content,'hosts_tab'); - -$.each(host_buttons,function(){ - Sunstone.addButton(this,'#hosts_tab'); -} - - -//Setup tab +// title, content, buttons, id +Sunstone.addMainTab('Hosts',hosts_tab_content,host_buttons,'hosts_tab'); //Plugin functions @@ -291,6 +284,20 @@ function updateHostSelect(host_list){ } +function updateClusterSelect(cluster_list){ + + //update select helper + clusters_select= ""; + clusters_select+=""; + $.each(cluster_list, function(){ + clusters_select += ""; + }); + + //update static selectors + //$('#host_cluster').html(clusters_select); + +} + function updateHostElement(request, host_json){ id = host_json.HOST.ID; element = hostElementArray(host_json); @@ -321,6 +328,19 @@ function updateHostsView (request,host_list){ updateDashboard("hosts",host_list_json); } +function updateClustersView(request, cluster_list){ + cluster_list_json = cluster_list; + //~ cluster_list_array = []; + + //~ $.each(cluster_list, function(){ + //~ cluster_list_array.push(clusterElementArray(this)); + //~ }); + //~ updateView(cluster_list_array,dataTable_clusters); + updateClusterSelect(cluster_list); + updateDashboard("clusters"); +} + + function updateHostInfo(request,host){ host_info = host.HOST rendered_info = @@ -402,10 +422,10 @@ function updateHostInfo(request,host){ } //Document ready -$(document).ready(){ +$(document).ready(function(){ //prepare host datatable - var dataTable_hosts = $("#datatable_hosts").dataTable({ + dataTable_hosts = $("#datatable_hosts").dataTable({ "bJQueryUI": true, "bSortClasses": false, "bAutoWidth":false, @@ -432,13 +452,8 @@ $(document).ready(){ if (!nodes.length && !filter.length){ OpenNebula.Host.list({timeout: true, success: updateHostsView,error: onError}); } - },interval); + },60000); initCheckAllBoxes(dataTable_hosts); - - //.action button listener - $('#hosts_tab .action_button').click(function(){ - Sunstone.runActionOnDatatableNodes($(this).val(),dataTable_hosts); - } - -} + +}); diff --git a/src/sunstone/public/js/sunstone-util.js b/src/sunstone/public/js/sunstone-util.js index 5baa070b62..be4789d287 100644 --- a/src/sunstone/public/js/sunstone-util.js +++ b/src/sunstone/public/js/sunstone-util.js @@ -124,6 +124,11 @@ function humanize_size(value) { return st; } +function addElement(element,data_table){ + data_table.fnAddData(element); +} + + function deleteElement(data_table,tag){ tr = $(tag).parents('tr')[0]; data_table.fnDeleteRow(tr); @@ -258,3 +263,73 @@ function initCheckAllBoxes(datatable){ }); } }); } + +function onError(request,error_json) { + var method; + var action; + var object; + var id; + var reason; + var m; + var message = error_json.error.message; + + //redirect to login if unauthenticated + if (error_json.error.http_status=="401") { + window.location.href = "/login"; + }; + + //Parse known errors: + var action_error = /^\[(\w+)\] Error trying to (\w+) (\w+) \[(\w+)\].*Reason: (.*)\.$/; + var action_error_noid = /^\[(\w+)\] Error trying to (\w+) (\w+) (.*)\.$/; + var get_error = /^\[(\w+)\] Error getting (\w+) \[(\w+)\]\.$/; + var auth_error = /^\[(\w+)\] User \[.\] not authorized to perform (\w+) on (\w+) \[?(\w+)\]?\.?$/; + + if (m = message.match(action_error)) { + method = m[1]; + action = m[2]; + object = m[3]; + id = m[4]; + reason = m[5]; + } else if (m = message.match(action_error_noid)) { + method = m[1]; + action = m[2]; + object = m[3]; + reason = m[4]; + } else if (m = message.match(get_error)) { + method = m[1]; + action = "SHOW"; + object = m[2]; + id = m[3]; + } else if (m = message.match(auth_error)) { + method = m[1]; + action = m[2]; + object = m[3]; + id = m[4]; + } + + if (m) { + var rows; + var i; + var value; + rows = ["method","action","object","id","reason"]; + message = ""; + for (i in rows){ + key = rows[i]; + value = eval(key); + if (value) + message += ""+key+""+value+""; + } + message = "" + message + "
"; + } + + notifyError(message); + return true; +} + + +function True(){ + return true; +} +function False(){ + return false; +} diff --git a/src/sunstone/public/js/sunstone.js b/src/sunstone/public/js/sunstone.js index 7c631040af..57f0fd7fe9 100644 --- a/src/sunstone/public/js/sunstone.js +++ b/src/sunstone/public/js/sunstone.js @@ -22,12 +22,27 @@ var username = ''; var uid = ''; var spinner = 'retrieving'; +var SunstoneCfg = { + "actions" : { + + + }, + + "tabs" : { + + }, + + "info_panels" : { + + } +}; + var Sunstone = { "addAction" : function (name,action_obj) { - SunstoneCfg.config.actions[name] = action_obj; + SunstoneCfg["actions"].name = action_obj; }, "updateAction" : function(action,new_action) { @@ -38,9 +53,10 @@ var Sunstone = { }, - "addMainTab" : function(tab_id,title_arg,content_arg) { + "addMainTab" : function(title_arg,content_arg, buttons_arg,tab_id) { SunstoneCfg["tabs"][tab_id] = {title: title_arg, - content: content_arg}; + content: content_arg, + buttons: buttons_arg }; }, "updateMainTab" : function(tab_id,new_content){ @@ -66,6 +82,9 @@ var Sunstone = { var err = action_cfg.callback; var notify = action_cfg.notify; + $('div#confirm_with_select_dialog').dialog("close"); + $('div#confirm_dialog').dialog("close"); + //We ease the use of: // * Create call @@ -77,15 +96,6 @@ var Sunstone = { case "create","single": call({data:data_arg, success: callback,error:err}); break; - case "confirm": - tip = actions.tip; - //popup confirm dialog (action,tip). - break; - case "confirm_with_select": - tip = OpenNebula.Views.Actions[action].tip; - select = OpenNebula.Views.Actions[action].select; - //popup confirm dialog with select(action,tip,select) - break; case "list": call({success: callback, error:err}); break; @@ -93,9 +103,9 @@ var Sunstone = { //run on the list of nodes that come on the data $.each(data_arg,function(){ if (extra_param){ - call(this,callback,error) + //unsupported } else { - call(this,extra_param,callback,error) + call({data:this, success: callback, error:err}); } }); break; @@ -115,136 +125,122 @@ var Sunstone = { var data = []; $.each(nodes,function(){ data.push($(this).val()); - } + }); runAction(action,data); } else { - notifyError("Unknown datatable"); + runAction(action); }; }//meter coma y seguir aquĆ­ -} +}; + + + //~ "actions" : { + //~ + //~ "VM.create" = { + //~ + //~ }, + //~ + //~ "VM.deploy" = { + //~ + //~ }, + //~ + //~ "VM.migrate" = { + //~ + //~ }, + //~ + //~ "VM.livemigrate" = { + //~ + //~ }, + //~ + //~ "VM.hold" = { + //~ + //~ }, + //~ + //~ "VM.release" = { + //~ + //~ }, + //~ + //~ "VM.suspend" = { + //~ + //~ }, + //~ + //~ "VM.resume" = { + //~ + //~ }, + //~ + //~ "VM.stop" = { + //~ + //~ }, + //~ + //~ "VM.restart" = { + //~ + //~ }, + //~ + //~ "VM.shutdown" = { + //~ + //~ }, + //~ + //~ "VM.cancel" = { + //~ + //~ }, + //~ + //~ "VM.delete" = { + //~ + //~ }, + //~ + //~ "Network.publish" = { + //~ + //~ }, + //~ + //~ "Network.unpublish" = { + //~ + //~ }, + //~ + //~ "Network.delete" = { + //~ + //~ }, + //~ + //~ "User.create" = { + //~ + //~ }, + //~ + //~ "User.delete" = { + //~ + //~ }, + //~ + //~ "Image.enable" = { + //~ + //~ }, + //~ + //~ "Image.disable" = { + //~ + //~ }, + //~ + //~ "Image.persistent" = { + //~ + //~ }, + //~ + //~ "Image.nonpersistent" = { + //~ + //~ }, + //~ + //~ "Image.publish" = { + //~ + //~ }, + //~ + //~ "Image.unpublish" = { + //~ + //~ }, + //~ + //~ "Image.delete" = { + //~ + //~ } -var SunstoneCfg = { - "config" = { - - "actions" : { - - "VM.create" = { - - }, - - "VM.deploy" = { - - }, - - "VM.migrate" = { - - }, - - "VM.livemigrate" = { - - }, - - "VM.hold" = { - - }, - - "VM.release" = { - - }, - - "VM.suspend" = { - - }, - - "VM.resume" = { - - }, - - "VM.stop" = { - - }, - - "VM.restart" = { - - }, - - "VM.shutdown" = { - - }, - - "VM.cancel" = { - - }, - - "VM.delete" = { - - }, - - "Network.publish" = { - - }, - - "Network.unpublish" = { - - }, - - "Network.delete" = { - - }, - - "User.create" = { - - }, - - "User.delete" = { - - }, - - "Image.enable" = { - - }, - - "Image.disable" = { - - }, - - "Image.persistent" = { - - }, - - "Image.nonpersistent" = { - - }, - - "Image.publish" = { - - }, - - "Image.unpublish" = { - - }, - - "Image.delete" = { - - } - }, - - "tabs" = { - - }, - - "info_panels" = { - - } - - } - -} //plugins have done their jobs when we execute this -$(document).ready(){ +$(document).ready(function(){ readCookie(); setLogin(); insertTabs(); @@ -253,32 +249,46 @@ $(document).ready(){ initListButtons(); setupCreateDialogs(); //listener for create + setupConfirmDialogs(); setupTips(); - //action button listener! -> plugins deal with that + $('.action_button').live("click",function(){ + + var table = null; + if ($(this).parents('table').length){ + table = $(this).parents('table').dataTable(); + } + //if no table found the action will be run as custom + Sunstone.runActionOnDatatableNodes($(this).value,table); + }); + + $('.confirm_button').live("click",function(){ + popUpConfirmDialog(this); + }); + + $('.confirm_with_select_button').live("click",function(){ + popUpConfirmWithSelectDialog(this) + }); $('button').button(); $('div#select_helpers').hide(); - emptyDashboard(); + $(".ui-widget-overlay").live("click", function (){ $("div:ui-dialog:visible").dialog("close"); }); - //Dashboard link listener - $("#dashboard_table h3 a").live("click", function (){ - var tab = $(this).attr('href'); - showTab(tab); - return false; - }); + //Close select lists... $('*:not(.action_list,.list_button)').click(function(){ $('.action_list:visible').hide(); }); -} +}); + + //reads the cookie and places its info in the 'cookie' var @@ -310,11 +320,11 @@ function setLogin(){ function insertTabs(){ var tab_info; for (tab in SunstoneCfg["tabs"]){ - tab_info = SunstoneCfg["tabs"].tab; - $("div.inner_center").append('
'); - $('div#'+tab_info.tab_id).html(tab_info.content); + tab_info = SunstoneCfg["tabs"][tab]; + $("div.inner-center").append('
'); + $('div#'+tab).html(tab_info.content); - $('ul#navigation').append('
  • '+tab+'
  • '); + $('ul#navigation').append('
  • '+tab_info.title+'
  • '); } } @@ -331,25 +341,39 @@ function insertButtons(){ if ($('div#'+tab+' .action_blocks').length){ $.each(buttons,function(){ button_code = ""; - if (!this.condition()) { return true }; + if (this.condition()) { - switch (this.type) { - case "action": - button_code = ''; - break; - case "create": - button_code = ''; - break; - case "select": + switch (this.type) { + case "select": button_code = ''; + button_code += ''; break; + case "confirm_with_select": + button_code = ''; + break; + case "action": + case "create": + case "confirm": + default: + button_code = ''; + } } $('div#'+tab+' .action_blocks').append(button_code); @@ -433,16 +457,103 @@ function initListButtons(){ //Sets up all the "+ New Thing" dialogs. function setupCreateDialogs(){ - createHostDialog(); - createClusterDialog(); - createVMachineDialog(); - createVNetworkDialog(); - createUserDialog(); - createImageDialog(); +// createHostDialog(); +// createClusterDialog(); +// createVMachineDialog(); +// createVNetworkDialog(); +// createUserDialog(); +// createImageDialog(); //Todo listener on "create" class to trigger the right dialog. } +//Adds the dialogs bodies +function setupConfirmDialogs(){ + + //confirm + if (!($('div#confirm_dialog').length)){ + $('div#dialogs').append('
    '); + }; + + $('div#confirm_dialog').html( + '
    \ +
    Do you want to proceed?
    \ +
    \ +
    Do you want to proceed?
    \ +
    \ +
    \ + \ + \ +
    \ +
    '); + + //prepare the jquery dialog + $('div#confirm_dialog').dialog({ + resizable:false, + modal:true, + width:300, + heigth:200, + autoOpen:false + }); + + $('div#confirm_dialog button').button(); + + if (!($('div#confirm_with_select_dialog').length)){ + $('div#dialogs').append('
    '); + }; + + $('div#confirm_with_select_dialog').html( + '
    \ +
    \ + \ +
    \ + \ + \ +
    \ +
    '); + + //prepare the jquery dialog + $('div#confirm_with_select_dialog').dialog({ + resizable:false, + modal:true, + width:300, + heigth:300, + autoOpen:false + }); + + $('div#confirm_with_select_dialog button').button(); + + $('button.confirm_cancel').click(function(){ + $('div#confirm_with_select_dialog').dialog("close"); + $('div#confirm_dialog').dialog("close"); + return false; + }); + +} + +function popUpConfirmDialog(target_elem){ + button = $(target_elem); + value = button.val(); + action = SunstoneCfg["actions"][value]; + +} + +function popUpConfirmWithSelectDialog(target_elem){ + var button = $(target_elem); + var value = button.val(); + var action = SunstoneCfg["actions"][value]; + var select_var = eval(button.attr("select_id")); + var tip = button.attr(tip); + $('select#confirm_select').html(select_var); + $('div#confirm_with_select_tip').text(tip); + + $('button#confirm_with_select_proceed').val(val); + $('div#confirm_with_select_dialog').dialog("open"); + + +} + //Replaces all class"tip" divs with an information icon that //displays the tip information on mouseover. function setupTips(){ diff --git a/src/sunstone/templates/index.html b/src/sunstone/templates/index.html index 37abef4e23..79cc056998 100644 --- a/src/sunstone/templates/index.html +++ b/src/sunstone/templates/index.html @@ -20,31 +20,34 @@ - - + + + + +
    -
    +