update account page, instance creation form, and config page,
fix issue with instance delete confirm popup, fix issues with dialog exit handling without form element
This commit is contained in:
parent
7f4bdacef0
commit
230fe2c9e4
@ -53,12 +53,12 @@ function populateResources (containerID, meta, resources) {
|
|||||||
Object.keys(meta).forEach((resourceType) => {
|
Object.keys(meta).forEach((resourceType) => {
|
||||||
if (meta[resourceType].display) {
|
if (meta[resourceType].display) {
|
||||||
if (meta[resourceType].type === "list") {
|
if (meta[resourceType].type === "list") {
|
||||||
resources[resourceType].forEach((listResource) => {
|
resources[resourceType].total.forEach((listResource) => {
|
||||||
createResourceUsageChart(container, listResource.name, listResource.avail, listResource.used, listResource.max, null);
|
createResourceUsageChart(container, listResource.name, listResource.avail, listResource.used, listResource.max, null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
createResourceUsageChart(container, meta[resourceType].name, resources[resourceType].avail, resources[resourceType].used, resources[resourceType].max, meta[resourceType]);
|
createResourceUsageChart(container, meta[resourceType].name, resources[resourceType].total.avail, resources[resourceType].total.used, resources[resourceType].total.max, meta[resourceType]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -124,29 +124,29 @@ function parseNumber (value, unitData) {
|
|||||||
function handlePasswordChangeForm () {
|
function handlePasswordChangeForm () {
|
||||||
const body = `
|
const body = `
|
||||||
<form method="dialog" class="input-grid" style="grid-template-columns: auto 1fr;" id="form">
|
<form method="dialog" class="input-grid" style="grid-template-columns: auto 1fr;" id="form">
|
||||||
<label for="new-password">New Password</label>
|
<label for="new-password">New Password</label>
|
||||||
<input class="w3-input w3-border" type="password" id="new-password" name="new-password">
|
<input class="w3-input w3-border" id="new-password" name="new-password" type="password"required>
|
||||||
<label for="confirm-password">Confirm Password</label>
|
<label for="confirm-password">Confirm Password</label>
|
||||||
<input class="w3-input w3-border" type="password" id="confirm-password" name="confirm-password">
|
<input class="w3-input w3-border" id="confirm-password" name="confirm-password" type="password" required>
|
||||||
</form>
|
</form>
|
||||||
<p class="w3-large" id="error-message" style="text-align: center; color: var(--negative-color); margin-top: 0.5em; margin-bottom: 0;"></p>
|
|
||||||
`;
|
`;
|
||||||
dialog("Change Password", body, async (result, form) => {
|
const d = dialog("Change Password", body, async (result, form) => {
|
||||||
if (result === "confirm") {
|
if (result === "confirm") {
|
||||||
const result = await requestAPI("/auth/password", "POST", { password: form.get("new-password") });
|
const result = await requestAPI("/auth/password", "POST", { password: form.get("new-password") });
|
||||||
if (result.status !== 200) {
|
if (result.status !== 200) {
|
||||||
alert(result.error);
|
alert(result.error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, (dialog, form) => {
|
|
||||||
const pass = form.get("new-password");
|
|
||||||
const conf = form.get("confirm-password");
|
|
||||||
if (pass !== conf) {
|
|
||||||
dialog.querySelector("#error-message").innerText = "Passwords must match";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var password = d.querySelector("#new-password")
|
||||||
|
var confirm_password = d.querySelector("#confirm-password");
|
||||||
|
|
||||||
|
function validatePassword(){
|
||||||
|
confirm_password.setCustomValidity( password.value !=
|
||||||
|
confirm_password.value ? "Passwords Don't Match" : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
password.addEventListener("change", validatePassword);
|
||||||
|
confirm_password.addEventListener("keyup", validatePassword);
|
||||||
}
|
}
|
||||||
|
@ -54,8 +54,10 @@ async function populateResources () {
|
|||||||
const global = await requestAPI("/global/config/resources");
|
const global = await requestAPI("/global/config/resources");
|
||||||
const user = await requestAPI("/user/config/resources");
|
const user = await requestAPI("/user/config/resources");
|
||||||
let options = [];
|
let options = [];
|
||||||
if (global.cpu.whitelist) {
|
const globalCPU = global.cpu;
|
||||||
user.cpu.forEach((userType) => {
|
const userCPU = node in user.cpu.nodes ? user.cpu.nodes[node] : user.cpu.global;
|
||||||
|
if (globalCPU.whitelist) {
|
||||||
|
userCPU.forEach((userType) => {
|
||||||
options.push(userType.name);
|
options.push(userType.name);
|
||||||
});
|
});
|
||||||
options = options.sort((a, b) => {
|
options = options.sort((a, b) => {
|
||||||
@ -65,7 +67,7 @@ async function populateResources () {
|
|||||||
else {
|
else {
|
||||||
const supported = await requestPVE(`/nodes/${node}/capabilities/qemu/cpu`);
|
const supported = await requestPVE(`/nodes/${node}/capabilities/qemu/cpu`);
|
||||||
supported.data.forEach((supportedType) => {
|
supported.data.forEach((supportedType) => {
|
||||||
if (!user.cpu.some((userType) => supportedType.name === userType.name)) {
|
if (!userCPU.some((userType) => supportedType.name === userType.name)) {
|
||||||
options.push(supportedType.name);
|
options.push(supportedType.name);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
export function dialog (header, body, onclose = async (result, form) => { }, validate = async (dialog, form) => {
|
export function dialog (header, body, onclose = async (result, form) => { }) {
|
||||||
return true;
|
|
||||||
}) {
|
|
||||||
const dialog = document.createElement("dialog");
|
const dialog = document.createElement("dialog");
|
||||||
dialog.innerHTML = `
|
dialog.innerHTML = `
|
||||||
<p class="w3-large" id="prompt" style="text-align: center;"></p>
|
<p class="w3-large" id="prompt" style="text-align: center;"></p>
|
||||||
@ -15,29 +13,20 @@ export function dialog (header, body, onclose = async (result, form) => { }, val
|
|||||||
dialog.querySelector("#body").innerHTML = body;
|
dialog.querySelector("#body").innerHTML = body;
|
||||||
dialog.addEventListener("close", async () => {
|
dialog.addEventListener("close", async () => {
|
||||||
const formElem = dialog.querySelector("form");
|
const formElem = dialog.querySelector("form");
|
||||||
let formData = null;
|
const formData = formElem ? new FormData(formElem) : null;
|
||||||
if (formElem) {
|
|
||||||
formData = new FormData(formElem);
|
|
||||||
}
|
|
||||||
await onclose(dialog.returnValue, formData);
|
await onclose(dialog.returnValue, formData);
|
||||||
dialog.parentElement.removeChild(dialog);
|
dialog.parentElement.removeChild(dialog);
|
||||||
});
|
});
|
||||||
dialog.querySelector("#confirm").addEventListener("click", async (e) => {
|
if (!dialog.querySelector("form")) {
|
||||||
e.preventDefault();
|
dialog.querySelector("#confirm").addEventListener("click", async (e) => {
|
||||||
let valid = true;
|
e.preventDefault();
|
||||||
const formElem = dialog.querySelector("form");
|
|
||||||
if (formElem) {
|
|
||||||
const form = new FormData(formElem);
|
|
||||||
valid = await validate(dialog, form);
|
|
||||||
}
|
|
||||||
if (valid) {
|
|
||||||
dialog.close(e.target.value);
|
dialog.close(e.target.value);
|
||||||
}
|
});
|
||||||
});
|
dialog.querySelector("#cancel").addEventListener("click", async (e) => {
|
||||||
dialog.querySelector("#cancel").addEventListener("click", async (e) => {
|
e.preventDefault();
|
||||||
e.preventDefault();
|
dialog.close(e.target.value);
|
||||||
dialog.close(e.target.value);
|
});
|
||||||
});
|
}
|
||||||
document.body.append(dialog);
|
document.body.append(dialog);
|
||||||
dialog.showModal();
|
dialog.showModal();
|
||||||
return dialog;
|
return dialog;
|
||||||
|
@ -163,6 +163,9 @@ async function handleInstanceAdd () {
|
|||||||
const rootfsStorage = d.querySelector("#rootfs-storage");
|
const rootfsStorage = d.querySelector("#rootfs-storage");
|
||||||
rootfsStorage.selectedIndex = -1;
|
rootfsStorage.selectedIndex = -1;
|
||||||
|
|
||||||
|
const userResources = await requestAPI("/user/dynamic/resources", "GET");
|
||||||
|
const userCluster = await requestAPI("/user/config/cluster", "GET");
|
||||||
|
|
||||||
const nodeSelect = d.querySelector("#node");
|
const nodeSelect = d.querySelector("#node");
|
||||||
const clusterNodes = await requestPVE("/nodes", "GET");
|
const clusterNodes = await requestPVE("/nodes", "GET");
|
||||||
const allowedNodes = await requestAPI("/user/config/nodes", "GET");
|
const allowedNodes = await requestAPI("/user/config/nodes", "GET");
|
||||||
@ -185,6 +188,23 @@ async function handleInstanceAdd () {
|
|||||||
});
|
});
|
||||||
templateStorage.selectedIndex = -1;
|
templateStorage.selectedIndex = -1;
|
||||||
rootfsStorage.selectedIndex = -1;
|
rootfsStorage.selectedIndex = -1;
|
||||||
|
|
||||||
|
if (node in userResources.cores.nodes) {
|
||||||
|
d.querySelector("#cores").max = userResources.cores.nodes[node].avail;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d.querySelector("#cores").max = userResources.cores.global.avail;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node in userResources.memory.nodes) {
|
||||||
|
d.querySelector("#memory").max = userResources.memory.nodes[node].avail;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
d.querySelector("#memory").max = userResources.memory.global.avail;
|
||||||
|
}
|
||||||
|
|
||||||
|
d.querySelector("#vmid").min = userCluster.vmid.min;
|
||||||
|
d.querySelector("#vmid").max = userCluster.vmid.max;
|
||||||
});
|
});
|
||||||
|
|
||||||
const templateImage = d.querySelector("#template-image"); // populate templateImage depending on selected image storage
|
const templateImage = d.querySelector("#template-image"); // populate templateImage depending on selected image storage
|
||||||
@ -199,11 +219,4 @@ async function handleInstanceAdd () {
|
|||||||
});
|
});
|
||||||
templateImage.selectedIndex = -1;
|
templateImage.selectedIndex = -1;
|
||||||
});
|
});
|
||||||
|
|
||||||
const userResources = await requestAPI("/user/dynamic/resources", "GET");
|
|
||||||
const userCluster = await requestAPI("/user/config/cluster", "GET");
|
|
||||||
d.querySelector("#cores").max = userResources.cores.avail;
|
|
||||||
d.querySelector("#memory").max = userResources.memory.avail;
|
|
||||||
d.querySelector("#vmid").min = userCluster.vmid.min;
|
|
||||||
d.querySelector("#vmid").max = userCluster.vmid.max;
|
|
||||||
}
|
}
|
||||||
|
@ -219,7 +219,7 @@ class InstanceCard extends HTMLElement {
|
|||||||
handleDeleteButton () {
|
handleDeleteButton () {
|
||||||
if (!this.actionLock && this.status === "stopped") {
|
if (!this.actionLock && this.status === "stopped") {
|
||||||
const header = `Delete VM ${this.vmid}`;
|
const header = `Delete VM ${this.vmid}`;
|
||||||
const body = `<p>Are you sure you want to <strong>delete</strong> VM </p><p>${this.vmid}</p>`;
|
const body = `<p>Are you sure you want to <strong>delete</strong> VM ${this.vmid}</p>`;
|
||||||
|
|
||||||
dialog(header, body, async (result, form) => {
|
dialog(header, body, async (result, form) => {
|
||||||
if (result === "confirm") {
|
if (result === "confirm") {
|
||||||
|
Loading…
Reference in New Issue
Block a user