diff --git a/src/sunstone/public/js/one-ui_views.js b/src/sunstone/public/js/one-ui_views.js
index fb67fc85b3..c2a2e9d53e 100644
--- a/src/sunstone/public/js/one-ui_views.js
+++ b/src/sunstone/public/js/one-ui_views.js
@@ -21,25 +21,28 @@
 
 var dataTable_hosts=null;
 //~ var dataTable_clusters=null;
-var dataTable_vMachines=null;
-var dataTable_vNetworks=null;
-var dataTable_users=null;
-var dataTable_images=null;
-var host_list_json = {};
-var cluster_list_json = {};
-var vmachine_list_json = {};
-var network_list_json = {};
-var user_list_json = {};
-var image_list_json = {};
-var hosts_select="";
-var clusters_select="";
-var vnetworks_select="";
-var images_select="";
+//~ var dataTable_vMachines=null;
+//~ var dataTable_vNetworks=null;
+//~ var dataTable_users=null;
+//~ var dataTable_images=null;
+//~ var host_list_json = {};
+//~ var cluster_list_json = {};
+//~ var vmachine_list_json = {};
+//~ var network_list_json = {};
+//~ var user_list_json = {};
+//~ var image_list_json = {};
+//~ var hosts_select="";
+//~ var clusters_select="";
+//~ var vnetworks_select="";
+//~ var images_select="";
 var cookie = {};
 var username = '';
 var uid = '';
 var spinner = '<img src="/images/ajax-loader.gif" alt="retrieving" class="loading_img"/>';
 
+
+
+
 /*######################################################################
  * DOCUMENT READY FUNCTIONS
  * ###################################################################*/
@@ -229,12 +232,12 @@ function initDataTables(){
 }
 
 //Adds a listener to checks all the elements of a table
