fix bug in ssr dialog with multiple event listeners, add ssr dialog for instance delete
This commit is contained in:
@@ -23,15 +23,6 @@ class ModalDialog extends HTMLElement {
|
|||||||
const internals = this.attachInternals();
|
const internals = this.attachInternals();
|
||||||
this.shadowRoot = internals.shadowRoot;
|
this.shadowRoot = internals.shadowRoot;
|
||||||
this.dialog = this.shadowRoot.querySelector("dialog");
|
this.dialog = this.shadowRoot.querySelector("dialog");
|
||||||
// add dialog handler to each control button with the return value corresponding to their value attribute
|
|
||||||
const controls = this.shadowRoot.querySelector("#controls");
|
|
||||||
for (const button of controls.childNodes) {
|
|
||||||
button.addEventListener("click", async (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
this.dialog.close(e.target.value);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
this.setOnClose(); // default behavior to just close the dialog, should call setOnClose to override this behavior
|
|
||||||
}
|
}
|
||||||
|
|
||||||
showModal () {
|
showModal () {
|
||||||
@@ -46,6 +37,7 @@ class ModalDialog extends HTMLElement {
|
|||||||
return this.shadowRoot.querySelectorAll(query);
|
return this.shadowRoot.querySelectorAll(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// it is usually not safe to call this on each dialog invocation
|
||||||
setOnClose (callback = (result, form) => {}) {
|
setOnClose (callback = (result, form) => {}) {
|
||||||
this.dialog.addEventListener("close", () => {
|
this.dialog.addEventListener("close", () => {
|
||||||
const formElem = this.dialog.querySelector("form");
|
const formElem = this.dialog.querySelector("form");
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import { requestPVE, requestAPI, setAppearance, getSearchSettings, requestDash, setSVGSrc, setSVGAlt } from "./utils.js";
|
import { requestPVE, requestAPI, setAppearance, getSearchSettings, requestDash, setSVGSrc, setSVGAlt } from "./utils.js";
|
||||||
import { alert, dialog } from "./dialog.js";
|
import { alert } from "./dialog.js";
|
||||||
import { setupClientSync } from "./clientsync.js";
|
import { setupClientSync } from "./clientsync.js";
|
||||||
import wfaInit from "../modules/wfa.js";
|
import wfaInit from "../modules/wfa.js";
|
||||||
|
|
||||||
@@ -11,7 +11,8 @@ async function init () {
|
|||||||
wfaInit("modules/wfa.wasm");
|
wfaInit("modules/wfa.wasm");
|
||||||
initInstances();
|
initInstances();
|
||||||
|
|
||||||
document.querySelector("#instance-add").addEventListener("click", handleInstanceAdd);
|
initInstanceAddForm();
|
||||||
|
document.querySelector("#instance-add").addEventListener("click", handleInstanceAddButton);
|
||||||
document.querySelector("#vm-search").addEventListener("input", sortInstances);
|
document.querySelector("#vm-search").addEventListener("input", sortInstances);
|
||||||
|
|
||||||
setupClientSync(refreshInstances);
|
setupClientSync(refreshInstances);
|
||||||
@@ -119,6 +120,7 @@ class InstanceCard extends HTMLElement {
|
|||||||
nameParagraph.innerHTML = this.name ? this.name : " ";
|
nameParagraph.innerHTML = this.name ? this.name : " ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.initPowerForm();
|
||||||
const powerButton = this.shadowRoot.querySelector("#power-btn");
|
const powerButton = this.shadowRoot.querySelector("#power-btn");
|
||||||
if (powerButton.classList.contains("clickable")) {
|
if (powerButton.classList.contains("clickable")) {
|
||||||
powerButton.onclick = this.handlePowerButton.bind(this);
|
powerButton.onclick = this.handlePowerButton.bind(this);
|
||||||
@@ -131,6 +133,7 @@ class InstanceCard extends HTMLElement {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.initDeleteForm();
|
||||||
const deleteButton = this.shadowRoot.querySelector("#delete-btn");
|
const deleteButton = this.shadowRoot.querySelector("#delete-btn");
|
||||||
if (deleteButton.classList.contains("clickable")) {
|
if (deleteButton.classList.contains("clickable")) {
|
||||||
deleteButton.onclick = this.handleDeleteButton.bind(this);
|
deleteButton.onclick = this.handleDeleteButton.bind(this);
|
||||||
@@ -153,8 +156,7 @@ class InstanceCard extends HTMLElement {
|
|||||||
setSVGAlt(powerbtn, "");
|
setSVGAlt(powerbtn, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
async handlePowerButton () {
|
async initPowerForm () {
|
||||||
if (!this.actionLock) {
|
|
||||||
const dialog = this.shadowRoot.querySelector("#power-dialog");
|
const dialog = this.shadowRoot.querySelector("#power-dialog");
|
||||||
dialog.setOnClose(async (result, form) => {
|
dialog.setOnClose(async (result, form) => {
|
||||||
if (result === "confirm") {
|
if (result === "confirm") {
|
||||||
@@ -184,16 +186,18 @@ class InstanceCard extends HTMLElement {
|
|||||||
refreshInstances();
|
refreshInstances();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async handlePowerButton () {
|
||||||
|
if (!this.actionLock) {
|
||||||
|
const dialog = this.shadowRoot.querySelector("#power-dialog");
|
||||||
dialog.showModal();
|
dialog.showModal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteButton () {
|
initDeleteForm () {
|
||||||
if (!this.actionLock && this.status === "stopped") {
|
const dialog = this.shadowRoot.querySelector("#delete-dialog");
|
||||||
const header = `Delete ${this.vmid}`;
|
dialog.setOnClose(async (result, form) => {
|
||||||
const body = `<p>Are you sure you want to <strong>delete</strong> ${this.vmid}</p>`;
|
|
||||||
|
|
||||||
dialog(header, body, async (result, form) => {
|
|
||||||
if (result === "confirm") {
|
if (result === "confirm") {
|
||||||
this.actionLock = true;
|
this.actionLock = true;
|
||||||
|
|
||||||
@@ -211,6 +215,12 @@ class InstanceCard extends HTMLElement {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleDeleteButton () {
|
||||||
|
if (!this.actionLock && this.status === "stopped") {
|
||||||
|
const dialog = this.shadowRoot.querySelector("#delete-dialog");
|
||||||
|
dialog.showModal();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -312,9 +322,8 @@ function sortInstances () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function handleInstanceAdd () {
|
async function initInstanceAddForm () {
|
||||||
const d = document.querySelector("#create-instance-dialog");
|
const d = document.querySelector("#create-instance-dialog");
|
||||||
|
|
||||||
d.setOnClose(async (result, form) => {
|
d.setOnClose(async (result, form) => {
|
||||||
if (result === "confirm") {
|
if (result === "confirm") {
|
||||||
const body = {
|
const body = {
|
||||||
@@ -343,6 +352,10 @@ async function handleInstanceAdd () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function handleInstanceAddButton () {
|
||||||
|
const d = document.querySelector("#create-instance-dialog");
|
||||||
|
|
||||||
const templates = await requestAPI("/user/ct-templates", "GET");
|
const templates = await requestAPI("/user/ct-templates", "GET");
|
||||||
|
|
||||||
@@ -375,6 +388,7 @@ async function handleInstanceAdd () {
|
|||||||
const userCluster = await requestAPI("/user/config/cluster", "GET");
|
const userCluster = await requestAPI("/user/config/cluster", "GET");
|
||||||
|
|
||||||
const nodeSelect = d.querySelector("#node");
|
const nodeSelect = d.querySelector("#node");
|
||||||
|
nodeSelect.innerHTML = "";
|
||||||
const clusterNodes = await requestPVE("/nodes", "GET");
|
const clusterNodes = await requestPVE("/nodes", "GET");
|
||||||
const allowedNodes = Object.keys(userCluster.nodes);
|
const allowedNodes = Object.keys(userCluster.nodes);
|
||||||
clusterNodes.data.forEach((element) => {
|
clusterNodes.data.forEach((element) => {
|
||||||
@@ -415,6 +429,7 @@ async function handleInstanceAdd () {
|
|||||||
|
|
||||||
// add user pools to selector
|
// add user pools to selector
|
||||||
const poolSelect = d.querySelector("#pool");
|
const poolSelect = d.querySelector("#pool");
|
||||||
|
poolSelect.innerHTML = "";
|
||||||
const userPools = Object.keys(userCluster.pools);
|
const userPools = Object.keys(userCluster.pools);
|
||||||
userPools.forEach((element) => {
|
userPools.forEach((element) => {
|
||||||
poolSelect.add(new Option(element));
|
poolSelect.add(new Option(element));
|
||||||
|
@@ -61,6 +61,7 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<modal-dialog id="power-dialog">
|
<modal-dialog id="power-dialog">
|
||||||
<template shadowrootmode="open">
|
<template shadowrootmode="open">
|
||||||
<link rel="stylesheet" href="modules/w3.css">
|
<link rel="stylesheet" href="modules/w3.css">
|
||||||
@@ -94,6 +95,30 @@
|
|||||||
</dialog>
|
</dialog>
|
||||||
</template>
|
</template>
|
||||||
</modal-dialog>
|
</modal-dialog>
|
||||||
|
|
||||||
|
<modal-dialog id="delete-dialog">
|
||||||
|
<template shadowrootmode="open">
|
||||||
|
<link rel="stylesheet" href="modules/w3.css">
|
||||||
|
<link rel="stylesheet" href="css/style.css">
|
||||||
|
<link rel="stylesheet" href="css/form.css">
|
||||||
|
<dialog class="w3-container w3-card w3-border-0">
|
||||||
|
<p class="w3-large" id="prompt" style="text-align: center;">
|
||||||
|
Delete {{.VMID}}
|
||||||
|
</p>
|
||||||
|
<div id="body">
|
||||||
|
<form method="dialog" class="input-grid" style="grid-template-columns: auto 1fr;" id="form">
|
||||||
|
<p>
|
||||||
|
Are you sure you want to <strong>delete</strong> {{.VMID}}
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="controls" class="w3-center w3-container">
|
||||||
|
<button id="cancel" value="cancel" form="form" class="w3-button w3-margin" style="background-color: var(--negative-color, #f00); color: var(--lightbg-text-color, black);" formnovalidate>CANCEL</button>
|
||||||
|
<button id="confirm" value="confirm" form="form" class="w3-button w3-margin" style="background-color: var(--positive-color, #0f0); color: var(--lightbg-text-color, black);">CONFIRM</button>
|
||||||
|
</div>
|
||||||
|
</dialog>
|
||||||
|
</template>
|
||||||
|
</modal-dialog>
|
||||||
</template>
|
</template>
|
||||||
</instance-card>
|
</instance-card>
|
||||||
{{end}}
|
{{end}}
|
Reference in New Issue
Block a user