diff --git a/index.html b/index.html
index f71ad3d..694a004 100644
--- a/index.html
+++ b/index.html
@@ -10,7 +10,6 @@
-
diff --git a/scripts/config.js b/scripts/config.js
index 9018076..b654576 100644
--- a/scripts/config.js
+++ b/scripts/config.js
@@ -1,4 +1,4 @@
-import {requestPVE, requestAPI, goToPage, getURIData, resources} from "./utils.js";
+import {requestPVE, requestAPI, goToPage, getURIData, resources_config} from "./utils.js";
import {alert, dialog} from "./dialog.js";
window.addEventListener("DOMContentLoaded", init); // do the dumb thing where the disk config refreshes every second
diff --git a/scripts/index.js b/scripts/index.js
index 33e4e3b..069d89e 100644
--- a/scripts/index.js
+++ b/scripts/index.js
@@ -1,4 +1,4 @@
-import {requestPVE, requestAPI, goToPage} from "./utils.js";
+import {requestPVE, requestAPI, goToPage, instances_config, nodes_config} from "./utils.js";
import {alert, dialog} from "./dialog.js";
window.addEventListener("DOMContentLoaded", init);
@@ -57,9 +57,9 @@ async function populateInstances () {
`;
for(let i = 0; i < instances.length; i++) {
- let newInstance = document.createElement("instance-obj");
+ let newInstance = new Instance();
newInstance.data = instances[i];
- instanceContainer.append(newInstance);
+ instanceContainer.append(newInstance.shadowElement);
}
}
@@ -193,4 +193,212 @@ async function handleInstanceAdd () {
d.querySelector("#memory").max = userResources.avail.memory;
d.querySelector("#vmid").min = userInstances.vmid.min;
d.querySelector("#vmid").max = userInstances.vmid.max;
+}
+
+export class Instance {
+ constructor () {
+ let shadowRoot = document.createElement("div");
+
+ shadowRoot.innerHTML = `
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `;
+
+ this.shadowElement = shadowRoot;
+ this.actionLock = false;
+ }
+
+ set data (data) {
+ if (data.status === "unknown") {
+ data.status = "stopped";
+ }
+ this.type = data.type;
+ this.status = data.status;
+ this.vmid = data.vmid;
+ this.name = data.name;
+ this.node = data.node;
+ this.update();
+ }
+
+ update () {
+ let vmidParagraph = this.shadowElement.querySelector("#instance-id");
+ vmidParagraph.innerText = this.vmid;
+
+ let nameParagraph = this.shadowElement.querySelector("#instance-name");
+ nameParagraph.innerText = this.name ? this.name : "";
+
+ let typeParagraph = this.shadowElement.querySelector("#instance-type");
+ typeParagraph.innerText = this.type;
+
+ let statusParagraph = this.shadowElement.querySelector("#instance-status");
+ statusParagraph.innerText = this.status;
+
+ let statusIcon = this.shadowElement.querySelector("#instance-status-icon");
+ statusIcon.src = instances_config[this.status].statusSrc;
+ statusIcon.alt = instances_config[this.status].statusAlt;
+
+ let nodeNameParagraph = this.shadowElement.querySelector("#node-name");
+ nodeNameParagraph.innerText = this.node.name;
+
+ let nodeStatusParagraph = this.shadowElement.querySelector("#node-status");
+ nodeStatusParagraph.innerText = this.node.status;
+
+ let nodeStatusIcon = this.shadowElement.querySelector("#node-status-icon");
+ nodeStatusIcon.src = nodes_config[this.node.status].statusSrc;
+ nodeStatusIcon.alt = nodes_config[this.node.status].statusAlt;
+
+ let powerButton = this.shadowElement.querySelector("#power-btn");
+ powerButton.src = instances_config[this.status].powerButtonSrc;
+ powerButton.alt = instances_config[this.status].powerButtonAlt;
+ powerButton.title = instances_config[this.status].powerButtonAlt;
+ powerButton.onclick = this.handlePowerButton.bind(this)
+
+ let configButton = this.shadowElement.querySelector("#configure-btn");
+ configButton.src = instances_config[this.status].configButtonSrc;
+ configButton.alt = instances_config[this.status].configButtonAlt;
+ configButton.title = instances_config[this.status].configButtonAlt;
+ configButton.onclick = this.handleConfigButton.bind(this);
+
+ let consoleButton = this.shadowElement.querySelector("#console-btn");
+ consoleButton.src = instances_config[this.status].consoleButtonSrc;
+ consoleButton.alt = instances_config[this.status].consoleButtonAlt;
+ consoleButton.title = instances_config[this.status].consoleButtonAlt;
+ consoleButton.onclick = this.handleConsoleButton.bind(this);
+
+ let deleteButton = this.shadowElement.querySelector("#delete-btn");
+ deleteButton.src = instances_config[this.status].deleteButtonSrc;
+ deleteButton.alt = instances_config[this.status].deleteButtonAlt;
+ deleteButton.title = instances_config[this.status].deleteButtonAlt;
+ deleteButton.onclick = this.handleDeleteButton.bind(this);
+
+ if (this.node.status !== "online") {
+ powerButton.classList.add("hidden");
+ configButton.classList.add("hidden");
+ consoleButton.classList.add("hidden");
+ deleteButton.classList.add("hidden");
+ }
+ }
+
+ async handlePowerButton () {
+
+ if(!this.actionLock) {
+ let header = `${this.status === "running" ? "Stop" : "Start"} VM ${this.vmid}`;
+ let body = `Are you sure you want to ${this.status === "running" ? "stop" : "start"} VM
${this.vmid}
`
+
+ dialog(header, body, async (result, form) => {
+ if (result === "confirm") {
+ this.actionLock = true;
+ let targetAction = this.status === "running" ? "stop" : "start";
+ let targetStatus = this.status === "running" ? "stopped" : "running";
+ let prevStatus = this.status;
+ this.status = "loading";
+
+ this.update();
+
+ let result = await requestPVE(`/nodes/${this.node.name}/${this.type}/${this.vmid}/status/${targetAction}`, "POST", {node: this.node.name, vmid: this.vmid});
+
+ const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay));
+
+ while (true) {
+ let taskStatus = await requestPVE(`/nodes/${this.node.name}/tasks/${result.data}/status`, "GET");
+ if(taskStatus.data.status === "stopped" && taskStatus.data.exitstatus === "OK") { // task stopped and was successful
+ this.status = targetStatus;
+ this.update();
+ this.actionLock = false;
+ break;
+ }
+ else if (taskStatus.data.status === "stopped") { // task stopped but was not successful
+ this.status = prevStatus;
+ alert(`attempted to ${targetAction} ${this.vmid} but process returned stopped:${result.data.exitstatus}`);
+ this.update();
+ this.actionLock = false;
+ break;
+ }
+ else{ // task has not stopped
+ await waitFor(1000);
+ }
+ }
+ }
+ });
+ }
+ }
+
+ handleConfigButton () {
+ if (!this.actionLock && this.status === "stopped") { // if the action lock is false, and the node is stopped, then navigate to the conig page with the node infor in the search query
+ goToPage("config.html", {node: this.node.name, type: this.type, vmid: this.vmid});
+ }
+ }
+
+ handleConsoleButton () {
+ if (!this.actionLock && this.status === "running") {
+ let data = {console: `${this.type === "qemu" ? "kvm" : "lxc"}`, vmid: this.vmid, vmname: this.name, node: this.node.name, resize: "off", cmd: ""};
+ data[`${this.type === "qemu" ? "novnc" : "xtermjs"}`] = 1;
+ goToURL(PVE, data, true);
+ }
+ }
+
+ handleDeleteButton () {
+ if (!this.actionLock && this.status === "stopped") {
+
+ let header = `Delete VM ${this.vmid}`;
+ let body = `Are you sure you want to delete VM
${this.vmid}
`
+
+ dialog(header, body, async (result, form) => {
+ if (result === "confirm") {
+ this.actionLock = true;
+ let prevStatus = this.status;
+ this.status = "loading";
+ this.update();
+
+ let action = {};
+ action.purge = 1;
+ action["destroy-unreferenced-disks"] = 1;
+
+ let body = {
+ node: this.node.name,
+ type: this.type,
+ vmid: this.vmid,
+ action: JSON.stringify(action)
+ };
+
+ let result = await requestAPI("/instance", "DELETE", body);
+ if (result.status === 200) {
+ this.parentNode.removeChild(this);
+ }
+ else {
+ alert(result.error);
+ this.status = this.prevStatus;
+ this.update();
+ this.actionLock = false;
+ }
+ }
+ });
+ }
+ }
}
\ No newline at end of file
diff --git a/scripts/instance.js b/scripts/instance.js
deleted file mode 100644
index a2ef802..0000000
--- a/scripts/instance.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import {requestPVE, requestAPI, goToPage, goToURL, instances, nodes} from "./utils.js";
-import {alert, dialog} from "./dialog.js";
-import {PVE} from "../vars.js"
-
-export class Instance extends HTMLElement {
- constructor () {
- super();
- let shadowRoot = this.attachShadow({mode: "open"});
-
- shadowRoot.innerHTML = `
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- `;
-
- this.shadowElement = shadowRoot;
- this.actionLock = false;
- }
-
- set data (data) {
- if (data.status === "unknown") {
- data.status = "stopped";
- }
- this.type = data.type;
- this.status = data.status;
- this.vmid = data.vmid;
- this.name = data.name;
- this.node = data.node;
- this.update();
- }
-
- update () {
- let vmidParagraph = this.shadowElement.querySelector("#instance-id");
- vmidParagraph.innerText = this.vmid;
-
- let nameParagraph = this.shadowElement.querySelector("#instance-name");
- nameParagraph.innerText = this.name ? this.name : "";
-
- let typeParagraph = this.shadowElement.querySelector("#instance-type");
- typeParagraph.innerText = this.type;
-
- let statusParagraph = this.shadowElement.querySelector("#instance-status");
- statusParagraph.innerText = this.status;
-
- let statusIcon = this.shadowElement.querySelector("#instance-status-icon");
- statusIcon.src = instances[this.status].statusSrc;
- statusIcon.alt = instances[this.status].statusAlt;
-
- let nodeNameParagraph = this.shadowElement.querySelector("#node-name");
- nodeNameParagraph.innerText = this.node.name;
-
- let nodeStatusParagraph = this.shadowElement.querySelector("#node-status");
- nodeStatusParagraph.innerText = this.node.status;
-
- let nodeStatusIcon = this.shadowElement.querySelector("#node-status-icon");
- nodeStatusIcon.src = nodes[this.node.status].statusSrc;
- nodeStatusIcon.alt = nodes[this.node.status].statusAlt;
-
- let powerButton = this.shadowElement.querySelector("#power-btn");
- powerButton.src = instances[this.status].powerButtonSrc;
- powerButton.alt = instances[this.status].powerButtonAlt;
- powerButton.title = instances[this.status].powerButtonAlt;
- powerButton.onclick = this.handlePowerButton.bind(this)
-
- let configButton = this.shadowElement.querySelector("#configure-btn");
- configButton.src = instances[this.status].configButtonSrc;
- configButton.alt = instances[this.status].configButtonAlt;
- configButton.title = instances[this.status].configButtonAlt;
- configButton.onclick = this.handleConfigButton.bind(this);
-
- let consoleButton = this.shadowElement.querySelector("#console-btn");
- consoleButton.src = instances[this.status].consoleButtonSrc;
- consoleButton.alt = instances[this.status].consoleButtonAlt;
- consoleButton.title = instances[this.status].consoleButtonAlt;
- consoleButton.onclick = this.handleConsoleButton.bind(this);
-
- let deleteButton = this.shadowElement.querySelector("#delete-btn");
- deleteButton.src = instances[this.status].deleteButtonSrc;
- deleteButton.alt = instances[this.status].deleteButtonAlt;
- deleteButton.title = instances[this.status].deleteButtonAlt;
- deleteButton.onclick = this.handleDeleteButton.bind(this);
-
- if (this.node.status !== "online") {
- powerButton.classList.add("hidden");
- configButton.classList.add("hidden");
- consoleButton.classList.add("hidden");
- deleteButton.classList.add("hidden");
- }
- }
-
- async handlePowerButton () {
-
- if(!this.actionLock) {
- let header = `${this.status === "running" ? "Stop" : "Start"} VM ${this.vmid}`;
- let body = `Are you sure you want to ${this.status === "running" ? "stop" : "start"} VM
${this.vmid}
`
-
- dialog(header, body, async (result, form) => {
- if (result === "confirm") {
- this.actionLock = true;
- let targetAction = this.status === "running" ? "stop" : "start";
- let targetStatus = this.status === "running" ? "stopped" : "running";
- let prevStatus = this.status;
- this.status = "loading";
-
- this.update();
-
- let result = await requestPVE(`/nodes/${this.node.name}/${this.type}/${this.vmid}/status/${targetAction}`, "POST", {node: this.node.name, vmid: this.vmid});
-
- const waitFor = delay => new Promise(resolve => setTimeout(resolve, delay));
-
- while (true) {
- let taskStatus = await requestPVE(`/nodes/${this.node.name}/tasks/${result.data}/status`, "GET");
- if(taskStatus.data.status === "stopped" && taskStatus.data.exitstatus === "OK") { // task stopped and was successful
- this.status = targetStatus;
- this.update();
- this.actionLock = false;
- break;
- }
- else if (taskStatus.data.status === "stopped") { // task stopped but was not successful
- this.status = prevStatus;
- alert(`attempted to ${targetAction} ${this.vmid} but process returned stopped:${result.data.exitstatus}`);
- this.update();
- this.actionLock = false;
- break;
- }
- else{ // task has not stopped
- await waitFor(1000);
- }
- }
- }
- });
- }
- }
-
- handleConfigButton () {
- if (!this.actionLock && this.status === "stopped") { // if the action lock is false, and the node is stopped, then navigate to the conig page with the node infor in the search query
- goToPage("config.html", {node: this.node.name, type: this.type, vmid: this.vmid});
- }
- }
-
- handleConsoleButton () {
- if (!this.actionLock && this.status === "running") {
- let data = {console: `${this.type === "qemu" ? "kvm" : "lxc"}`, vmid: this.vmid, vmname: this.name, node: this.node.name, resize: "off", cmd: ""};
- data[`${this.type === "qemu" ? "novnc" : "xtermjs"}`] = 1;
- goToURL(PVE, data, true);
- }
- }
-
- handleDeleteButton () {
- if (!this.actionLock && this.status === "stopped") {
-
- let header = `Delete VM ${this.vmid}`;
- let body = `Are you sure you want to delete VM
${this.vmid}
`
-
- dialog(header, body, async (result, form) => {
- if (result === "confirm") {
- this.actionLock = true;
- let prevStatus = this.status;
- this.status = "loading";
- this.update();
-
- let action = {};
- action.purge = 1;
- action["destroy-unreferenced-disks"] = 1;
-
- let body = {
- node: this.node.name,
- type: this.type,
- vmid: this.vmid,
- action: JSON.stringify(action)
- };
-
- let result = await requestAPI("/instance", "DELETE", body);
- if (result.status === 200) {
- this.parentNode.removeChild(this);
- }
- else {
- alert(result.error);
- this.status = this.prevStatus;
- this.update();
- this.actionLock = false;
- }
- }
- });
- }
- }
-}
-
-customElements.define("instance-obj", Instance);
\ No newline at end of file
diff --git a/scripts/utils.js b/scripts/utils.js
index cb08be8..33e612c 100644
--- a/scripts/utils.js
+++ b/scripts/utils.js
@@ -7,7 +7,7 @@ export class NetworkError extends Error {
}
}
-export const resources = {
+export const resources_config = {
disk: {
actionBarOrder: ["move", "resize", "detach_attach", "delete"],
lxc: {
@@ -25,7 +25,7 @@ export const resources = {
}
}
-export const instances = {
+export const instances_config = {
running: {
statusSrc: "images/status/active.svg",
statusAlt: "Instance is running",
@@ -64,7 +64,7 @@ export const instances = {
}
}
-export const nodes = {
+export const nodes_config = {
online: {
statusSrc: "images/status/active.svg",
statusAlt: "Node is online",