mirror of
https://github.com/unraid/webgui.git
synced 2026-04-22 18:19:14 -05:00
Merge remote-tracking branch 'upstream/master' into Snapshots
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
function clearHistory(){
|
||||
window.history.pushState('VMs', 'Title', '/VMs');
|
||||
}
|
||||
|
||||
function ordinal_suffix_of(i) {
|
||||
var j = i % 10,
|
||||
k = i % 100;
|
||||
if (j == 1 && k != 11) {
|
||||
return i + "st";
|
||||
}
|
||||
if (j == 2 && k != 12) {
|
||||
return i + "nd";
|
||||
}
|
||||
if (j == 3 && k != 13) {
|
||||
return i + "rd";
|
||||
}
|
||||
return i + "th";
|
||||
}
|
||||
|
||||
function slideUpRows($tr, onComplete) {
|
||||
$tr.not('tr,table').finish().fadeOut('fast');
|
||||
|
||||
$tr.filter('tr').find('td').finish().each(function(){
|
||||
$(this)
|
||||
.data("paddingstate", $(this).css(["paddingTop", "paddingBottom"]))
|
||||
.animate({ paddingTop: 0, paddingBottom: 0 }, { duration: 'fast' })
|
||||
.wrapInner('<div />')
|
||||
.children()
|
||||
.slideUp("fast", function() {
|
||||
$(this).contents().unwrap();
|
||||
$tr.filter('tr').hide();
|
||||
if ($.isFunction(onComplete)) {
|
||||
onComplete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$tr.filter('table').finish().each(function(){
|
||||
$(this)
|
||||
.wrap('<div style="overflow: hidden"></div>')
|
||||
.parent()
|
||||
.slideUp("fast", function() {
|
||||
$(this).contents().unwrap();
|
||||
$tr.filter('table').hide();
|
||||
if ($.isFunction(onComplete)) {
|
||||
onComplete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return $tr;
|
||||
}
|
||||
|
||||
function slideDownRows($tr, onComplete) {
|
||||
$tr.filter(':hidden').not('tr,table').finish().fadeIn('fast');
|
||||
|
||||
$tr.filter('tr:hidden').find('td').finish().each(function(){
|
||||
$(this)
|
||||
.wrapInner('<div style="display: none"></div>')
|
||||
.animate($(this).data("paddingstate"), { duration: 'fast', start: function() { $tr.filter('tr:hidden').show(); } })
|
||||
.children()
|
||||
.slideDown("fast", function() {
|
||||
$(this).contents().unwrap();
|
||||
if ($.isFunction(onComplete)) {
|
||||
onComplete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$tr.filter('table:hidden').finish().each(function(){
|
||||
$(this)
|
||||
.wrap('<div style="display: none; overflow: hidden"></div>')
|
||||
.show()
|
||||
.parent()
|
||||
.slideDown("fast", function() {
|
||||
$(this).contents().unwrap();
|
||||
if ($.isFunction(onComplete)) {
|
||||
onComplete();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return $tr;
|
||||
}
|
||||
|
||||
function toggleRows(what, val, what2, onComplete) {
|
||||
if (val == 1) {
|
||||
slideDownRows($('.'+what), onComplete);
|
||||
if (arguments.length > 2) {
|
||||
slideUpRows($('.'+what2), onComplete);
|
||||
}
|
||||
} else {
|
||||
slideUpRows($('.'+what), onComplete);
|
||||
if (arguments.length > 2) {
|
||||
slideDownRows($('.'+what2), onComplete);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function updatePrefixLabels(category) {
|
||||
$("#vmform table:data(category)").filter(function() {
|
||||
return $(this).data('category') == category;
|
||||
}).each(function (index) {
|
||||
var oldprefix = $(this).data('prefix');
|
||||
var newprefix = oldprefix;
|
||||
|
||||
if (index > 0) {
|
||||
newprefix = ordinal_suffix_of(index+1);
|
||||
}
|
||||
|
||||
$(this)
|
||||
.data('prefix', newprefix)
|
||||
.find('tr').each(function() {
|
||||
var $td = $(this).children('td').first();
|
||||
|
||||
var old = $td.text();
|
||||
if (oldprefix && old.indexOf(oldprefix) === 0) {
|
||||
old = old.replace(oldprefix + ' ', '');
|
||||
}
|
||||
|
||||
$td.text(newprefix + ' ' + old);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function bindSectionEvents(category) {
|
||||
var $Filtered = $("#vmform table:data(category)").filter(function(index) {
|
||||
return $(this).data('category') == category;
|
||||
});
|
||||
|
||||
var count = $Filtered.length;
|
||||
|
||||
$Filtered.each(function(index) {
|
||||
var $table = $(this);
|
||||
var config = $(this).data();
|
||||
var boolAdd = false;
|
||||
var boolDelete = false;
|
||||
|
||||
if (!config.hasOwnProperty('multiple')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clean old sections
|
||||
var $first_td = $(this).find('td').first();
|
||||
|
||||
// delete section
|
||||
if (!config.hasOwnProperty('minimum') || config.minimum === undefined || parseInt(config.minimum) < (index+1)) {
|
||||
if ($first_td.children('.sectionbutton.remove').length === 0) {
|
||||
var $el_remove = $('<div class="sectionbutton remove" title="Remove ' + config.prefix + ' ' + category.replace('_', ' ') + '"><i class="fa fa-minus-circle red"></i></div>').one('click', clickRemoveSection);
|
||||
$first_td.append($el_remove);
|
||||
}
|
||||
boolDelete = true;
|
||||
} else {
|
||||
$first_td.children('.sectionbutton.remove').fadeOut('fast', function() { $(this).remove(); });
|
||||
}
|
||||
|
||||
// add section (can only add from the last section)
|
||||
if ((index+1) == count) {
|
||||
if (!config.hasOwnProperty('maximum') || config.maximum === undefined || parseInt(config.maximum) > (index+1)) {
|
||||
if ($first_td.children('.sectionbutton.add').length === 0) {
|
||||
var $el_add = $('<div class="sectionbutton add" title="Add another ' + category.replace('_', ' ') + '"><i class="fa fa-plus-circle green"></i></div>').one('click', clickAddSection);
|
||||
$first_td.append($el_add);
|
||||
}
|
||||
boolAdd = true;
|
||||
} else {
|
||||
$first_td.children('.sectionbutton.add').fadeOut('fast', function() { $(this).remove(); });
|
||||
}
|
||||
}
|
||||
|
||||
if (boolDelete || boolAdd) {
|
||||
$table.addClass("multiple");
|
||||
if ($first_td.children('.sectiontab').length === 0) {
|
||||
var $el_tab = $('<div class="sectiontab"></div>');
|
||||
$first_td.append($el_tab);
|
||||
}
|
||||
} else {
|
||||
$first_td.children('.sectionbutton, .sectiontab').fadeOut('fast', function() {
|
||||
$(this).remove();
|
||||
$table.removeClass("multiple");
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function clickAddSection() {
|
||||
var $table = $(this).closest('table');
|
||||
$(this).remove();
|
||||
var newindex = new Date().getTime();
|
||||
var config = $table.data();
|
||||
|
||||
var $template = $($('<div/>').loadTemplate($("#tmpl" + config.category)).html().replace(/{{INDEX}}/g, newindex));
|
||||
|
||||
$template
|
||||
.data({
|
||||
multiple: true,
|
||||
category: config.category,
|
||||
index: newindex,
|
||||
minimum: config.minimum,
|
||||
maximum: config.maximum
|
||||
})
|
||||
.find('tr').hide()
|
||||
.find("input[data-pickroot]").fileTreeAttach();
|
||||
|
||||
$table.after($template);
|
||||
|
||||
updatePrefixLabels(config.category);
|
||||
bindSectionEvents(config.category);
|
||||
|
||||
$el_showable = $template.find('tr').not("." + (isVMAdvancedMode() ? 'basic' : 'advanced'));
|
||||
|
||||
slideDownRows($el_showable);
|
||||
|
||||
$table.parent().trigger('spawn_section', [ $template, $template.data() ]);
|
||||
}
|
||||
|
||||
function clickRemoveSection() {
|
||||
var $table = $(this).closest('table');
|
||||
var $parent = $table.parent();
|
||||
var tabledata = $table.data();
|
||||
|
||||
slideUpRows($table, function() {
|
||||
$table.detach();
|
||||
$parent.trigger('destroy_section', [ $table, tabledata ]);
|
||||
$table.remove();
|
||||
|
||||
updatePrefixLabels(tabledata.category);
|
||||
bindSectionEvents(tabledata.category);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,282 @@
|
||||
function displayconsole(url) {
|
||||
window.open(url, '_blank', 'scrollbars=yes,resizable=yes');
|
||||
}
|
||||
|
||||
function downloadFile(source) {
|
||||
var a = document.createElement('a');
|
||||
a.setAttribute('href',source);
|
||||
a.setAttribute('download',source.split('/').pop());
|
||||
a.style.display = 'none';
|
||||
document.body.appendChild(a);
|
||||
a.click();
|
||||
document.body.removeChild(a);
|
||||
}
|
||||
|
||||
function ajaxVMDispatch(params, spin){
|
||||
if (spin) $('#vm-'+params['uuid']).parent().find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", params, function(data) {
|
||||
if (data.error) {
|
||||
swal({
|
||||
title:_("Execution error"), html:true,
|
||||
text:data.error, type:"error",
|
||||
confirmButtonText:_('Ok')
|
||||
},function(){
|
||||
if (spin) setTimeout(spin+'()',500); else location=window.location.href;
|
||||
});
|
||||
} else {
|
||||
if (spin) setTimeout(spin+'()',500); else location=window.location.href;
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
function ajaxVMDispatchconsole(params, spin){
|
||||
if (spin) $('#vm-'+params['uuid']).parent().find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", params, function(data) {
|
||||
if (data.error) {
|
||||
swal({
|
||||
title:_("Execution error"), html:true,
|
||||
text:data.error, type:"error",
|
||||
confirmButtonText:_('Ok')
|
||||
},function(){
|
||||
if (spin) setTimeout(spin+'()',500); else location=window.location.href;
|
||||
});
|
||||
} else {
|
||||
if (spin) setTimeout(spin+'()',500); else location=window.location.href;
|
||||
setTimeout('displayconsole("'+data.vmrcurl+'")',500) ;
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
function ajaxVMDispatchconsoleRV(params, spin){
|
||||
if (spin) $('#vm-'+params['uuid']).parent().find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
$.post("/plugins/dynamix.vm.manager/include/VMajax.php", params, function(data) {
|
||||
if (data.error) {
|
||||
swal({
|
||||
title:_("Execution error"), html:true,
|
||||
text:data.error, type:"error",
|
||||
confirmButtonText:_('Ok')
|
||||
},function(){
|
||||
if (spin) setTimeout(spin+'()',500); else location=window.location.href;
|
||||
});
|
||||
} else {
|
||||
if (spin) setTimeout(spin+'()',500); else location=window.location.href;
|
||||
downloadFile(data.vvfile) ;
|
||||
}
|
||||
},'json');
|
||||
}
|
||||
function addVMContext(name, uuid, template, state, vmrcurl, vmrcprotocol, log, console="web", preview=false){
|
||||
var opts = [];
|
||||
var path = location.pathname;
|
||||
var x = path.indexOf("?");
|
||||
if (x!=-1) path = path.substring(0,x);
|
||||
if (vmrcurl !== "" && state == "running") {
|
||||
if (console == "web" || console == "both") {
|
||||
var vmrctext=_("VM Console") + "(" + vmrcprotocol + ")" ;
|
||||
opts.push({text:vmrctext, icon:"fa-desktop", action:function(e) {
|
||||
e.preventDefault();
|
||||
window.open(vmrcurl, '_blank', 'scrollbars=yes,resizable=yes');
|
||||
}});
|
||||
}
|
||||
if (console == "remote" || console == "both") {
|
||||
opts.push({text:_("VM remote-viewer")+ "(" + vmrcprotocol + ")" , icon:"fa-desktop", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatchconsoleRV({action:"domain-consoleRV", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ;
|
||||
}});
|
||||
}
|
||||
|
||||
opts.push({divider:true});
|
||||
}
|
||||
context.settings({right:false,above:false});
|
||||
if (state == "running") {
|
||||
opts.push({text:_("Stop"), icon:"fa-stop", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-stop", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
opts.push({text:_("Pause"), icon:"fa-pause", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-pause", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
opts.push({text:_("Restart"), icon:"fa-refresh", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-restart", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
opts.push({text:_("Hibernate"), icon:"fa-bed", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-pmsuspend", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
opts.push({text:_("Force Stop"), icon:"fa-bomb", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch( {action:"domain-destroy", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
opts.push({divider:true});
|
||||
if (preview) {
|
||||
opts.push({text:_("Create Snapshot"), icon:"fa-clone", action:function(e) {
|
||||
e.preventDefault();
|
||||
selectsnapshot(uuid , name, "--generate" , "create",false,state) ;
|
||||
}}); }
|
||||
} else if (state == "pmsuspended") {
|
||||
opts.push({text:_("Resume"), icon:"fa-play", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-pmwakeup", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
opts.push({text:_("Force Stop"), icon:"fa-bomb", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-destroy", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
} else if (state == "paused" || state == "unknown") {
|
||||
opts.push({text:_("Resume"), icon:"fa-play", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-resume", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
opts.push({text:_("Force Stop"), icon:"fa-bomb", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-destroy", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
} else {
|
||||
opts.push({text:_("Start"), icon:"fa-play", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-start", uuid:uuid}, "loadlist");
|
||||
}});
|
||||
if (vmrcprotocol == "VNC" || vmrcprotocol == "SPICE") {
|
||||
if (console == "web" || console == "both") {
|
||||
opts.push({text:_("Start with console")+ "(" + vmrcprotocol + ")" , icon:"fa-play", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatchconsole({action:"domain-start-console", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ;
|
||||
}});}
|
||||
if (console == "remote" || console == "both") {
|
||||
opts.push({text:_("Start with remote-viewer")+ "(" + vmrcprotocol + ")" , icon:"fa-play", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatchconsoleRV({action:"domain-start-consoleRV", uuid:uuid, vmrcurl:vmrcurl}, "loadlist") ;
|
||||
}});
|
||||
}
|
||||
}
|
||||
}
|
||||
opts.push({divider:true});
|
||||
if (log !== "") {
|
||||
opts.push({text:_("Logs"), icon:"fa-navicon", action:function(e){e.preventDefault(); openTerminal('log',name,log);}});
|
||||
}
|
||||
opts.push({text:_("Edit"), icon:"fa-pencil", href:path+'/UpdateVM?uuid='+uuid});
|
||||
if (state == "shutoff") {
|
||||
opts.push({divider:true});
|
||||
opts.push({text:_("Create Snapshot"), icon:"fa-clone", action:function(e) {
|
||||
e.preventDefault();
|
||||
selectsnapshot(uuid , name, "--generate" , "create",false,state) ;
|
||||
}});
|
||||
opts.push({text:_("Remove VM"), icon:"fa-minus", action:function(e) {
|
||||
e.preventDefault();
|
||||
swal({
|
||||
title:_("Are you sure?"),
|
||||
text:_("Remove definition:")+name,
|
||||
type:"warning",
|
||||
showCancelButton:true,
|
||||
confirmButtonText:_('Proceed'),
|
||||
cancelButtonText:_('Cancel')
|
||||
},function(){
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
ajaxVMDispatch({action:"domain-undefine",uuid:uuid}, "loadlist");
|
||||
});
|
||||
}});
|
||||
if (template != 'OpenELEC') {
|
||||
opts.push({text:_("Remove VM")+" & "+_("Disks"), icon:"fa-trash", action:function(e) {
|
||||
e.preventDefault();
|
||||
swal({
|
||||
title:_("Are you sure?"),
|
||||
text:_("Completely REMOVE")+" "+name+" "+_("disk image and definition"),
|
||||
type:"warning",
|
||||
showCancelButton:true,
|
||||
confirmButtonText:_('Proceed'),
|
||||
cancelButtonText:_('Cancel')
|
||||
},function(){
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
ajaxVMDispatch({action:"domain-delete",uuid:uuid}, "loadlist");
|
||||
});
|
||||
}});
|
||||
}
|
||||
}
|
||||
context.attach('#vm-'+uuid, opts);
|
||||
}
|
||||
function addVMSnapContext(name, uuid, template, state, snapshotname, preview=false){
|
||||
var opts = [];
|
||||
var path = location.pathname;
|
||||
var x = path.indexOf("?");
|
||||
if (x!=-1) path = path.substring(0,x);
|
||||
|
||||
context.settings({right:false,above:false});
|
||||
if (state == "running") {
|
||||
if (preview) {
|
||||
opts.push({text:_("Revert snapshot"), icon:"fa-stop", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"snapshot-revert-externa", uuid:uuid, snapshotname:snapshotname}, "loadlist");
|
||||
}});
|
||||
}
|
||||
opts.push({text:_("Block Commit"), icon:"fa-hdd-o", action:function(e) {
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
e.preventDefault();
|
||||
selectblock(uuid, name, snapshotname, "commit",true) ;
|
||||
}});
|
||||
if (preview) {
|
||||
opts.push({text:_("Block Pull"), icon:"fa-hdd-o", action:function(e) {
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
e.preventDefault();
|
||||
selectblock(uuid, name, snapshotname, "pull",true) ;
|
||||
}});
|
||||
|
||||
opts.push({text:_("Block Copy"), icon:"fa-stop", action:function(e) {
|
||||
e.preventDefault();
|
||||
ajaxVMDispatch({action:"domain-stop", uuid:uuid}, "loadlist");
|
||||
}}); }
|
||||
} else {
|
||||
opts.push({text:_("Revert snapshot"), icon:"fa-fast-backward", action:function(e) {
|
||||
e.preventDefault();
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
selectsnapshot(uuid, name, snapshotname, "revert",true) ;
|
||||
}});
|
||||
}
|
||||
opts.push({text:_("Remove snapshot"), icon:"fa-trash", action:function(e) {
|
||||
e.preventDefault();
|
||||
$('#vm-'+uuid).find('i').removeClass('fa-play fa-square fa-pause').addClass('fa-refresh fa-spin');
|
||||
selectsnapshot(uuid, name, snapshotname, "remove",true) ;
|
||||
}});
|
||||
context.attach('#vmsnap-'+uuid, opts);
|
||||
}
|
||||
function startAll() {
|
||||
$('input[type=button]').prop('disabled',true);
|
||||
for (var i=0,vm; vm=kvm[i]; i++) if (vm.state!='running') $('#vm-'+vm.id).parent().find('i').removeClass('fa-square').addClass('fa-refresh fa-spin');
|
||||
$.post('/plugins/dynamix.vm.manager/include/VMManager.php',{action:'start'}, function(){loadlist();});
|
||||
}
|
||||
function stopAll() {
|
||||
$('input[type=button]').prop('disabled',true);
|
||||
for (var i=0,vm; vm=kvm[i]; i++) if (vm.state=='running') $('#vm-'+vm.id).parent().find('i').removeClass('fa-play').addClass('fa-refresh fa-spin');
|
||||
$.post('/plugins/dynamix.vm.manager/include/VMManager.php',{action:'stop'}, function(){loadlist();});
|
||||
}
|
||||
function vncOpen() {
|
||||
$.post('/plugins/dynamix.vm.manager/include/vnc.php',{cmd:'open',root:'<?=$docroot?>',file:'<?=$docroot?>/plugins/dynamix.vm.manager/vncconnect.vnc'},function(data) {
|
||||
window.location.href = data;
|
||||
});
|
||||
}
|
||||
function toggle_id(itemID){
|
||||
var cookie = $.cookie('vmshow')||'';
|
||||
if ((document.getElementById(itemID).style.display == 'none')) {
|
||||
slideDownRows($('#'+itemID));
|
||||
if (cookie.indexOf(itemID)<0) $.cookie('vmshow',cookie+itemID+',');
|
||||
} else {
|
||||
slideUpRows($('#'+itemID));
|
||||
if (cookie.indexOf(itemID)>=0) $.cookie('vmshow',cookie.replace(itemID+',',''));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function showInput(){
|
||||
$(this).off('click');
|
||||
$(this).siblings('input').each(function(){$(this).show();});
|
||||
$(this).siblings('input').focus();
|
||||
$(this).hide();
|
||||
}
|
||||
function hideInput(){
|
||||
$(this).hide();
|
||||
$(this).siblings('span').show();
|
||||
$(this).siblings('span').click(showInput);
|
||||
}
|
||||
function addVM() {
|
||||
var path = location.pathname;
|
||||
var x = path.indexOf("?");
|
||||
if (x!=-1) path = path.substring(0,x);
|
||||
location = path+"/VMTemplates";
|
||||
}
|
||||
Reference in New Issue
Block a user