Update UI boot order selection element

Update the UI boot order selection element. It has been modified to
support the new 'order=' format for the Proxmox boot order option
in a more intuitive way for the user. The new element allows users
to enable any bootable device and choose the order for these
devices to boot in.

The new UI element is a table with four columns. The first column
indicates the order of the corresponding device. The second column
indicates whether the device is enabled as bootable. The third
column contains the device name. The fourth column contains the
device description. The order of the columns is changed by
dragging, enabled by SortableJS.

In cases of legacy nodes, the older dropdown boxes are used.
This commit is contained in:
Harmon Herring 2021-06-18 00:09:22 -04:00
parent fae4e9f059
commit b9860a10ff
3 changed files with 105 additions and 19 deletions

View file

@ -133,3 +133,15 @@ table, th, td {
#show-for-template {
display: none
}
.boot-order-check {
margin: 0 auto;
}
.borderless td, .borderless th, table.borderless {
border: none;
}
.fa-bars {
cursor: move;
}

View file

@ -815,24 +815,10 @@ $("#edit-boot-order").click(function(){
const vmid = $(this).data('vmid');
const vmname = $(this).data('vmname');
const boot_order = $(this).data('boot_order');
var options = document.createElement('div');
for (i = 0; i < boot_order.order.length; i++) {
text = document.createElement('span');
text.innerHTML = `${i + 1}. `;
options.append(text);
var entry = document.createElement('select');
entry.setAttribute("id", `boot-order-${i + 1}`);
for (j = 0; j < boot_order.order.length; j++) {
entry.appendChild(new Option(boot_order.order[j].device, boot_order.order[j].device));
}
entry.selectedIndex = i;
entry.setAttribute('style', 'width: 85px');
options.append(entry);
options.append(document.createElement('br'));
}
var options = renderBootOrder(boot_order);
swal({
title: `Select the new boot order for ${vmname} (full shutdown required for settings to take effect):`,
content: options,
content: renderBootOrder(boot_order),
buttons: {
cancel: {
text: "Cancel",
@ -848,10 +834,19 @@ $("#edit-boot-order").click(function(){
.then((willChange) => {
if (willChange) {
var data = new FormData();
if (boot_order.legacy) {
for (k = 0; k < boot_order.order.length; k++) {
e = document.getElementById(`boot-order-${k + 1}`);
data.append(`${k + 1}`, e.options[e.selectedIndex].value);
}
}
else {
document.getElementById('boot-order-sortable').childNodes.forEach((order, index) => {
if (order.children[1].firstChild.checked) {
data.append(`${index + 1}`, order.children[2].innerHTML);
}
});
}
fetch(`/vm/${vmid}/boot_order`, {
credentials: 'same-origin',
method: 'post',
@ -880,6 +875,81 @@ $("#edit-boot-order").click(function(){
});
});
function renderBootOrder(boot_order) {
let options = document.createElement('div');
if (boot_order.legacy) {
for (i = 0; i < boot_order.order.length; i++) {
text = document.createElement('span');
text.innerHTML = `${i + 1}. `;
options.append(text);
var entry = document.createElement('select');
entry.setAttribute("id", `boot-order-${i + 1}`);
for (j = 0; j < boot_order.order.length; j++) {
entry.appendChild(new Option(boot_order.order[j].device, boot_order.order[j].device));
}
entry.selectedIndex = i;
entry.setAttribute('style', 'width: 85px');
options.append(entry);
options.append(document.createElement('br'));
}
}
else {
let table = document.createElement('table');
table.classList.add('table', 'table-sm', 'borderless', 'text-left');
let thead = table.createTHead();
thead.classList.add('font-weight-bold');
let tbody = table.createTBody();
tbody.classList.add('text-break', 'boot-order-sortable');
tbody.id = 'boot-order-sortable';
let hrow = thead.insertRow();
hrow.insertCell().innerHTML = 'Order';
hrow.insertCell().innerHTML = 'Enabled';
hrow.insertCell().innerHTML = 'Device';
hrow.insertCell().innerHTML = 'Description';
for (i = 0; i < boot_order.order.length; i++) {
let row = tbody.insertRow();
row.id = `boot-order-${i + 1}`;
$(row.insertCell()).append(
$('<i>', {
class: 'fas fa-bars'
}),
$('<span>', {
class: 'boot-order-number',
id: `boot-order-number-${i + 1}`,
style: 'margin-left: .25rem',
text: `${i + 1}`
})
);
let checkCell = $(row.insertCell()).addClass('text-center');
$(checkCell).append(
$('<input>', {
type: 'checkbox',
class: 'form-check-input boot-order-check',
checked: boot_order.order[i].enabled
})
);
row.insertCell().innerHTML = boot_order.order[i].device;
row.insertCell().innerHTML = boot_order.order[i].description;
}
new Sortable(tbody, {
animation: 150,
filter: '.boot-order-check',
onEnd: function(event) {
numberBootOrderTable();
},
});
options.append(table);
}
return options;
}
function numberBootOrderTable() {
let i = 0;
$('[id^=boot-order-number]').each(function() {
this.innerHTML = ++i;
})
}
$(document).on('focus click', "[id^=boot-order-]", function() {
previous = $(this).val();
}).on('change', "[id^=boot-order-]", function() {

View file

@ -112,6 +112,10 @@
<script defer src="https://use.fontawesome.com/releases/v5.0.8/js/fontawesome.js"
integrity="sha384-7ox8Q2yzO/uWircfojVuCQOZl+ZZBg2D2J5nkpLqzH1HY0C1dHlTKIbpRz/LG23c"
crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Sortable/1.13.0/Sortable.min.js"
integrity="sha512-5x7t0fTAVo9dpfbp3WtE2N6bfipUwk7siViWncdDoSz2KwOqVC1N9fDxEOzk0vTThOua/mglfF8NO7uVDLRC8Q=="
crossorigin="anonymous"
referrerpolicy="no-referrer"></script>
<script src="/static/js/script.js"></script>
</body>