mirror of
https://github.com/OpenNebula/one.git
synced 2025-01-26 10:03:37 +03:00
Merge remote-tracking branch 'origin/feature-1607' into feature-2854
This commit is contained in:
commit
2dc10c2408
@ -1498,6 +1498,9 @@ 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/jquery.flot.resize.min.js \
|
||||
src/sunstone/public/vendor/flot/jquery.flot.stack.min.js \
|
||||
src/sunstone/public/vendor/flot/jquery.flot.tooltip.min.js \
|
||||
src/sunstone/public/vendor/flot/jquery.flot.JUMlib.min.js \
|
||||
src/sunstone/public/vendor/flot/jquery.flot.gantt.min.js \
|
||||
src/sunstone/public/vendor/flot/LICENSE.txt \
|
||||
src/sunstone/public/vendor/flot/NOTICE"
|
||||
|
||||
|
@ -368,6 +368,30 @@ class SunstoneServer < CloudServer
|
||||
return [200, {:monitoring => result}.to_json]
|
||||
end
|
||||
|
||||
def get_vm_accounting(options)
|
||||
pool = VirtualMachinePool.new(@client)
|
||||
|
||||
filter_flag = options[:userfilter] ? options[:userfilter].to_i : VirtualMachinePool::INFO_ALL
|
||||
start_time = options[:start_time] ? options[:start_time].to_i : -1
|
||||
end_time = options[:end_time] ? options[:end_time].to_i : -1
|
||||
|
||||
acct_options = {
|
||||
:start_time => start_time,
|
||||
:end_time => end_time,
|
||||
:group => options[:group]
|
||||
}
|
||||
|
||||
rc = pool.accounting(filter_flag, acct_options)
|
||||
|
||||
if OpenNebula.is_error?(rc)
|
||||
error = Error.new(rc.message)
|
||||
return [500, error.to_json]
|
||||
end
|
||||
|
||||
return [200, rc.to_json]
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
|
||||
############################################################################
|
||||
|
@ -595,7 +595,32 @@ var OpenNebula = {
|
||||
callback_error(request, OpenNebula.Error(response)) : null;
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
"accounting": function(params, resource, path){
|
||||
var callback = params.success;
|
||||
var callback_error = params.error;
|
||||
var data = params.data;
|
||||
|
||||
var method = "accounting";
|
||||
var request = OpenNebula.Helper.request(resource,method, data);
|
||||
|
||||
var url = path ? path : resource.toLowerCase() + "/accounting";
|
||||
|
||||
$.ajax({
|
||||
url: url,
|
||||
type: "GET",
|
||||
data: data,
|
||||
dataType: "json",
|
||||
success: function(response){
|
||||
return callback ? callback(request, response) : null;
|
||||
},
|
||||
error: function(response){
|
||||
return callback_error ?
|
||||
callback_error(request, OpenNebula.Error(response)) : null;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
"Auth": {
|
||||
@ -984,7 +1009,10 @@ var OpenNebula = {
|
||||
"recover" : function(params){
|
||||
var action_obj = {"with": params.data.extra_param};
|
||||
OpenNebula.Action.simple_action(params,OpenNebula.VM.resource,"recover",action_obj);
|
||||
}
|
||||
},
|
||||
"accounting": function(params){
|
||||
OpenNebula.Action.accounting(params,OpenNebula.VM.resource);
|
||||
},
|
||||
},
|
||||
|
||||
"Group": {
|
||||
|
@ -703,9 +703,16 @@ function updateGroupInfo(request,group){
|
||||
</div>'
|
||||
};
|
||||
|
||||
var accounting_tab = {
|
||||
title: tr("Accounting"),
|
||||
icon: "fa-bar-chart-o",
|
||||
content: '<div id="group_accounting"></div>'
|
||||
};
|
||||
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_info_tab",info_tab);
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_quotas_tab",quotas_tab);
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_providers_tab",providers_tab);
|
||||
Sunstone.updateInfoPanelTab("group_info_panel","group_accouning_tab",accounting_tab);
|
||||
Sunstone.popUpInfoPanel("group_info_panel", 'groups-tab');
|
||||
|
||||
$("#add_rp_button", $("#group_info_panel")).click(function(){
|
||||
@ -715,6 +722,11 @@ function updateGroupInfo(request,group){
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
accountingGraphs(
|
||||
$("#group_accounting","#group_info_panel"),
|
||||
{ fixed_group: info.ID,
|
||||
init_group_by: "user" });
|
||||
}
|
||||
|
||||
function setup_group_resource_tab_content(zone_id, zone_section, str_zone_tab_id, str_datatable_id, selected_group_clusters, group) {
|
||||
|
@ -343,9 +343,10 @@ var provision_user_info = '<div id="provision_user_info" class="hidden section_c
|
||||
'<div class="row">'+
|
||||
'<div class="large-10 large-centered columns">'+
|
||||
'<dl class="tabs text-center" data-tab style="width: 100%">'+
|
||||
'<dd class="active" style="width: 33%;box-shadow: 0px 1px #dfdfdf;"><a href="#provision_info_ssh_key"><i class="fa fa-fw fa-lg fa-key"/> '+ tr("SSH Key") +'</a></dd>'+
|
||||
'<dd style="width: 33%;box-shadow: 0px 1px #dfdfdf;"><a href="#provision_info_quotas"><i class="fa fa-fw fa-lg fa-align-left"/> '+ tr("Quotas") +'</a></dd>'+
|
||||
'<dd style="width: 33%;box-shadow: 0px 1px #dfdfdf;"><a href="#provision_info_settings"><i class="fa fa-fw fa-lg fa-cogs"/> '+ tr("Settings") +'</a></dd>'+
|
||||
'<dd class="active" style="width: 25%;box-shadow: 0px 1px #dfdfdf;"><a href="#provision_info_ssh_key"><i class="fa fa-fw fa-lg fa-key"/> '+ tr("SSH Key") +'</a></dd>'+
|
||||
'<dd style="width: 25%;box-shadow: 0px 1px #dfdfdf;"><a href="#provision_info_acct"><i class="fa fa-fw fa-lg fa-bar-chart-o"/> '+ tr("Accounting") +'</a></dd>'+
|
||||
'<dd style="width: 25%;box-shadow: 0px 1px #dfdfdf;"><a href="#provision_info_quotas"><i class="fa fa-fw fa-lg fa-align-left"/> '+ tr("Quotas") +'</a></dd>'+
|
||||
'<dd style="width: 25%;box-shadow: 0px 1px #dfdfdf;"><a href="#provision_info_settings"><i class="fa fa-fw fa-lg fa-cogs"/> '+ tr("Settings") +'</a></dd>'+
|
||||
'</dl>'+
|
||||
'<br>'+
|
||||
'</div>'+
|
||||
@ -406,6 +407,12 @@ var provision_user_info = '<div id="provision_user_info" class="hidden section_c
|
||||
'</div>'+
|
||||
'</form>'+
|
||||
'</div>'+
|
||||
'<div class="content" id="provision_info_acct">'+
|
||||
'<div class="row">'+
|
||||
'<div id="provision_user_info_acct_div" class="large-9 large-centered columns">'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'</div>'+
|
||||
'<div class="content" id="provision_info_quotas">'+
|
||||
'<div class="row">'+
|
||||
'<div id="provision_user_info_quotas_div" class="large-9 large-centered columns">'+
|
||||
@ -1261,6 +1268,11 @@ function show_provision_user_info_callback(request, response) {
|
||||
|
||||
$('#provision_new_language option[value="'+config['user_config']["lang"]+'"]').attr('selected','selected');
|
||||
$('#provision_user_views_select option[value="'+config['user_config']["default_view"]+'"]').attr('selected','selected');
|
||||
|
||||
accountingGraphs(
|
||||
$("#provision_user_info_acct_div"),
|
||||
{ fixed_user: info.ID,
|
||||
fixed_group_by: "vm" });
|
||||
}
|
||||
|
||||
function show_provision_create_vm() {
|
||||
|
@ -715,10 +715,23 @@ function updateUserInfo(request,user){
|
||||
content : quotas_html
|
||||
};
|
||||
|
||||
var accounting_tab = {
|
||||
title: tr("Accounting"),
|
||||
icon: "fa-bar-chart-o",
|
||||
content: '<div id="user_accounting"></div>'
|
||||
};
|
||||
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_info_tab",info_tab);
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_quotas_tab",quotas_tab);
|
||||
Sunstone.updateInfoPanelTab("user_info_panel","user_accouning_tab",accounting_tab);
|
||||
//Sunstone.updateInfoPanelTab("user_info_panel","user_acct_tab",acct_tab);
|
||||
Sunstone.popUpInfoPanel("user_info_panel", 'users-tab');
|
||||
|
||||
accountingGraphs(
|
||||
$("#user_accounting","#user_info_panel"),
|
||||
{ fixed_user: info.ID,
|
||||
init_group_by: "vm" });
|
||||
|
||||
};
|
||||
|
||||
// Used also from groups-tabs.js
|
||||
|
@ -3902,3 +3902,639 @@ $(document).ready(function(){
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Format time in UTC, YYYY/MM/DD
|
||||
// time is in ms
|
||||
function time_UTC(time){
|
||||
var d = new Date(time);
|
||||
|
||||
return d.getUTCFullYear() + '/' + (d.getUTCMonth()+1) + '/' + d.getUTCDate();
|
||||
}
|
||||
|
||||
// div is a jQuery selector
|
||||
// The following options can be set:
|
||||
// fixed_user fix an owner user ID
|
||||
// fixed_group fix an owner group ID
|
||||
// init_group_by "user", "group", "vm". init the group-by selector
|
||||
// fixed_group_by "user", "group", "vm". set a fixed group-by selector
|
||||
function accountingGraphs(div, opt){
|
||||
|
||||
if(div.html() != ""){
|
||||
return false;
|
||||
}
|
||||
|
||||
div.html(
|
||||
'<div class="row">\
|
||||
<div class="large-3 columns">\
|
||||
'+tr("Time range")+'\
|
||||
</div>\
|
||||
<div class="large-4 left columns">\
|
||||
<input id="acct_start_time" type="text" placeholder="2013/12/30"/>\
|
||||
</div>\
|
||||
<div class="large-4 left columns">\
|
||||
<input id="acct_end_time" type="text" placeholder="'+tr("Today")+'"/>\
|
||||
</div>\
|
||||
<div class="large-1 left columns">\
|
||||
<button class="button radius left success" id="acct_submit" type="submit">'+tr("Go")+'</button>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="row" id="acct_owner">\
|
||||
<div class="large-7 text-right columns">\
|
||||
<input id="acct_owner_all" type="radio" name="acct_owner" value="acct_owner_all" checked/><label for="acct_owner_all">' + tr("All") + '</label>\
|
||||
<input id="acct_owner_group" type="radio" name="acct_owner" value="acct_owner_group" /><label for="acct_owner_group">' + tr("Group") + '</label>\
|
||||
<input id="acct_owner_user" type="radio" name="acct_owner" value="acct_owner_user" /><label for="acct_owner_user">' + tr("User") + '</label>\
|
||||
</div>\
|
||||
<div class="large-5 left columns">\
|
||||
<div id="acct_owner_select"/>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="row" id="acct_group_by_row">\
|
||||
<div class="large-3 columns">\
|
||||
<label for="acct_group_by">' + tr("Group by") + '</label>\
|
||||
</div>\
|
||||
<div class="large-4 left columns">\
|
||||
<select id="acct_group_by" name="acct_group_by">\
|
||||
<option value="user">' + tr("User") + '</option>\
|
||||
<option value="group">' + tr("Group") + '</option>\
|
||||
<option value="vm">' + tr("VM") + '</option>\
|
||||
</select>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="row">\
|
||||
</div>\
|
||||
<div id="acct_placeholder">\
|
||||
<div class="row">\
|
||||
<div class="large-8 large-centered columns">\
|
||||
<div class="text-center">\
|
||||
<span class="fa-stack fa-5x" style="color: #dfdfdf">\
|
||||
<i class="fa fa-cloud fa-stack-2x"></i>\
|
||||
<i class="fa fa-bar-chart-o fa-stack-1x fa-inverse"></i>\
|
||||
</span>\
|
||||
<div id="acct_no_data" class="hidden">\
|
||||
<br>\
|
||||
<p style="font-size: 18px; color: #999">'+
|
||||
tr("There are no accounting records")+
|
||||
'</p>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div id="acct_content" class="hidden">\
|
||||
<div class="row">\
|
||||
<div class="row graph_legend">\
|
||||
<h3 class="subheader"><small>'+tr("CPU hours")+'</small></h3>\
|
||||
</div>\
|
||||
<div class="row">\
|
||||
<div class="large-12 columns centered graph" id="acct_cpu_graph" style="height: 200px;">\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="row">\
|
||||
<div class="row graph_legend">\
|
||||
<h3 class="subheader"><small>'+tr("Memory GB hours")+'</small></h3>\
|
||||
</div>\
|
||||
<div class="row">\
|
||||
<div class="large-12 columns centered graph" id="acct_mem_graph" style="height: 200px;">\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="row">\
|
||||
<div class="row graph_legend">\
|
||||
<h3 class="subheader"><small>'+tr("CPU hours")+'</small></h3>\
|
||||
</div>\
|
||||
<div style="overflow:auto">\
|
||||
<table id="acct_cpu_datatable" class="datatable twelve">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th>'+tr("Date")+'</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody id="tbody_acct_cpu_datatable">\
|
||||
</tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
<div class="row">\
|
||||
<div class="row graph_legend">\
|
||||
<h3 class="subheader"><small>'+tr("Memory GB hours")+'</small></h3>\
|
||||
</div>\
|
||||
<div style="overflow:auto">\
|
||||
<table id="acct_mem_datatable" class="datatable twelve">\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th>'+tr("Date")+'</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody id="tbody_acct_mem_datatable">\
|
||||
</tbody>\
|
||||
</table>\
|
||||
</div>\
|
||||
</div>\
|
||||
</div>');
|
||||
|
||||
if (opt == undefined){
|
||||
opt = {};
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Init start time to 1st of last month
|
||||
//--------------------------------------------------------------------------
|
||||
var d = new Date();
|
||||
|
||||
d.setDate(1);
|
||||
d.setMonth(d.getMonth() - 1);
|
||||
|
||||
$("#acct_start_time", div).val(d.getFullYear() + '/' + (d.getMonth()+1) + '/' + d.getDate());
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// VM owner: all, group, user
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
if (opt.fixed_user != undefined || opt.fixed_group != undefined){
|
||||
$("#acct_owner", div).hide();
|
||||
/*
|
||||
$("input[name='acct_owner']", div).attr("disabled", "disabled");
|
||||
|
||||
$("#acct_owner_select", div).show();
|
||||
|
||||
if(opt.fixed_user != undefined){
|
||||
var text = tr("User") +" " + opt.fixed_user;
|
||||
$("input[value='acct_owner_user']", div).attr("checked", "checked");
|
||||
} else {
|
||||
var text = tr("Group") + " " + opt.fixed_group;
|
||||
$("input[value='acct_owner_group']", div).attr("checked", "checked");
|
||||
}
|
||||
|
||||
$("#acct_owner_select", div).text(text);
|
||||
*/
|
||||
} else {
|
||||
$("input[name='acct_owner']", div).change(function(){
|
||||
var value = $(this).val();
|
||||
|
||||
switch (value){
|
||||
case "acct_owner_all":
|
||||
$("#acct_owner_select", div).hide();
|
||||
break;
|
||||
|
||||
case "acct_owner_group":
|
||||
$("#acct_owner_select", div).show();
|
||||
insertSelectOptions("#acct_owner_select", div, "Group");
|
||||
break;
|
||||
|
||||
case "acct_owner_user":
|
||||
$("#acct_owner_select", div).show();
|
||||
insertSelectOptions("#acct_owner_select", div, "User", -1, false,
|
||||
'<option value="-1">'+tr("<< me >>")+'</option>');
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Init group by select
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
if(opt.init_group_by != undefined){
|
||||
$("#acct_group_by", div).val(opt.init_group_by);
|
||||
}else if(opt.fixed_group_by != undefined){
|
||||
$("#acct_group_by", div).val(opt.fixed_group_by);
|
||||
$("#acct_group_by_row", div).hide();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Submit request
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
$("#acct_submit", div).on("click", function(){
|
||||
var start_time = -1;
|
||||
var end_time = -1;
|
||||
|
||||
var v = $("#acct_start_time", div).val();
|
||||
if (v == ""){
|
||||
notifyError(tr("Time range start is mandatory"));
|
||||
return false;
|
||||
}else{
|
||||
start_time = Date.parse(v+' UTC');
|
||||
|
||||
if (isNaN(start_time)){
|
||||
notifyError(tr("Time range start is not a valid date. It must be YYYY/MM/DD"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// ms to s
|
||||
start_time = start_time / 1000;
|
||||
}
|
||||
|
||||
var v = $("#acct_end_time", div).val();
|
||||
if (v != ""){
|
||||
|
||||
end_time = Date.parse(v+' UTC');
|
||||
|
||||
if (isNaN(end_time)){
|
||||
notifyError(tr("Time range end is not a valid date. It must be YYYY/MM/DD"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// ms to s
|
||||
end_time = end_time / 1000;
|
||||
}
|
||||
|
||||
var options = {
|
||||
"start_time": start_time,
|
||||
"end_time": end_time
|
||||
};
|
||||
|
||||
if (opt.fixed_user != undefined){
|
||||
options.userfilter = opt.fixed_user;
|
||||
} else if (opt.fixed_group != undefined){
|
||||
options.group = opt.fixed_group;
|
||||
} else {
|
||||
var select_val = $("#acct_owner_select .resource_list_select", div).val();
|
||||
|
||||
switch ($("input[name='acct_owner']:checked", div).val()){
|
||||
case "acct_owner_all":
|
||||
break;
|
||||
|
||||
case "acct_owner_group":
|
||||
if(select_val != ""){
|
||||
options.group = select_val;
|
||||
}
|
||||
break;
|
||||
|
||||
case "acct_owner_user":
|
||||
if(select_val != ""){
|
||||
options.userfilter = select_val;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
OpenNebula.VM.accounting({
|
||||
// timeout: true,
|
||||
success: function(req, response){
|
||||
fillAccounting(div, req, response);
|
||||
},
|
||||
error: onError,
|
||||
data: options
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function fillAccounting(div, req, response) {
|
||||
var options = req.request.data[0];
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Time slots
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// start_time is mandatory
|
||||
var start = new Date(options.start_time * 1000);
|
||||
|
||||
var end = new Date();
|
||||
|
||||
if(options.end_time != undefined && options.end_time != -1){
|
||||
var end = new Date(options.end_time * 1000)
|
||||
}
|
||||
|
||||
// granularity of 1 day
|
||||
var times = [];
|
||||
|
||||
var tmp_time = start;
|
||||
|
||||
// End time is the start of the last time slot. We use <=, to
|
||||
// add one extra time step
|
||||
while (tmp_time <= end) {
|
||||
times.push(tmp_time.getTime());
|
||||
|
||||
// day += 1
|
||||
tmp_time.setUTCDate( tmp_time.getUTCDate() + 1 );
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Flot options
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
var options = {
|
||||
colors: ["#0098C3","#0A00C2","#AB00C2","#C20037","#C26B00","#78C200","#00C22A","#00B8C2"],
|
||||
|
||||
xaxis : {
|
||||
mode: "time",
|
||||
timeformat: "%y/%m/%d",
|
||||
color: "#999",
|
||||
size: 8,
|
||||
minTickSize: [1, "day"]
|
||||
},
|
||||
yaxis : { labelWidth: 50,
|
||||
min: 0,
|
||||
color: "#999",
|
||||
size: 8
|
||||
},
|
||||
series: {
|
||||
bars: {
|
||||
show: true,
|
||||
lineWidth: 1,
|
||||
fill: true,
|
||||
barWidth: 24*60*60*1000 * 0.8,
|
||||
align: "center"
|
||||
},
|
||||
stack: true
|
||||
},
|
||||
legend : {
|
||||
show : false
|
||||
},
|
||||
grid: {
|
||||
borderWidth: 1,
|
||||
borderColor: "#cfcfcf",
|
||||
hoverable: true
|
||||
},
|
||||
tooltip: true,
|
||||
tooltipOpts: {
|
||||
content: "%x | %s | %y"
|
||||
}
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Group by
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// TODO: Allow to change group by dynamically, instead of calling oned again
|
||||
|
||||
switch ($("#acct_group_by", div).val()){
|
||||
case "user":
|
||||
var group_by_fn = function(history){
|
||||
return history.VM.UID;
|
||||
}
|
||||
|
||||
var group_by_prefix = tr("User")+" ";
|
||||
|
||||
break;
|
||||
|
||||
case "group":
|
||||
var group_by_fn = function(history){
|
||||
return history.VM.GID;
|
||||
}
|
||||
|
||||
var group_by_prefix = tr("Group")+" ";
|
||||
|
||||
break;
|
||||
|
||||
case "vm":
|
||||
var group_by_fn = function(history){
|
||||
return history.OID;
|
||||
}
|
||||
|
||||
var group_by_prefix = tr("VM")+" ";
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Filter history entries
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
// TODO filter
|
||||
// True to proccess, false to discard
|
||||
var filter_by_fn = function(history){
|
||||
// return history.OID == 3605 || history.OID == 2673;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Process data series for flot
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
var series = {};
|
||||
|
||||
$("#acct_no_data", div).hide();
|
||||
|
||||
if(response.HISTORY_RECORDS == undefined){
|
||||
$("#acct_placeholder", div).show();
|
||||
$("#acct_content", div).hide();
|
||||
|
||||
$("#acct_no_data", div).show();
|
||||
return false;
|
||||
}
|
||||
|
||||
$.each(response.HISTORY_RECORDS.HISTORY, function(index, history){
|
||||
|
||||
/*
|
||||
if(!filter_by_fn(history)){
|
||||
return true; //continue
|
||||
}
|
||||
*/
|
||||
var group_by = group_by_fn(history);
|
||||
|
||||
if (series[group_by] == undefined){
|
||||
series[group_by] = {};
|
||||
|
||||
series[group_by][times[0]] = {};
|
||||
series[group_by][times[times.length-2]] = {};
|
||||
|
||||
series[group_by][times[0]].CPU_HOURS = 0;
|
||||
series[group_by][times[times.length-2]].CPU_HOURS = 0;
|
||||
|
||||
series[group_by][times[0]].MEM_HOURS = 0;
|
||||
series[group_by][times[times.length-2]].MEM_HOURS = 0;
|
||||
}
|
||||
|
||||
var serie = series[group_by];
|
||||
|
||||
for (var i = 0; i<times.length-1; i++){
|
||||
|
||||
var t = times[i];
|
||||
var t_next = times[i+1];
|
||||
|
||||
if( (history.ETIME*1000 > t || history.ETIME == 0) &&
|
||||
(history.STIME != 0 && history.STIME*1000 <= t_next) ) {
|
||||
|
||||
var stime = t;
|
||||
if(history.STIME != 0){
|
||||
stime = Math.max(t, history.STIME*1000);
|
||||
}
|
||||
|
||||
var etime = t_next;
|
||||
if(history.ETIME != 0){
|
||||
etime = Math.min(t_next, history.ETIME*1000);
|
||||
}
|
||||
|
||||
var n_hours = (etime - stime) / 1000 / 60 / 60;
|
||||
|
||||
if(serie[t] == undefined){
|
||||
serie[t] = {};
|
||||
serie[t].CPU_HOURS = 0;
|
||||
serie[t].MEM_HOURS = 0;
|
||||
}
|
||||
|
||||
// --- cpu ---
|
||||
|
||||
var val = parseFloat(history.VM.TEMPLATE.CPU) * n_hours;
|
||||
|
||||
if (!isNaN(val)){
|
||||
serie[t].CPU_HOURS += val;
|
||||
}
|
||||
|
||||
// --- mem ---
|
||||
|
||||
var val = parseInt(history.VM.TEMPLATE.MEMORY)/1024 * n_hours;
|
||||
|
||||
if (!isNaN(val)){
|
||||
serie[t].MEM_HOURS += val;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Create series, draw plots
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
var cpu_plot_series = [];
|
||||
var mem_plot_series = [];
|
||||
|
||||
$.each(series, function(key, val){
|
||||
var cpu_data = [];
|
||||
var mem_data = [];
|
||||
|
||||
$.each(val, function(time,num){
|
||||
cpu_data.push([parseInt(time),num.CPU_HOURS]);
|
||||
mem_data.push([parseInt(time),num.MEM_HOURS]);
|
||||
});
|
||||
|
||||
cpu_plot_series.push(
|
||||
{
|
||||
label: group_by_prefix+key,
|
||||
data: cpu_data
|
||||
});
|
||||
|
||||
mem_plot_series.push(
|
||||
{
|
||||
label: group_by_prefix+key,
|
||||
data: mem_data
|
||||
});
|
||||
});
|
||||
|
||||
var cpu_plot = $.plot($("#acct_cpu_graph", div), cpu_plot_series, options);
|
||||
var mem_plot = $.plot($("#acct_mem_graph", div), mem_plot_series, options);
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Init dataTables
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
$("#acct_cpu_datatable",div).dataTable().fnClearTable();
|
||||
$("#acct_cpu_datatable",div).dataTable().fnDestroy();
|
||||
|
||||
$("#acct_cpu_datatable thead",div).remove();
|
||||
$("#acct_cpu_datatable",div).width("1px");
|
||||
|
||||
|
||||
$("#acct_mem_datatable",div).dataTable().fnClearTable();
|
||||
$("#acct_mem_datatable",div).dataTable().fnDestroy();
|
||||
|
||||
$("#acct_mem_datatable thead",div).remove();
|
||||
$("#acct_mem_datatable",div).width("1px");
|
||||
|
||||
|
||||
cpu_plot_data = cpu_plot.getData();
|
||||
mem_plot_data = mem_plot.getData();
|
||||
|
||||
var thead =
|
||||
'<thead>\
|
||||
<tr>\
|
||||
<th>'+tr("Date UTC")+'</th>\
|
||||
<th>'+tr("Total")+'</th>';
|
||||
|
||||
$.each(cpu_plot_data, function(i, serie){
|
||||
thead += '<th style="border-bottom: '+serie.color+' 4px solid !important;'+
|
||||
' border-left: 10px solid white; border-right: 5px solid white">'+
|
||||
serie.label+'</th>';
|
||||
});
|
||||
|
||||
thead += '</tr></thead>';
|
||||
|
||||
$("#acct_cpu_datatable",div).append(thead);
|
||||
|
||||
thead =
|
||||
'<thead>\
|
||||
<tr>\
|
||||
<th>'+tr("Date UTC")+'</th>\
|
||||
<th>'+tr("Total")+'</th>';
|
||||
|
||||
$.each(mem_plot_data, function(i, serie){
|
||||
thead += '<th style="border-bottom: '+serie.color+' 4px solid !important;'+
|
||||
' border-left: 10px solid white; border-right: 5px solid white">'+
|
||||
serie.label+'</th>';
|
||||
});
|
||||
|
||||
thead += '</tr></thead>';
|
||||
|
||||
$("#acct_mem_datatable",div).append(thead);
|
||||
|
||||
|
||||
var cpu_dataTable_data = [];
|
||||
var mem_dataTable_data = [];
|
||||
|
||||
for (var i = 0; i<times.length-1; i++){
|
||||
var t = times[i];
|
||||
|
||||
var cpu_row = [];
|
||||
var mem_row = [];
|
||||
|
||||
var time_st = time_UTC(t);
|
||||
|
||||
cpu_row.push(time_st);
|
||||
mem_row.push(time_st);
|
||||
|
||||
cpu_row.push(0);
|
||||
mem_row.push(0);
|
||||
|
||||
var cpu_total = 0;
|
||||
var mem_total = 0;
|
||||
|
||||
$.each(series, function(key, val){
|
||||
var v = val[t];
|
||||
|
||||
if(v != undefined){
|
||||
var cpu_v = (v.CPU_HOURS * 100).toFixed() / 100;
|
||||
var mem_v = (v.MEM_HOURS * 100).toFixed() / 100;
|
||||
|
||||
cpu_total += cpu_v;
|
||||
mem_total += mem_v;
|
||||
|
||||
cpu_row.push(cpu_v);
|
||||
mem_row.push(mem_v);
|
||||
} else {
|
||||
cpu_row.push(0);
|
||||
mem_row.push(0);
|
||||
}
|
||||
});
|
||||
|
||||
cpu_row[1] = cpu_total;
|
||||
mem_row[1] = mem_total;
|
||||
|
||||
cpu_dataTable_data.push(cpu_row);
|
||||
mem_dataTable_data.push(mem_row);
|
||||
}
|
||||
|
||||
var acct_cpu_dataTable = $("#acct_cpu_datatable",div).dataTable({
|
||||
"bSortClasses" : false,
|
||||
"bDeferRender": true,
|
||||
"aoColumnDefs": [
|
||||
{ "bSortable": false, "aTargets": ['_all'] },
|
||||
]
|
||||
});
|
||||
|
||||
var acct_mem_dataTable = $("#acct_mem_datatable",div).dataTable({
|
||||
"bSortClasses" : false,
|
||||
"bDeferRender": true,
|
||||
"aoColumnDefs": [
|
||||
{ "bSortable": false, "aTargets": ['_all'] },
|
||||
]
|
||||
});
|
||||
|
||||
acct_cpu_dataTable.fnAddData(cpu_dataTable_data);
|
||||
acct_mem_dataTable.fnAddData(mem_dataTable_data);
|
||||
|
||||
$("#acct_placeholder", div).hide();
|
||||
$("#acct_content", div).show();
|
||||
}
|
520
src/sunstone/public/vendor/flot/jquery.flot.JUMlib.js
vendored
Normal file
520
src/sunstone/public/vendor/flot/jquery.flot.JUMlib.js
vendored
Normal file
@ -0,0 +1,520 @@
|
||||
/*
|
||||
* The MIT License
|
||||
|
||||
Copyright (c) 2012, 2013 by Juergen Marsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
(function ($) {
|
||||
"use strict";
|
||||
var pluginName = "JUMlib", pluginVersion = "0.5";
|
||||
function between(v,limit1,limit2){
|
||||
if(limit2 > limit1){ return (v >= limit1 && v <= limit2); }
|
||||
else{ return(v >=limit2 && v <= limit1); }
|
||||
}
|
||||
function getMinMax(data,dataIndex){
|
||||
var mn,mx,df,dI;
|
||||
if(dataIndex){ dI = dataIndex} else{ dI = 1;}
|
||||
mn = Number.POSITIVE_INFINITY;
|
||||
mx = Number.NEGATIVE_INFINITY;
|
||||
for(var i = 0; i < data.length; i++){
|
||||
mn = Math.min(mn, data[i][dI]);
|
||||
mx = Math.max(mx, data[i][dI]);
|
||||
}
|
||||
df = mx - mn;
|
||||
return {min: mn, max: mx, diff: df};
|
||||
}
|
||||
function showHover(event,pos,item,showAlways,createText){
|
||||
var txt;
|
||||
if (item) {
|
||||
var data = item.series.data[item.dataIndex];
|
||||
if(createText){ txt = createText(data);}
|
||||
else {
|
||||
txt = "X:" + data[0] + "<br>Y:" + data[1];
|
||||
if(data.length > 2) { for(var i = 2; i < data.length; i++){ txt += "<br>" + data[i]; } }
|
||||
}
|
||||
showTooltip(pos.pageX, pos.pageY,txt);
|
||||
}
|
||||
else {
|
||||
if(showAlways === true){
|
||||
txt = pos.x1 + " / " + pos.y1;
|
||||
showTooltip(pos.pageX,pos.pageY,txt);
|
||||
}
|
||||
else {$("#FLOTtooltip").remove();}
|
||||
}
|
||||
}
|
||||
function showTooltip(x, y, contents){
|
||||
$("#FLOTtooltip").remove();
|
||||
$('<div id="FLOTtooltip">' + contents + '</div>').css(
|
||||
{ position: 'absolute',display: 'none',top: y + 5,left: x + 5,
|
||||
border: '1px solid #fdd',padding: '2px','background-color': '#fee',opacity: 0.80
|
||||
}).appendTo("body").fadeIn(200);
|
||||
}
|
||||
function loadScripts(scripts,maxWait,callback){
|
||||
var loadedScripts = {},defs = [];
|
||||
for(var i = 0; i < scripts.length; i++){ defs.push(loadScript(scripts[i].path,scripts[i].name)); }
|
||||
$.when.apply(null,defs).then(function(){callback(loadedScripts);});
|
||||
function loadScript(path,name){
|
||||
var dfd = $.Deferred(),t;
|
||||
t = setInterval(function(){clearInterval(t);dfd.reject();},maxWait);
|
||||
$.getScript(path).done(loaded).fail(errorFound);
|
||||
return dfd.promise();
|
||||
function loaded(){ loadedScripts[name] = true;dfd.resolve();}
|
||||
function errorFound(e,f,g){console.log(path,e); loadedScripts[name] = false;dfd.reject();}
|
||||
}
|
||||
}
|
||||
function loadJSON(scripts,maxWait,callback){
|
||||
var loadedJSON = {},defs = [];
|
||||
for(var i = 0;i < scripts.length; i++){ defs.push(loadJSON(scripts[i].path,scripts[i].name)); }
|
||||
$.when.apply(null,defs).then(function(){ callback(loadedJSON);});
|
||||
function loadJSON(path,name){
|
||||
var dfd = $.Deferred(),t;
|
||||
t = setInterval(function(){clearInterval(t);dfd.reject();},maxWait);
|
||||
$.getJSON(path,function(data){
|
||||
loadedJSON[name] = {data:data,name:name,loaded:true};
|
||||
}).done(loaded).fail(errorFound);
|
||||
return dfd.promise();
|
||||
function loaded(){ dfd.resolve(); }
|
||||
function errorFound(e,f,g){ loadedJSON[name] = {name:name,loaded:false};dfd.reject();}
|
||||
}
|
||||
}
|
||||
|
||||
function createQuartile(data, index, indexName){
|
||||
var q0 = [], q1 = [],q2 = [],q3 = [],q4 = [], v = [], i1, i2, i3, i4, p;
|
||||
i1 = (0.25 * data.length).toFixed(0); i2 = (0.5 * data.length).toFixed(0);
|
||||
i3 = (0.75 * data.length).toFixed(0); i4 = data.length - 1;
|
||||
for (var j = 0; j < data[0].length; j++){
|
||||
p = [];
|
||||
for (var i = 0; i < data.length; i++) { p.push(data[i][j]); }
|
||||
p.sort(function(a,b){return a - b;} );
|
||||
q1.push([j,p[i1]]); q2.push([j,p[i2]]); q3.push([j,p[i3]]); q4.push([j,p[i4]]);
|
||||
q0.push([j,p[0]]); v.push([j,data[index][j]]);
|
||||
}
|
||||
var r = [ { data: q4}, { data: q3}, { data: q2}, { data: q1}, {data: q0, color: "#ffffff" },
|
||||
{label: indexName, points: {show:true}, lines: { fill: null, steps: false}, data: v}];
|
||||
return r;
|
||||
}
|
||||
function createPercentile(data, index, indexName, percentiles){
|
||||
var percentile = [], val = [], indexes = [], p,j,i;
|
||||
if(percentiles.length){
|
||||
indexes.push([0]);
|
||||
percentile.push([]);
|
||||
for(j = 0;j < percentiles.length;j++){
|
||||
indexes.push(parseInt(data.length * percentiles[j],0));
|
||||
percentile.push([]);
|
||||
}
|
||||
indexes.push(data.length - 1);
|
||||
}
|
||||
else{
|
||||
for(j = 0;j < percentiles; j++){
|
||||
indexes.push(parseInt(data.length / percentiles * j,0));
|
||||
percentile.push([]);
|
||||
}
|
||||
indexes.push(data.length - 1);
|
||||
}
|
||||
percentile.push([]);
|
||||
for(j = 0; j < data[0].length; j++){
|
||||
p = [];
|
||||
for(i = 0; i < data.length; i++){ p.push(data[i][j]); }
|
||||
p.sort(function(a,b){return a-b;});
|
||||
for(i = 0; i < percentile.length; i++ ) { percentile[i].push([j,p[indexes[i]]]); }
|
||||
val.push([j,data[index][j]]);
|
||||
}
|
||||
var r = [];
|
||||
for(j = percentile.length - 1; j > 0 ; j--){ r.push({ data: percentile[j] });}
|
||||
r.push({data: percentile[0], color:"#ffffff"});
|
||||
r.push({label: indexName, points: {show: true}, lines: { fill: null, steps: false}, data:val});
|
||||
return r;
|
||||
}
|
||||
function createSimiliarity(data1, data2, mode){
|
||||
var r = [];
|
||||
var d1 = normalize(data1);
|
||||
var d2 = normalize(data2);
|
||||
var d;
|
||||
for (var i = 0; i < d1.length; i++){
|
||||
switch (mode){
|
||||
case "diff":
|
||||
d = d1[i][1] - d2[i][1];
|
||||
break;
|
||||
case "abs":
|
||||
d = Math.abs(d1[i][1] - d2[i][1]);
|
||||
break;
|
||||
default:
|
||||
d = 0;
|
||||
}
|
||||
r.push([d1[i][0],d]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
function createWaterfall(data, colors){ //convert waterfalldata to 4 Bars, d1 for fixed bars, d2 for invisible bar
|
||||
var d1 = [], d2 = [], d3 = [], d4 = [], p = 0, mn = Number.POSITIVE_INFINITY,i; // d3 for negative bars and d4 for positive bars
|
||||
var dx = data;
|
||||
for(i = 0; i < dx.length; i++) {
|
||||
if(dx[i][2]){
|
||||
if(typeof dx[i][1] === "undefined") { d1.push([i,p]); }
|
||||
else { d1.push([i,dx[i][1]]); p = dx[i][1]; }
|
||||
}
|
||||
else{
|
||||
if(dx[i][1] > 0) { d4.push([i,- dx[i][1]]);p = p + dx[i][1];d2.push([i,p]);d3.push([i,0]);}
|
||||
else {d3.push([i,- dx[i][1]]);p = p + dx[i][1];d2.push([i,p]);}
|
||||
}
|
||||
mn = Math.min(mn,p);
|
||||
}
|
||||
var ticks = [];
|
||||
for(i = 0; i < data.length; i++){ ticks.push([i,data[i][0]]);}
|
||||
var dr = {
|
||||
data: [
|
||||
{ data: d1, color: colors.fixed },
|
||||
{ data: d2, bars: { show: false }, lines: { show: false } },
|
||||
{ data: d3, color: colors.negative },
|
||||
{ data: d4, color: colors.positive}
|
||||
],
|
||||
ticks: ticks,
|
||||
yaxismin: mn
|
||||
};
|
||||
return dr;
|
||||
}
|
||||
function avg(data,range){
|
||||
var r = [],rd = [],i1,s;
|
||||
for(var i = 0; i < data.length; i++){
|
||||
if(i < range){ i1 = 0;} else{ i1 = i - range + 1;}
|
||||
rd = [];
|
||||
rd.push(data[i][0]);
|
||||
for(var k = 1; k < data[i].length; k++){
|
||||
s = 0;
|
||||
for(var j = i1; j <= i; j++){ s += data[j][k];}
|
||||
rd.push(s / (i - i1 + 1));
|
||||
}
|
||||
r.push(rd);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
function max(data,range){
|
||||
var r = [], rd = [], i1, mx;
|
||||
for(var i = 0; i < data.length; i++){
|
||||
if(i < range) {i1 = 0;} else {i1 = i - range + 1;}
|
||||
rd = [];
|
||||
rd.push(data[i][0]);
|
||||
for(var k = 1; k < data[i].length; k++){
|
||||
mx = - Number.MAX_VALUE;
|
||||
for(var j = i1; j <= i; j++){ if(data[j][k] > mx){ mx = data[j][k]; } }
|
||||
rd.push(mx);
|
||||
}
|
||||
r.push(rd);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
function min(data,range){
|
||||
var r = [], rd = [], i1, mn;
|
||||
for(var i = 0; i < data.length; i++){
|
||||
if(i < range){ i1 = 0;} else{ i1 = i - range + 1;}
|
||||
rd = [];
|
||||
rd.push(data[i][0]);
|
||||
for(var k = 1; k < data[i].length; k++){
|
||||
mn = Number.MAX_VALUE;
|
||||
for(var j = i1; j <= i; j++){ if(data[j][k] < mn){ mn = data[j][k]; } }
|
||||
rd.push(mn);
|
||||
}
|
||||
r.push(rd);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
function sort(data,sortOrder,sortfnc){
|
||||
var d = [];
|
||||
for(var i = 0; i < data.length; i++){ d.push(data[i]);}
|
||||
if(sortfnc){ d.sort(sortfnc); }
|
||||
else{
|
||||
if (sortOrder === "a"){ d.sort(mysorta); } else { d.sort(mysortd); }
|
||||
}
|
||||
return d;
|
||||
function mysorta(a,b){ return a[1] - b[1]; }
|
||||
function mysortd(a,b){ return b[1] - a[1]; }
|
||||
}
|
||||
function sortTicks(data,sortOrder,sortfnc){
|
||||
var d = sort(data,sortOrder,sortfnc);
|
||||
for(var i = 0; i < d.length; i++){d[i][0] = i; }
|
||||
return { data:d, ticks:getTicks(d) };
|
||||
}
|
||||
function pareto(data,otherLabel,showOthers,topN,topPercent){
|
||||
var d = [],othersLabel="Others",showothers = true,i,dn = [];
|
||||
d = sort(data,"d");
|
||||
if(otherLabel.length > 0){ othersLabel = otherLabel;}
|
||||
showothers = showOthers;
|
||||
if(topN){
|
||||
var s;
|
||||
for(i = 0;i < topN; i++){ dn.push(d[i]); }
|
||||
s = 0;
|
||||
for(i = topN;i < d.length; i++){ s+=d[i][1]; }
|
||||
if(showothers){ dn.push([topN, s,othersLabel]);}
|
||||
d = dn;
|
||||
}
|
||||
else if(topPercent){
|
||||
var datasum = 0, datar = 0, datao = 0,j;
|
||||
for(i = 0; i < d.length;i++){ datasum += d[i][1];}
|
||||
datasum = datasum * topPercent / 100;
|
||||
for(i = 0; i < d.length; i++){
|
||||
if (datar < datasum) {
|
||||
dn.push(d[i]);
|
||||
datar += d[i][1];
|
||||
j = i;
|
||||
}
|
||||
else{ datao += d[i][1]; }
|
||||
}
|
||||
j++;
|
||||
if(showothers){ dn.push([j,datao,othersLabel]);}
|
||||
d = dn;
|
||||
}
|
||||
for(i = 0; i < d.length; i++){d[i][0] = i; }
|
||||
return { data:d, ticks:getTicks(d) };
|
||||
}
|
||||
function getTicks(d){
|
||||
var t = [];
|
||||
for(var i = 0; i < d.length; i++){
|
||||
if(d[i][2]){ t.push([d[i][0], d[i][2]]);} else{ t.push(d[i][0], d[i][0]);}
|
||||
}
|
||||
return t;
|
||||
}
|
||||
function normalize(data){
|
||||
var minmax, d;var r = [];
|
||||
minmax = getMinMax(data);
|
||||
for(var i = 0; i < data.length; i++){
|
||||
d = (data[i][1] - minmax.min) / minmax.diff * 100;
|
||||
r.push([data[i][0],d]);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
function combineData(data,ticks){
|
||||
var r = [];
|
||||
for(var i = 0; i < data.length; i++){
|
||||
var s = [];
|
||||
for(var j = 0; j < data[i].length; j++){
|
||||
var d = [ ticks[j], data[i][j] ];
|
||||
s.push(d);
|
||||
}
|
||||
r.push(s);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
function createFont(placeholder){
|
||||
var f = {
|
||||
style: placeholder.css("font-style"),
|
||||
size: Math.round(0.8 * (+placeholder.css("font-size").replace("px", "") || 13)),
|
||||
variant: placeholder.css("font-variant"),
|
||||
weight: placeholder.css("font-weight"),
|
||||
family: placeholder.css("font-family")
|
||||
};
|
||||
return f;
|
||||
}
|
||||
function createColors(options,neededColors){
|
||||
// this is copied code from jquery.flot.js in fillInSeriesOptions
|
||||
var c, colors = [], colorPool = options.colors,
|
||||
colorPoolSize = colorPool.length, variation = 0;
|
||||
for(var i = 0; i < colorPoolSize; i++){ colors[i] = colorPool[i]; }
|
||||
if(colorPoolSize < neededColors){
|
||||
for (i = colorPoolSize; i < neededColors; i++) {
|
||||
c = $.color.parse(colorPool[i % colorPoolSize] || "#666");
|
||||
if (i % colorPoolSize === 0 && i) {
|
||||
if (variation >= 0) {
|
||||
if (variation < 0.5) { variation = -variation - 0.2; } else{ variation = 0;}
|
||||
}
|
||||
else {variation = -variation;}
|
||||
}
|
||||
colors[i] = c.scale('rgb', 1 + variation).toString();
|
||||
}
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
function getColor(colorData){ //based on a patch from Martin Thorsen Ranang from Nov 2012
|
||||
var c;
|
||||
if(typeof colorData === "object"){
|
||||
if(typeof colorData.dataIndex !== "undefined"){
|
||||
if(typeof colorData.serie.data[colorData.dataIndex].color !== "undefined"){
|
||||
c = getColorL(colorData.serie.data[colorData.dataIndex].color);
|
||||
}
|
||||
else{ c = colorData.colors[colorData.dataIndex]; }
|
||||
}
|
||||
else{
|
||||
if(typeof colorData.serieIndex !== "undefined"){
|
||||
if(typeof colorData.serie.color !== "undefined"){ c = getColorL(colorData.serie.color);}
|
||||
else{ c = colorData.colors[colorData.serieIndex];}
|
||||
}
|
||||
else{
|
||||
if(typeof colorData.color !== "undefined"){c = getColorL(colorData.color);}
|
||||
else {c = "darkgreen"; }
|
||||
}
|
||||
}
|
||||
}
|
||||
else{ c = getColorL(colorData); }
|
||||
return c;
|
||||
function getColorL(color){
|
||||
var c;
|
||||
if(typeof color === "object"){
|
||||
if(typeof color.image !== "undefined"){
|
||||
c = colorData.ctx.createPattern(color.image,color.repeat);
|
||||
}
|
||||
else{
|
||||
if(colorData.radius){
|
||||
c = colorData.ctx.createRadialGradient(colorData.left,colorData.top,0,
|
||||
colorData.left,colorData.top,colorData.radius);
|
||||
}
|
||||
else { c = colorData.ctx.createLinearGradient(0,0,colorData.width,colorData.height);}
|
||||
for(var i = 0; i < color.colors.length; i++){
|
||||
var cl = color.colors[i];
|
||||
if(typeof cl !== "string"){
|
||||
var co = $.color.parse(colorData.defaultColor);
|
||||
if(color.brightness !== null){ cl = co.scale("rgb",color.brightness);}
|
||||
if(color.opacity !== null){ co *= color.opacity;}
|
||||
cl = co.toString();
|
||||
}
|
||||
c.addColorStop(i / (color.colors.length - 1),cl);
|
||||
}
|
||||
}
|
||||
}
|
||||
else{ if(typeof color === "string"){ c = color; } else { c = colorData.colors[color]; } }
|
||||
return c;
|
||||
}
|
||||
}
|
||||
function loadImages(images,maxWait,callback){
|
||||
var loadedImg = {},defs = [];
|
||||
for(var i = 0; i < images.length; i++){ defs.push(loadImage(images[i])); }
|
||||
$.when.apply(null,defs).then(function(){callback(loadedImg);});
|
||||
function loadImage(img){
|
||||
var dfd = $.Deferred(),t,url;
|
||||
url = img.path + img.name + "." + img.type;
|
||||
t = setInterval(function(){clearInterval(t);dfd.reject();},maxWait);
|
||||
$('<img />').attr('src',url).load(loaded).error(errorFound);
|
||||
return dfd.promise();
|
||||
function loaded(){ loadedImg[img.name] = this;dfd.resolve();}
|
||||
function errorFound(e,f,g){console.log(url,e); loadedImg[img.name] = null;dfd.reject();}
|
||||
}
|
||||
}
|
||||
function getCanvases(placeholder){
|
||||
var canvases = {
|
||||
background:$(placeholder).children(".flot-background"),
|
||||
base:$(placeholder).children(".flot-base"),
|
||||
overlay:$(placeholder).children(".flot-overlay")
|
||||
};
|
||||
return canvases;
|
||||
}
|
||||
function extendEmpty(org,ext){
|
||||
for(var i in ext){
|
||||
if(!org[i]){ org[i] = ext[i];}
|
||||
else{
|
||||
if(typeof ext[i] === "object"){
|
||||
extendEmpty(org[i],ext[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function drawLines(plot,lines){
|
||||
var offset,series,ctx;
|
||||
offset = plot.getPlotOffset();
|
||||
series = plot.getData();
|
||||
ctx = plot.getCanvas().getContext("2d");
|
||||
ctx.translate(offset.left,offset.top);
|
||||
for(var i = 0; i < lines.length; i++){
|
||||
var from = series[lines[i].from.seriesIndex], to = series[lines[i].to.seriesIndex];
|
||||
var fl = lines[i].from, tl = lines[i].to;
|
||||
if(!fl.dataFieldX){ fl.dataFieldX = 0;}
|
||||
if(!fl.dataFieldY){ fl.dataFieldY = 1;}
|
||||
if(!tl.dataFieldX){ tl.dataFieldX = 0;}
|
||||
if(!tl.dataFieldY){ tl.dataFieldY = 1;}
|
||||
var fromPos = {xaxis:from.xaxis, yaxis:from.yaxis, x:from.data[fl.dataIndex][fl.dataFieldX], y:from.data[fl.dataIndex][fl.dataFieldY]},
|
||||
toPos = {xaxis:to.xaxis, yaxis:to.yaxis, x:to.data[tl.dataIndex][tl.dataFieldX], y:to.data[tl.dataIndex][tl.dataFieldY]},
|
||||
lineStyle = {strokeStyle:"red", lineWidth:5};
|
||||
drawLine(plot,ctx,fromPos,toPos,lineStyle);
|
||||
}
|
||||
}
|
||||
function drawLine(plot,ctx,fromPos,toPos,lineStyle){
|
||||
var xf,yf,xt,yt;
|
||||
xf = fromPos.xaxis.p2c(fromPos.x);
|
||||
yf = fromPos.yaxis.p2c(fromPos.y);
|
||||
xt = toPos.xaxis.p2c(toPos.x);
|
||||
yt = toPos.yaxis.p2c(toPos.y);
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = lineStyle.strokeStyle;
|
||||
ctx.lineWidth = lineStyle.lineWidth;
|
||||
ctx.moveTo(xf,yf);
|
||||
ctx.lineTo(xt,yt);
|
||||
ctx.stroke();
|
||||
}
|
||||
function drawRect(plot,ctx,xaxis,yaxis,boxDim,boxStyle){
|
||||
var boxC = {x: xaxis.p2c(boxDim.x),y: yaxis.p2c(boxDim.y),
|
||||
width: xaxis.p2c((boxDim.x + boxDim.width)) - xaxis.p2c(boxDim.x),
|
||||
height: yaxis.p2c(boxDim.y + boxDim.height) - yaxis.p2c(boxDim.y)};
|
||||
switch(boxStyle.mode){
|
||||
case "image": drawImage(plot,ctx,boxC,boxStyle); break;
|
||||
case "color": drawColor(plot,ctx,boxC,boxStyle); break;
|
||||
case "userdefined": boxStyle.boxDraw(plot,ctx,boxC,boxStyle); break;
|
||||
default: drawColor(plot,ctx,boxC,boxStyle);
|
||||
}
|
||||
function drawImage(plot,ctx,boxC,boxStyle){
|
||||
var image = boxStyle.image;
|
||||
if(typeof image !== "undefined"){ctx.drawImage(image,boxC.x,boxC.y,boxC.width(),boxC.height());}
|
||||
}
|
||||
function drawColor(plot,ctx,boxC,boxStyle){
|
||||
color = getColor({ctx:ctx,color:boxStyle.color,left:boxC.x,top:boxC.y,height:boxC.height,width:boxC.width});
|
||||
ctx.fillStyle = color;
|
||||
ctx.fillRect(boxC.x,boxC.y,boxC.width,boxC.height);
|
||||
}
|
||||
}
|
||||
function drawCircle(plot,ctx,xaxis,yaxis,circle,circleStyle){
|
||||
var circleC = {x: xaxis.p2c(boxDim.x),y: yaxis.p2c(boxDim.y)}
|
||||
}
|
||||
$.plot.JUMlib = {};
|
||||
$.plot.JUMlib.library = {};
|
||||
$.plot.JUMlib.library.between = between;
|
||||
$.plot.JUMlib.library.getMinMax = getMinMax;
|
||||
$.plot.JUMlib.library.showHover = showHover;
|
||||
$.plot.JUMlib.library.showTooltip = showTooltip;
|
||||
$.plot.JUMlib.library.loadScripts = loadScripts;
|
||||
$.plot.JUMlib.library.loadJSON = loadJSON;
|
||||
$.plot.JUMlib.prepareData = {};
|
||||
$.plot.JUMlib.prepareData.createQuartile = createQuartile;
|
||||
$.plot.JUMlib.prepareData.createPercentile = createPercentile;
|
||||
$.plot.JUMlib.prepareData.createSimiliarity = createSimiliarity;
|
||||
$.plot.JUMlib.prepareData.createWaterfall = createWaterfall;
|
||||
$.plot.JUMlib.prepareData.avg = avg;
|
||||
$.plot.JUMlib.prepareData.max = max;
|
||||
$.plot.JUMlib.prepareData.min = min;
|
||||
$.plot.JUMlib.prepareData.sort = sort;
|
||||
$.plot.JUMlib.prepareData.sortTicks = sortTicks;
|
||||
$.plot.JUMlib.prepareData.pareto = pareto;
|
||||
$.plot.JUMlib.prepareData.normalize = normalize;
|
||||
$.plot.JUMlib.prepareData.combineData = combineData;
|
||||
$.plot.JUMlib.data = {};
|
||||
$.plot.JUMlib.data.createFont = createFont;
|
||||
$.plot.JUMlib.data.createColors = createColors;
|
||||
$.plot.JUMlib.data.getColor = getColor;
|
||||
$.plot.JUMlib.data.loadImages = loadImages;
|
||||
$.plot.JUMlib.data.getCanvases = getCanvases;
|
||||
$.plot.JUMlib.data.extendEmpty = extendEmpty;
|
||||
$.plot.JUMlib.drawing = {};
|
||||
$.plot.JUMlib.drawing.drawLine = drawLine;
|
||||
$.plot.JUMlib.drawing.drawRect = drawRect;
|
||||
$.plot.JUMlib.drawing.drawLines = drawLines;
|
||||
$.plot.plugins.push({
|
||||
init: function(){},
|
||||
options: { },
|
||||
name: pluginName,
|
||||
version: pluginVersion
|
||||
});
|
||||
})(jQuery);
|
201
src/sunstone/public/vendor/flot/jquery.flot.gantt.js
vendored
Normal file
201
src/sunstone/public/vendor/flot/jquery.flot.gantt.js
vendored
Normal file
@ -0,0 +1,201 @@
|
||||
/*
|
||||
* The MIT License
|
||||
|
||||
Copyright (c) 2010, 2011, 2012, 2013 by Juergen Marsch
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
"use strict";
|
||||
var pluginName = "gantt", pluginVersion = "0.3";
|
||||
var options = {
|
||||
series: {
|
||||
gantt: {
|
||||
active: false,
|
||||
show: false,
|
||||
connectSteps: { show: false, lineWidth:2, color:"rgb(0,0,0)" },
|
||||
barHeight: 0.6,
|
||||
highlight: { opacity: 0.5 },
|
||||
drawstep: drawStepDefault
|
||||
}
|
||||
}
|
||||
};
|
||||
var replaceOptions = { series:{ lines: { show:false } } };
|
||||
var defaultOptions = {
|
||||
series:{
|
||||
editMode: 'y', //could be none, x, y, xy, v
|
||||
nearBy:{
|
||||
distance: 6,
|
||||
findItem: null,
|
||||
findMode: "circle",
|
||||
drawHover: null
|
||||
}
|
||||
}
|
||||
};
|
||||
function drawStepDefault(ctx,series,data,x,y,x2,color, isHighlight){
|
||||
if(isHighlight === false){
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = series.gantt.barheight;
|
||||
ctx.strokeStyle = "rgb(0,0,0)";
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x2, y);
|
||||
ctx.stroke();
|
||||
}
|
||||
ctx.beginPath();
|
||||
ctx.strokeStyle = color;
|
||||
ctx.lineWidth = series.gantt.barheight - 2;
|
||||
ctx.lineCap = "butt";
|
||||
ctx.moveTo(x + 1, y);
|
||||
ctx.lineTo(x2 - 1, y);
|
||||
ctx.stroke();
|
||||
}
|
||||
function init(plot) {
|
||||
var offset = null, opt = null, series = null,canvas,target,axes,data;
|
||||
plot.hooks.processOptions.push(processOptions);
|
||||
function processOptions(plot,options){
|
||||
if (options.series.gantt.active){
|
||||
$.extend(true,options,replaceOptions);
|
||||
$.plot.JUMlib.data.extendEmpty(options,defaultOptions);
|
||||
opt = options;
|
||||
plot.hooks.processRawData.push(processRawData);
|
||||
plot.hooks.draw.push(draw);
|
||||
}
|
||||
}
|
||||
function processRawData(plot,s,data,datapoints){
|
||||
if(s.gantt.show === true){
|
||||
s.nearBy.findItem = findNearbyItemGantt;
|
||||
s.nearBy.drawHover = drawHoverGantt;
|
||||
}
|
||||
}
|
||||
function draw(plot, ctx){
|
||||
var serie;
|
||||
canvas = plot.getCanvas();
|
||||
target = $(canvas).parent();
|
||||
axes = plot.getAxes();
|
||||
offset = plot.getPlotOffset();
|
||||
data = plot.getData();
|
||||
for (var i = 0; i < data.length; i++){
|
||||
serie = data[i];
|
||||
serie.gantt.barheight = axes.yaxis.p2c(1) / (axes.yaxis.max - axes.yaxis.min) * serie.gantt.barHeight;
|
||||
if (serie.gantt.show) {
|
||||
series = serie;
|
||||
for (var j = 0; j < serie.data.length; j++){drawData(ctx,serie, serie.data[j], serie.color,false); }
|
||||
if(serie.gantt.connectSteps.show){ drawConnections(ctx,serie); }
|
||||
}
|
||||
}
|
||||
}
|
||||
function drawData(ctx,series,data,color,isHighlight){
|
||||
var x,y,x2;
|
||||
x = offset.left + axes.xaxis.p2c(data[0]);
|
||||
x = Math.min(Math.max(offset.left,x),offset.left + plot.width());
|
||||
y = offset.top + axes.yaxis.p2c(data[1]);
|
||||
x2 = offset.left + axes.xaxis.p2c(data[2]);
|
||||
x2 = Math.min(Math.max(x2,offset.left),offset.left + plot.width());
|
||||
if(x2 > offset.left || x > offset.left){
|
||||
if (x < (offset.left + plot.width()) || x2 < (offset.left + plot.width())){
|
||||
if (data.length === 4) {drawStepDefault(ctx, series, data, x, y, x2, color, isHighlight);}
|
||||
else{ series.gantt.drawstep(ctx,series,data,x,y,x2,color,isHighlight);}
|
||||
}
|
||||
}
|
||||
}
|
||||
function drawConnections(ctx,series){
|
||||
for(var i = 0; i < series.data.length; i++){
|
||||
for(var j = 0; j < series.data.length; j++){
|
||||
if(series.data[i][2] == series.data[j][0]){
|
||||
var x = offset.left + axes.xaxis.p2c(series.data[i][2]),
|
||||
y = offset.top + axes.yaxis.p2c(series.data[i][1]),
|
||||
y2 = offset.top + axes.yaxis.p2c(series.data[j][1]);
|
||||
drawConnection(ctx,x,y,y2,series.gantt.connectSteps.lineWidth,series.gantt.connectSteps.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function drawConnection(ctx,x,y,y2,lineWidth,color){
|
||||
ctx.beginPath();
|
||||
ctx.lineWidth = lineWidth;
|
||||
ctx.strokeStyle = color;
|
||||
ctx.moveTo(x, y);
|
||||
ctx.lineTo(x, y2);
|
||||
ctx.stroke();
|
||||
}
|
||||
function findNearbyItemGantt(mouseX, mouseY,i,serie){
|
||||
var item = null;
|
||||
if(opt.series.justEditing){
|
||||
if(opt.series.justEditing[1].seriesIndex === i){item = findNearbyItemEdit(mouseX,mouseY,i,serie);}
|
||||
}
|
||||
else{
|
||||
if(opt.grid.editable){ item = findNearbyItemForEdit(mouseX,mouseY,i,serie);}
|
||||
else{ item = findNearbyItem(mouseX,mouseY,i,serie);}
|
||||
}
|
||||
return item;
|
||||
function findNearbyItem(mouseX,mouseY,i,serie){
|
||||
var item = null;
|
||||
if(serie.gantt.show){
|
||||
for(var j = 0; j < serie.data.length; j++){
|
||||
var dataitem = serie.data[j];
|
||||
var dx = serie.xaxis.p2c(dataitem[0]),dx2 = serie.xaxis.p2c(dataitem[2]),
|
||||
dy = Math.abs(serie.yaxis.p2c(dataitem[1]) - mouseY);
|
||||
if(dy <= serie.gantt.barheight / 2){ if(between(mouseX,dx,dx2)){ item = [i,j]; } }
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
function findNearbyItemForEdit(mouseX,mouseY,i,serie){
|
||||
var item = null;
|
||||
if(serie.gantt.show){
|
||||
for(var j = 0; j < serie.data.length; j++){
|
||||
var dataitem = serie.data[j];
|
||||
var dx = serie.xaxis.p2c(dataitem[0]),dx2 = serie.xaxis.p2c(dataitem[2]),
|
||||
dy = Math.abs(serie.yaxis.p2c(dataitem[1]) - mouseY);
|
||||
if(dy <= serie.gantt.barheight / 2){
|
||||
if(between(mouseX,dx,dx2)){ item = [i,j]; serie.editMode = 'y'; serie.nearBy.findMode = 'vertical';serie.nearBy.width = dataitem[2]-dataitem[0];}
|
||||
if(between(mouseX,dx,dx + serie.nearBy.distance)) { item = [i,[j,1]];serie.editMode = 'x'; serie.nearBy.findMode = 'horizontal'; }
|
||||
if(between(mouseX,dx2,dx2 + serie.nearBy.distance)) { item = [i,[j,2]];serie.editMode = 'x'; serie.nearBy.findMode = 'horizontal'; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
function findNearbyItemEdit(mouseX,mouseY,i,serie){
|
||||
var item = null;
|
||||
var j = opt.series.justEditing[1].dataIndex;
|
||||
var dataitem = serie.data[j];
|
||||
if(j.length){item = [i,j];}else{item = [i,j];}
|
||||
return item;
|
||||
}
|
||||
}
|
||||
function drawHoverGantt(octx,serie,dataIndex){
|
||||
var data;
|
||||
octx.save();
|
||||
octx.translate(-offset.left,-offset.top);
|
||||
var c = "rgba(255,255,255, " + serie.gantt.highlight.opacity + ")";
|
||||
if(dataIndex.length){ data = serie.data[dataIndex[0]];} else{ data = serie.data[dataIndex];}
|
||||
drawData(octx,serie,data,c,true);
|
||||
octx.restore();
|
||||
}
|
||||
}
|
||||
var between = $.plot.JUMlib.library.between;
|
||||
$.plot.plugins.push({
|
||||
init: init,
|
||||
options: options,
|
||||
name: pluginName,
|
||||
version: pluginVersion
|
||||
});
|
||||
})(jQuery);
|
12
src/sunstone/public/vendor/flot/jquery.flot.tooltip.min.js
vendored
Normal file
12
src/sunstone/public/vendor/flot/jquery.flot.tooltip.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@ -374,7 +374,7 @@ get '/vm/:id/log' do
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Accounting & Monitoring
|
||||
# Monitoring
|
||||
##############################################################################
|
||||
|
||||
get '/:resource/monitor' do
|
||||
@ -399,6 +399,15 @@ get '/:resource/:id/monitor' do
|
||||
params[:monitor_resources])
|
||||
end
|
||||
|
||||
##############################################################################
|
||||
# Accounting
|
||||
##############################################################################
|
||||
|
||||
get '/vm/accounting' do
|
||||
@SunstoneServer.get_vm_accounting(params)
|
||||
end
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Marketplace
|
||||
##############################################################################
|
||||
|
@ -13,6 +13,7 @@
|
||||
<script src="vendor/flot/jquery.flot.pie.min.js?v=<%= OpenNebula::VERSION %>" type="text/javascript"></script>
|
||||
<script src="vendor/flot/jquery.flot.resize.min.js?v=<%= OpenNebula::VERSION %>" type="text/javascript"></script>
|
||||
<script src="vendor/flot/jquery.flot.stack.min.js?v=<%= OpenNebula::VERSION %>" type="text/javascript"></script>
|
||||
<script src="vendor/flot/jquery.flot.tooltip.min.js?v=<%= OpenNebula::VERSION %>" type="text/javascript"></script>
|
||||
<script src="vendor/fileuploader/fileuploader.js?v=<%= OpenNebula::VERSION %>" type="text/javascript"></script>
|
||||
<script src="vendor/4.0/nouislider/jquery.nouislider.min.js?v=<%= OpenNebula::VERSION %>" type="text/javascript"></script>
|
||||
<script src="vendor/4.0/jdpicker_1.1/jquery.jdpicker.js"?v=<%= OpenNebula::VERSION %> type="text/javascript"></script>
|
||||
|
Loading…
x
Reference in New Issue
Block a user