-function initCheckAllBoxes(){
+function initCheckAllBoxes(datatable){
 	//not showing nice in that position
 	//$('.check_all').button({ icons: {primary : "ui-icon-check" },
 	//							text : true});
-	$('.check_all').css({"border":"2px"});
-	$('.check_all').click(function(){
+	$('.check_all',datatable).css({"border":"2px"});
+	$('.check_all',datatable).click(function(){
 		if ($(this).attr("checked")) {
 			$('tbody input:checkbox',
 				$(this).parents("table")).each(function(){
@@ -761,6 +764,9 @@ function actionButtonListener(){
 	});
 }
 
+
+
+
 function preloadTables(){
     dataTable_hosts.fnClearTable();
     addElement([
@@ -2180,17 +2186,14 @@ function setupTips(){
 //Crawls the user dataTable for that. If such user is not found,
 //we return the uid.
 function getUserName(uid){
+    nodes = dataTable_users.fnGetData();
     user = "uid "+uid;
-    if (dataTable_users != null){
-        nodes = dataTable_users.fnGetData();
-        $.each(nodes,function(){
-            if (uid == this[1]) {
-            user = this[2];
-            return false;
-            }
-        });
-    };
-
+    $.each(nodes,function(){
+       if (uid == this[1]) {
+           user = this[2];
+           return false;
+       }
+    });
     return user;
 
 }
@@ -2556,13 +2559,13 @@ function emptyDashboard(){
     $("#dashboard .value_td span").html(spinner);
 }
 
-function updateDashboard(what){
+function updateDashboard(what,json_info){
 	db = $('#dashboard');
 	switch (what){
 		case "hosts":
-			total_hosts=host_list_json.length;
+			total_hosts=json_info.length;
 			active_hosts=0;
-			$.each(host_list_json,function(){
+			$.each(json_info,function(){
 				if (parseInt(this.HOST.STATE) < 3){
 					active_hosts++;}
 			});
@@ -2570,14 +2573,14 @@ function updateDashboard(what){
 			$('#active_hosts',db).html(active_hosts);
 			break;
 		case "clusters":
-			total_clusters=cluster_list_json.length;
+			total_clusters=json_info.length;
 			$('#total_clusters',db).html(total_clusters);
 			break;
 		case "vms":
-			total_vms=vmachine_list_json.length;
+			total_vms=json_info.length;
 			running_vms=0;
             failed_vms=0;
-			$.each(vmachine_list_json,function(){
+			$.each(json_info,function(){
                 vm_state = parseInt(this.VM.STATE);
 				if (vm_state == 3){
 					running_vms++;
@@ -2592,8 +2595,8 @@ function updateDashboard(what){
 			break;
 		case "vnets":
 			public_vnets=0;
-			total_vnets=network_list_json.length;
-			$.each(network_list_json,function(){
+			total_vnets=json_info.length;
+			$.each(json_info,function(){
 				if (parseInt(this.VNET.PUBLIC)){
 					public_vnets++;}
 			});
@@ -2601,13 +2604,13 @@ function updateDashboard(what){
 			$('#public_vnets',db).html(public_vnets);
 			break;
 		case "users":
-			total_users=user_list_json.length;
+			total_users=json_info.length;
 			$('#total_users',db).html(total_users);
 			break;
         case "images":
-            total_images=image_list_json.length;
+            total_images=json_info.length;
             public_images=0;
-            $.each(image_list_json,function(){
+            $.each(json_info,function(){
 				if (parseInt(this.IMAGE.PUBLIC)){
 					public_images++;}
 			});
diff --git a/src/sunstone/public/js/plugins/hosts-tab.js b/src/sunstone/public/js/plugins/hosts-tab.js
new file mode 100644
index 0000000000..a1abcefe54
--- /dev/null
+++ b/src/sunstone/public/js/plugins/hosts-tab.js
@@ -0,0 +1,444 @@
+/* -------------------------------------------------------------------------- */
+/* 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.                                             */
+/* -------------------------------------------------------------------------- */
+
+/*Host tab plugin*/
+
+var host_tab_content = 
+'<form id="form_hosts" action="javascript:alert(\'js errors?!\')">\
+  <div class="action_blocks">\
+  </div>\
+<table id="datatable_hosts" class="display">\
+  <thead>\
+    <tr>\
+      <th class="check"><input type="checkbox" class="check_all" value="">All</input></th>\
+      <th>ID</th>\
+      <th>Name</th>\
+      <th>Cluster</th>\
+      <th>Running VMs</th>\
+      <th>CPU Use</th>\
+      <th>Memory use</th>\
+      <th>Status</th>\
+    </tr>\
+  </thead>\
+  <tbody id="tbodyhosts">\
+  </tbody>\
+</table>\
+</form>';
+
+var hosts_select="";
+var host_list_json = {};
+
+
+//Setup actions
+var host_actions = {
+            "Host.create" : {
+                type: "create",
+                call : OpenNebula.Host.create,
+                callback = addHostElement,
+                error : onError,
+                notify:true,
+                condition: true
+            },
+            
+            "Host.enable" = {
+                type: "multiple",
+                call : OpenNebula.Host.enable,
+                callback = host_update_callback,
+                error : onError,
+                notify:true,
+                condition:true
+            },
+            
+            "Host.disable" = {
+                type: "multiple",
+                call : OpenNebula.Host.disable,
+                callback = host_update_callback,
+                error : onError,
+                notify:true,
+                condition:true
+            },
+            
+            "Host.delete" = {
+                type: "multiple",
+                call : OpenNebula.Host.create,
+                callback = deleteHostElement,
+                error : onError,
+                notify:true,
+                condition:true
+            },
+            
+            "Host.list" = {
+                type: "custom",
+                call : function() {
+                    OpenNebula.Host.list({success: updateHostsView, error: onError});
+                    OpenNebula.Cluster.list({success: updateClustersView, error: onError});
+                    }
+                callback: null,
+                error: onError,
+                notify:true,
+                condition:true 
+            },
+            
+            "Cluster.create" = {
+                type: "create",
+                call : OpenNebula.Cluster.create,
+                callback = addClusterElement
+                error : onError,
+                notify:true,
+                condition : true
+            },
+            
+            "Cluster.delete" = {
+                type: "multiple",
+                call : OpenNebula.Host.create,
+                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",
+                call : OpenNebula.Cluster.addhost,
+                callback = updateHostElement,
+                error : onError,
+                notify:true,
+                condition : true
+            },
+            
+            "Cluster.removehost" = {
+                type: "multiple",
+                call : OpenNebula.Cluster.removehost,
+                callback = deleteHostElement,
+                error : onError,
+                notify:true,
+                condition:true
+            }
+        };
+
+
+var host_buttons = [
+        {
+            type: "create",
+            text: "+ New host",
+            action: "Host.create",
+            condition : true
+        },
+        {
+            type: "action",
+            text: "Enable",
+            action: "Host.enable",
+            condition : true
+        },
+        {
+            type: "action",
+            text: "Disable",
+            action: "Host.disable",
+            condition : true
+        },
+        {
+            type: "create",
+            text: "+ New Cluster",
+            action: "Cluster.create",
+            condition : true
+        },
+        {
+            type: "action",
+            text: "Delete cluster",
+            action: "Cluster.delete",
+            condition : true
+        }
+        {
+            type: "select",
+            action: [{ text: "Add host to cluster", 
+                        value: "Cluster.addhost",
+                        condition: true},
+                     {  text: "Remove host from cluster",
+                        value: "Cluster.removehost",
+                        condition: true}],
+            condition : true
+        },
+        {
+            type: "action",
+            text: "Delete host",
+            value: "Host.delete",
+            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
+
+
+//Plugin functions
+function host_update_callback(req){
+    OpenNebula.Host.show({data:{id:req.request.data[0]},success: updateHostElement,error: onError});
+}
+
+function hostElementArray(host_json){
+	host = host_json.HOST;
+	acpu = parseInt(host.HOST_SHARE.MAX_CPU);
+		if (!acpu) {acpu=100};
+	acpu = acpu - parseInt(host.HOST_SHARE.CPU_USAGE);
+
+    total_mem = parseInt(host.HOST_SHARE.MAX_MEM);
+    free_mem = parseInt(host.HOST_SHARE.FREE_MEM);
+
+    if (total_mem == 0) {
+        ratio_mem = 0;
+    } else {
+        ratio_mem = Math.round(((total_mem - free_mem) / total_mem) * 100);
+    }
+
+
+    total_cpu = parseInt(host.HOST_SHARE.MAX_CPU);
+    used_cpu = Math.max(total_cpu - parseInt(host.HOST_SHARE.USED_CPU),acpu);
+
+    if (total_cpu == 0) {
+        ratio_cpu = 0;
+    } else {
+        ratio_cpu = Math.round(((total_cpu - used_cpu) / total_cpu) * 100);
+    }
+
+     pb_mem =
+'<div style="height:10px" class="ratiobar ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="'+ratio_mem+'">\
+    <div class="ui-progressbar-value ui-widget-header ui-corner-left ui-corner-right" style="width: '+ratio_mem+'%;"/>\
+    <span style="position:relative;left:45px;top:-4px;font-size:0.6em">'+ratio_mem+'%</span>\
+    </div>\
+</div>';
+
+    pb_cpu =
+'<div style="height:10px" class="ratiobar ui-progressbar ui-widget ui-widget-content ui-corner-all" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="'+ratio_cpu+'">\
+    <div class="ui-progressbar-value ui-widget-header ui-corner-left ui-corner-right" style="width: '+ratio_cpu+'%;"/>\
+    <span style="position:relative;left:45px;top:-4px;font-size:0.6em">'+ratio_cpu+'%</span>\
+    </div>\
+</div>';
+
+
+    return [ '<input type="checkbox" id="host_'+host.ID+'" name="selected_items" value="'+host.ID+'"/>',
+			host.ID,
+			host.NAME,
+			host.CLUSTER,
+			host.HOST_SHARE.RUNNING_VMS, //rvm
+            pb_cpu,
+			pb_mem,
+			OpenNebula.Helper.resource_state("host",host.STATE) ];
+
+
+	//~ return [ '<input type="checkbox" id="host_'+host.ID+'" name="selected_items" value="'+host.ID+'"/>',
+			//~ host.ID,
+			//~ host.NAME,
+			//~ host.CLUSTER,
+			//~ host.HOST_SHARE.RUNNING_VMS, //rvm
+			//~ host.HOST_SHARE.MAX_CPU, //tcpu
+			//~ parseInt(host.HOST_SHARE.MAX_CPU) - parseInt(host.HOST_SHARE.USED_CPU), //fcpu
+			//~ acpu,
+			//~ humanize_size(host.HOST_SHARE.MAX_MEM),
+			//~ humanize_size(host.HOST_SHARE.FREE_MEM),
+			//~ OpenNebula.Helper.resource_state("host",host.STATE) ];
+}
+
+
+function hostInfoListener(){
+	$('#tbodyhosts tr').live("click",function(e){
+
+		//do nothing if we are clicking a checkbox!
+		if ($(e.target).is('input')) {return true;}
+
+        popDialogLoading();
+		aData = dataTable_hosts.fnGetData(this);
+		id = $(aData[0]).val();
+		OpenNebula.Host.show({data:{id:id},success: updateHostInfo,error: onError});
+		return false;
+	});
+}
+
+function updateHostSelect(host_list){
+
+	//update select helper
+	hosts_select="";
+	hosts_select += "<option value=\"\">Select a Host</option>";
+	$.each(host_list, function(){
+		hosts_select += "<option value=\""+this.HOST.ID+"\">"+this.HOST.NAME+"</option>";
+	});
+
+	//update static selectors
+	$('#vm_host').html(hosts_select);
+}
+
+
+function updateHostElement(request, host_json){
+	id = host_json.HOST.ID;
+	element = hostElementArray(host_json);
+	updateSingleElement(element,dataTable_hosts,'#host_'+id);
+}
+
+function deleteHostElement(req){
+	deleteElement(dataTable_hosts,'#host_'+req.request.data);
+}
+
+function addHostElement(request,host_json){
+    id = host_json.HOST.ID;
+	element = hostElementArray(host_json);
+	addElement(element,dataTable_hosts);
+}
+
+function updateHostsView (request,host_list){
+	host_list_json = host_list;
+	host_list_array = []
+
+	$.each(host_list,function(){
+	//Grab table data from the host_list
+		host_list_array.push(hostElementArray(this));
+	});
+
+	updateView(host_list_array,dataTable_hosts);
+	updateHostSelect(host_list);
+	updateDashboard("hosts",host_list_json);
+}
+
+function updateHostInfo(request,host){
+	host_info = host.HOST
+	rendered_info =
+'<div id="host_informations">\
+	<ul>\
+		<li><a href="#info_host">Host information</a></li>\
+		<li><a href="#host_template">Host template</a></li>\
+	</ul>\
+	<div id="info_host">\
+		<table id="info_host_table" class="info_table">\
+			<thead>\
+				<tr><th colspan="2">Host information - '+host_info.NAME+'</th></tr>\
+			</thead>\
+			<tr>\
+				<td class="key_td">ID</td>\
+				<td class="value_td">'+host_info.ID+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">State</td>\
+				<td class="value_td">'+OpenNebula.Helper.resource_state("host",host_info.STATE)+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">Cluster</td>\
+				<td class="value_td">'+host_info.CLUSTER+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">IM MAD</td>\
+				<td class="value_td">'+host_info.IM_MAD+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">VM MAD</td>\
+				<td class="value_td">'+host_info.VM_MAD+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">TM MAD</td>\
+				<td class="value_td">'+host_info.TM_MAD+'</td>\
+			</tr>\
+		</table>\
+		<table id="host_shares_table" class="info_table">\
+			<thead>\
+				<tr><th colspan="2">Host shares</th></tr>\
+			</thead>\
+			<tr>\
+				<td class="key_td">Max Mem</td>\
+				<td class="value_td">'+humanize_size(host_info.HOST_SHARE.MAX_MEM)+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">Used Mem (real)</td>\
+				<td class="value_td">'+humanize_size(host_info.HOST_SHARE.USED_MEM)+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">Used Mem (allocated)</td>\
+				<td class="value_td">'+humanize_size(host_info.HOST_SHARE.MAX_USAGE)+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">Used CPU (real)</td>\
+				<td class="value_td">'+host_info.HOST_SHARE.USED_CPU+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">Used CPU(allocated)</td>\
+				<td class="value_td">'+host_info.HOST_SHARE.CPU_USAGE+'</td>\
+			</tr>\
+			<tr>\
+				<td class="key_td">Running VMs</td>\
+				<td class="value_td">'+host_info.HOST_SHARE.RUNNING_VMS+'</td>\
+			</tr>\
+		</table>\
+	</div>\
+	<div id="host_template">\
+		<table id="host_template_table" class="info_table">\
+		<thead><tr><th colspan="2">Host template</th></tr></thead>'+
+		prettyPrintJSON(host_info.TEMPLATE)+
+		'</table>\
+	</div>\
+</div>';
+    popDialog(rendered_info);
+    $('#host_informations').tabs();
+
+}
+
+//Document ready
+$(document).ready(){
+    
+    //prepare host datatable
+    var dataTable_hosts = $("#datatable_hosts").dataTable({
+      "bJQueryUI": true,
+      "bSortClasses": false,
+      "bAutoWidth":false,
+      "sPaginationType": "full_numbers",
+      "aoColumnDefs": [
+                        { "bSortable": false, "aTargets": ["check"] },
+                        { "sWidth": "60px", "aTargets": [0,4] },
+                        { "sWidth": "35px", "aTargets": [1] },
+                        { "sWidth": "120px", "aTargets": [5,6] }
+                       ]
+    });
+    
+    //preload it
+    dataTable_hosts.fnClearTable();
+    addElement([
+        spinner,
+        '','','','','','',''],dataTable_hosts);
+	OpenNebula.Host.list({success: updateHostsView,error: onError});
+    
+    //set refresh interval
+    setInterval(function(){
+		nodes = $('input:checked',dataTable_hosts.fnGetNodes());
+        filter = $("#datatable_hosts_filter input").attr("value");
+		if (!nodes.length && !filter.length){
+			OpenNebula.Host.list({timeout: true, success: updateHostsView,error: onError});
+		}
+	},interval);
+    
+    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
new file mode 100644
index 0000000000..5baa070b62
--- /dev/null
+++ b/src/sunstone/public/js/sunstone-util.js
@@ -0,0 +1,260 @@
+/* -------------------------------------------------------------------------- */
+/* 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.                                             */
+/* -------------------------------------------------------------------------- */
+
+
+/* Some useful functions for Sunstone default plugins */
+
+function emptyDashboard(){
+    $("#dashboard .value_td span").html(spinner);
+}
+
+function updateDashboard(what,json_info){
+	db = $('#dashboard');
+	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;
+	}
+}
+
+function pad(number,length) {
+    var str = '' + number;
+    while (str.length < length)
+        str = '0' + str;
+    return str;
+}
+
+function pretty_time(time_seconds)
+{
+    var d = new Date();
+    d.setTime(time_seconds*1000);
+
+    var secs = pad(d.getSeconds(),2);
+    var hour = pad(d.getHours(),2);
+    var mins = pad(d.getMinutes(),2);
+    var day = pad(d.getDate(),2);
+    var month = pad(d.getMonth(),2);
+    var year = d.getFullYear();
+
+    return hour + ":" + mins +":" + secs + "&nbsp;" + month + "/" + day + "/" + year;
+}
+
+function humanize_size(value) {
+    if (typeof(value) === "undefined") {
+        value = 0;
+    }
+    var binarySufix = ["K", "M", "G", "T" ];
+    var i=0;
+    while (value > 1024 && i < 3){
+        value = value / 1024;
+        i++;
+    }
+    value = Math.round(value * 10) / 10;
+
+    if (value - Math.round(value) == 0) {
+        value = Math.round(value);
+    }
+
+    var st = value + binarySufix[i];
+    return st;
+}
+
+function deleteElement(data_table,tag){
+	tr = $(tag).parents('tr')[0];
+	data_table.fnDeleteRow(tr);
+    $('input',data_table).trigger("change");
+}
+
+function tableCheckboxesListener(dataTable){
+
+    context = dataTable.parents('form');
+    last_action_b = $('.last_action_button',context);
+    $('.top_button, .list_button',context).button("disable");
+    if (last_action_b.length && last_action_b.val().length){
+        last_action_b.button("disable");
+    };
+    $('.new_button',context).button("enable");
+
+    //listen to changes
+    $('input',dataTable).live("change",function(){
+        dataTable = $(this).parents('table').dataTable();
+        context = dataTable.parents('form');
+        last_action_b = $('.last_action_button',context);
+        nodes = dataTable.fnGetNodes();
+        total_length = nodes.length;
+        checked_length = $('input:checked',nodes).length;
+
+        if (total_length == checked_length){
+            $('.check_all',dataTable).attr("checked","checked");
+        } else {
+            $('.check_all',dataTable).removeAttr("checked");
+        }
+
+        if (checked_length){
+            $('.top_button, .list_button',context).button("enable");
+            if (last_action_b.length && last_action_b.val().length){
+                last_action_b.button("enable");
+            };
+            $('.new_button',context).button("enable");
+        } else {
+            $('.top_button, .list_button',context).button("disable");
+            last_action_b.button("disable");
+            $('.new_button',context).button("enable");
+        }
+    });
+
+}
+
+// Updates a data_table, with a 2D array containing
+// Does a partial redraw, so the filter and pagination are kept
+function updateView(item_list,data_table){
+	if (data_table!=null) {
+		data_table.fnClearTable();
+		data_table.fnAddData(item_list);
+		data_table.fnDraw(false);
+	};
+}
+
+function updateSingleElement(element,data_table,tag){
+	tr = $(tag).parents('tr')[0];
+	position = data_table.fnGetPosition(tr);
+	data_table.fnUpdate(element,position,0);
+    $('input',data_table).trigger("change");
+
+}
+
+// Returns an string in the form key=value key=value ...
+// Does not explore objects in depth.
+function stringJSON(json){
+	str = ""
+	for (field in json) {
+		str+= field + '=' + json[field] + ' ';
+	}
+	return str;
+}
+
+// Returns the running time data
+function str_start_time(vm){
+    return pretty_time(vm.STIME);
+}
+
+
+//Notifications
+function notifySubmit(action, args, extra_param){
+    var action_text = action.replace(/OpenNebula\./,'').replace(/\./,' ');
+
+    var msg = "<h1>Submitted</h1>";
+    msg += action_text + ": " + args;
+    if (extra_param != null)
+        msg += " >> " + extra_param;
+
+    $.jGrowl(msg, {theme: "jGrowl-notify-submit"});
+}
+
+function notifyError(msg){
+    msg = "<h1>Error</h1>" + msg;
+
+    $.jGrowl(msg, {theme: "jGrowl-notify-error", sticky: true });
+}
+
+// Returns an HTML string with the json keys and values in the form
+// key: value<br />
+// It recursively explores objects, and flattens their contents in
+// the result.
+function prettyPrintJSON(template_json){
+	str = ""
+	for (field in template_json) {
+		if (typeof template_json[field] == 'object'){
+			str += prettyPrintJSON(template_json[field]) + '<tr><td></td><td></td></tr>';
+		} else {
+			str += '<tr><td class="key_td">'+field+'</td><td class="value_td">'+template_json[field]+'</td></tr>';
+		};
+	};
+	return str;
+}
+
+//Adds a listener to checks all the elements of a table
+function initCheckAllBoxes(datatable){
+	//not showing nice in that position
+	//$('.check_all').button({ icons: {primary : "ui-icon-check" },
+	//							text : true});
+	$('.check_all',datatable).css({"border":"2px"});
+	$('.check_all',datatable).click(function(){
+		if ($(this).attr("checked")) {
+			$('tbody input:checkbox',
+				$(this).parents("table")).each(function(){
+					$(this).attr("checked","checked");
+			});
+
+		} else {
+			$('tbody input:checkbox',
+				$(this).parents("table")).each(function(){
+					$(this).removeAttr("checked");
+			});			}
+	});
+}
diff --git a/src/sunstone/public/js/sunstone.js b/src/sunstone/public/js/sunstone.js
new file mode 100644
index 0000000000..7c631040af
--- /dev/null
+++ b/src/sunstone/public/js/sunstone.js
@@ -0,0 +1,472 @@
+/* -------------------------------------------------------------------------- */
+/* 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.                                             */
+/* -------------------------------------------------------------------------- */
+
+
+//TODOs: handle confirm and confirm with select dialogs
+
+var cookie = {};
+var username = '';
+var uid = '';
+var spinner = '<img src="/images/ajax-loader.gif" alt="retrieving" class="loading_img"/>';
+
+
+var Sunstone = {
+    
+    
+    "addAction" : function (name,action_obj) {
+        SunstoneCfg.config.actions[name] = action_obj;
+    },
+    
+    "updateAction" : function(action,new_action) {
+        
+    },
+    
+    "removeAction" : function(action) {
+        
+    },
+    
+    "addMainTab" : function(tab_id,title_arg,content_arg) {
+        SunstoneCfg["tabs"][tab_id] = {title: title_arg,
+                                        content: content_arg};
+    },
+    
+    "updateMainTab" : function(tab_id,new_content){
+        
+    },
+    
+    "removeMainTab" : function(tab_id) {
+        
+    },
+    
+    "runAction" : function(action, data_arg, extra_param){
+    
+        var actions = Sunstone.actions;
+        if (!actions[action]){
+            notifyError("Action "+action+" not defined");
+            return;
+        }
+        
+        var action_cfg = actions[action];
+        
+        var call = action_cfg.run;
+        var callback = action_cfg.callback;
+        var err = action_cfg.callback;
+        var notify = action_cfg.notify;
+        
+        
+        //We ease the use of:
+        // * Create call
+        // * Confirm and confirm with select calls
+        // * Calls on multiple elements
+        // * Other calls
+        switch (actions[action].type){
+            
+            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;
+            case "multiple":
+                //run on the list of nodes that come on the data
+                $.each(data_arg,function(){
+                    if (extra_param){
+                        call(this,callback,error)
+                    } else {
+                        call(this,extra_param,callback,error)
+                    }
+                });
+                break;
+            default: 
+                //we have supposedly altered an action and we want it to do
+                //something completely different
+                call(data,extra_param);
+        }
+        
+    },
+    
+    "runActionOnDatatableNodes": function(action,datatable){
+        if (dataTable != null){
+            
+            //Which rows of the datatable are checked?
+            var nodes = $('input:checked',dataTable.fnGetNodes());
+            var data = [];
+            $.each(nodes,function(){
+                data.push($(this).val());
+            }
+            runAction(action,data);
+            
+        } else {
+            notifyError("Unknown datatable");
+        };
+    }//meter coma y seguir aquĆ­
+    
+}
+
+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(){
+    readCookie();
+    setLogin();
+    insertTabs();
+    insertButtons();
+    
+    
+    initListButtons();
+    setupCreateDialogs(); //listener for create
+    setupTips();
+    
+    //action button listener! -> plugins deal with that
+    
+    
+    $('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
+function readCookie(){
+    $.each(document.cookie.split("; "), function(i,e){
+        var e_split = e.split("=");
+        var key = e_split[0];
+        var value = e_split[1];
+        cookie[key] = value;
+    });
+}
+
+//sets the user info in the top bar and creates a listner in the signout button
+function setLogin(){
+    username = cookie["one-user"];
+    uid = cookie["one-user_id"];
+
+    $("#user").html(username);
+    $("#logout").click(function(){
+        OpenNebula.Auth.logout({success:function(){
+                                    window.location.href = "/login";
+                                    }
+                                });
+        return false;
+    });
+}
+
+
+function insertTabs(){
+    var tab_info;
+    for (tab in SunstoneCfg["tabs"]){
+        tab_info = SunstoneCfg["tabs"].tab;
+        $("div.inner_center").append('<div id="'+tab_info.tab_id+'" class="tab"></div>');
+        $('div#'+tab_info.tab_id).html(tab_info.content);
+        
+        $('ul#navigation').append('<li><a href="'+tab_info.tab_id+'">'+tab+'</a></li>');
+        
+    }
+}
+
+
+function insertButtons(){
+    var buttons;
+    var tab_id;
+    var button_code;
+    
+    for (tab in SunstoneCfg["tabs"]){
+        buttons = SunstoneCfg["tabs"][tab].buttons;
+        content = SunstoneCfg["tabs"][tab].content;
+        if ($('div#'+tab+' .action_blocks').length){
+            $.each(buttons,function(){
+                button_code = "";
+                if (!this.condition()) { return true };
+                
+                switch (this.type) {
+                    case "action":
+                        button_code = '<button class="action_button top_button" value="'+this.action+'">'+this.text+'</button>';
+                        break;
+                    case "create":
+                        button_code = '<button class="create top_button" value="'+this.action+'">'+this.text+'</button>';
+                        break;
+                    case "select":
+                        button_code = '<select class="multi_action_slct">';
+                        $.each(this.action,function(){
+                            if (this.condition()){
+                                button_code += '<option value="'+this.value+'">'+this.text+'</option>';
+                            };
+                        });
+                        button_code = '</select>';
+                        break;
+                    
+                }
+                $('div#'+tab+' .action_blocks').append(button_code);
+                
+            });
+        }
+    }
+    
+}
+
+//Converts selects into buttons which show a of actions when clicked
+function initListButtons(){
+
+        //for each multi_action select
+        $('.multi_action_slct').each(function(){
+             //prepare replacement buttons
+            buttonset = $('<div style="display:inline-block;" class="top_button"></div');
+            button1 = $('<button class="last_action_button action_button confirm_button confirm_with_select_button" value="">Previous action</button>').button();
+            button1.attr("disabled","disabled");
+            button2 = $('<button class="list_button" value="">See more</button>').button({
+                text:false,
+                icons: { primary: "ui-icon-triangle-1-s" }
+                });
+            buttonset.append(button1);
+            buttonset.append(button2);
+            buttonset.buttonset();
+
+            //prepare list
+            options = $('option', $(this));
+             list = $('<ul class="action_list"></ul>');
+            $.each(options,function(){
+                classes = $(this).attr("class");
+                item = $('<li></li>');
+                a = $('<a href="#" class="'+classes+'" value="'+$(this).val()+'">'+$(this).text()+'</a>');
+                a.val($(this).val());
+                item.html(a);
+                list.append(item);
+            });
+            list.css({
+                "display":"none"
+            });
+
+
+            //replace the select and insert the buttons
+            $(this).before(buttonset);
+            $(this).parents('.action_blocks').append(list);
+            $(this).remove();
+            //$(this).replaceWith(list);
+
+        });
+
+
+        //listen for events on this buttons and list
+
+        //enable run the last action button
+        $('.action_list li a').click(function(){
+                //enable run last action button
+                prev_action_button = $('.last_action_button',$(this).parents('.action_blocks'));
+                prev_action_button.val($(this).val());
+                prev_action_button.removeClass("confirm_with_select_button");
+                prev_action_button.removeClass("confirm_button");
+                prev_action_button.removeClass("action_button");
+                prev_action_button.addClass($(this).attr("class"));
+                prev_action_button.button("option","label",$(this).text());
+                prev_action_button.button("enable");
+                $(this).parents('ul').hide("blind",100);
+                //return false;
+        });
+
+
+        //Show the list of actions in place
+        $('.list_button').click(function(){
+            $('.action_list',$(this).parents('.action_blocks')).css({
+                "left": $(this).prev().position().left,
+                "top": $(this).prev().position().top+13,
+                "width": $(this).parent().outerWidth()-11
+            });
+            $('.action_list',$(this).parents('.action_blocks')).toggle("blind",100);
+            return false;
+        });
+}
+
+//Sets up all the "+ New Thing" dialogs.
+function setupCreateDialogs(){
+	createHostDialog();
+	createClusterDialog();
+	createVMachineDialog();
+	createVNetworkDialog();
+	createUserDialog();
+    createImageDialog();
+    
+    //Todo listener on "create" class to trigger the right dialog.
+}
+
+//Replaces all class"tip" divs with an information icon that
+//displays the tip information on mouseover.
+function setupTips(){
+		$('div.tip').each(function(){
+				tip = $(this).html();
+				$(this).html('<span class="ui-icon ui-icon-info info_icon"></span>');
+                $(this).append('<span class="tipspan"></span>');
+
+                $(this).append('<span class="ui-icon ui-icon-alert man_icon" />');
+
+
+				$('span.tipspan',this).html(tip);
+                $(this).parent().append('<div class="clear"></div>');
+				$('span.tipspan',this).hide();
+				$('span.info_icon',this).hover(function(e){
+                    var top, left;
+                    top = e.pageY - 15;// - $(this).parents('#create_vm_dialog').offset().top - 15;
+                    left = e.pageX + 15;// - $(this).parents('#create_vm_dialog').offset().left;
+                    $(this).next().css(
+                        {"top":top+"px",
+                        "left":left+"px"});
+					$(this).next().fadeIn();
+				},function(){
+					$(this).next().fadeOut();
+				});
+		});
+}