diff --git a/app/routes/index.go b/app/routes/index.go index 88ef52b..9741a13 100644 --- a/app/routes/index.go +++ b/app/routes/index.go @@ -53,22 +53,25 @@ type Node struct { // used in constructing instance cards in index type InstanceCard struct { - VMID uint - Name string - Type string - Status string - Node string - NodeStatus string + VMID uint + Name string + Type string + Status string + Node string + NodeStatus string + ConfigPath string + ConsolePath string } // used in retriving cluster tasks type Task struct { - Type string - Node string - User string - ID string - VMID uint - Status string + Type string + Node string + User string + ID string + VMID uint + Status string + EndTime uint } type InstanceStatus struct { @@ -116,6 +119,12 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No for vmid, instance := range instances { nodestatus := nodes[instance.Node].Status instance.NodeStatus = nodestatus + instance.ConfigPath = fmt.Sprintf("config?node=%s&type=%s&vmid=%d", instance.Node, instance.Type, instance.VMID) + if instance.Type == "qemu" { + instance.ConsolePath = fmt.Sprintf("%s/?console=kvm&vmid=%d&vmname=%s&node=%s&resize=off&cmd=&novnc=1", common.Global.PVE, instance.VMID, instance.Name, instance.Node) + } else if instance.Type == "lxc" { + instance.ConsolePath = fmt.Sprintf("%s/?console=lxc&vmid=%d&vmname=%s&node=%s&resize=off&cmd=&xtermjs=1", common.Global.PVE, instance.VMID, instance.Name, instance.Node) + } instances[vmid] = instance } @@ -128,6 +137,9 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No return nil, nil, fmt.Errorf("request to /cluster/tasks resulted in %+v", res) } + most_recent_task := map[uint]uint{} + expected_state := map[uint]string{} + for _, v := range ctx.Body["data"].([]any) { task := Task{} err := mapstructure.Decode(v, &task) @@ -151,8 +163,21 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No } else if !(task.Status == "running" || task.Status == "OK") { // task is not running or finished with status OK continue } else { // recent task is a start or stop task for user instance which is running or "OK" + if task.EndTime > most_recent_task[task.VMID] { // if the task's end time is later than the most recent one encountered + most_recent_task[task.VMID] = task.EndTime // update the most recent task + if task.Type == "qmstart" || task.Type == "vzstart" { // if the task was a start task, update the expected state to running + expected_state[task.VMID] = "running" + } else if task.Type == "qmstop" || task.Type == "vzstop" { // if the task was a stop task, update the expected state to stopped + expected_state[task.VMID] = "stopped" + } + } + } + } + + for vmid, expected_state := range expected_state { // for the expected states from recent tasks + if instances[vmid].Status != expected_state { // if the current node's state from /cluster/resources differs from expected state // get /status/current which is updated faster than /cluster/resources - instance := instances[task.VMID] + instance := instances[vmid] path := fmt.Sprintf("/proxmox/nodes/%s/%s/%d/status/current", instance.Node, instance.Type, instance.VMID) ctx.Body = map[string]any{} res, code, err := common.RequestGetAPI(path, ctx) @@ -167,7 +192,7 @@ func GetClusterResources(auth common.Auth) (map[uint]InstanceCard, map[string]No mapstructure.Decode(ctx.Body["data"], &status) instance.Status = status.Status - instances[task.VMID] = instance + instances[vmid] = instance } } diff --git a/web/html/config.html b/web/html/config.html index fb121b8..c641957 100644 --- a/web/html/config.html +++ b/web/html/config.html @@ -26,7 +26,7 @@

Instances / {{.config.Name}}

-
+
Resources
@@ -91,7 +91,7 @@
{{end}}
- +
diff --git a/web/scripts/config.js b/web/scripts/config.js index e235c3c..6b12add 100644 --- a/web/scripts/config.js +++ b/web/scripts/config.js @@ -19,7 +19,7 @@ async function init () { initNetworks(); initDevices(); - document.querySelector("#exit").addEventListener("click", handleFormExit); + document.querySelector("#config-form").addEventListener("submit", handleFormExit); } class VolumeAction extends HTMLElement { @@ -530,7 +530,8 @@ async function refreshBoot () { } } -async function handleFormExit () { +async function handleFormExit (event) { + event.preventDefault(); const body = { cores: document.querySelector("#cores").value, memory: document.querySelector("#ram").value diff --git a/web/scripts/index.js b/web/scripts/index.js index 3cd9a2f..bd26719 100644 --- a/web/scripts/index.js +++ b/web/scripts/index.js @@ -1,4 +1,4 @@ -import { requestPVE, requestAPI, goToPage, setAppearance, getSearchSettings, goToURL, requestDash, setSVGSrc, setSVGAlt } from "./utils.js"; +import { requestPVE, requestAPI, setAppearance, getSearchSettings, requestDash, setSVGSrc, setSVGAlt } from "./utils.js"; import { alert, dialog } from "./dialog.js"; import { setupClientSync } from "./clientsync.js"; import wfaInit from "../modules/wfa.js"; @@ -124,17 +124,6 @@ class InstanceCard extends HTMLElement { powerButton.onclick = this.handlePowerButton.bind(this); } - const configButton = this.shadowRoot.querySelector("#configure-btn"); - if (configButton.classList.contains("clickable")) { - configButton.onclick = this.handleConfigButton.bind(this); - } - - const consoleButton = this.shadowRoot.querySelector("#console-btn"); - if (consoleButton.classList.contains("clickable")) { - consoleButton.classList.add("clickable"); - consoleButton.onclick = this.handleConsoleButton.bind(this); - } - const deleteButton = this.shadowRoot.querySelector("#delete-btn"); if (deleteButton.classList.contains("clickable")) { deleteButton.onclick = this.handleDeleteButton.bind(this); @@ -186,20 +175,6 @@ class InstanceCard extends HTMLElement { } } - handleConfigButton () { - if (!this.actionLock && this.status === "stopped") { // if the action lock is false, and the node is stopped, then navigate to the config page with the node info in the search query - goToPage("config", { node: this.node.name, type: this.type, vmid: this.vmid }); - } - } - - handleConsoleButton () { - if (!this.actionLock && this.status === "running") { - const 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(window.PVE, data, true); - } - } - handleDeleteButton () { if (!this.actionLock && this.status === "stopped") { const header = `Delete VM ${this.vmid}`; diff --git a/web/scripts/utils.js b/web/scripts/utils.js index edf0b59..2fa1670 100644 --- a/web/scripts/utils.js +++ b/web/scripts/utils.js @@ -114,20 +114,6 @@ export function goToPage (page, data = null) { window.location.href = `${page}${data ? "?" : ""}${params}`; } -export function goToURL (href, data = {}, newwindow = false) { - const url = new URL(href); - for (const k in data) { - url.searchParams.append(k, data[k]); - } - - if (newwindow) { - window.open(url, document.title, "height=480,width=848"); - } - else { - window.location.assign(url.toString()); - } -} - export function getURIData () { const url = new URL(window.location.href); return Object.fromEntries(url.searchParams); diff --git a/web/templates/instance-card.go.tmpl b/web/templates/instance-card.go.tmpl index 2b4b3bf..708906f 100644 --- a/web/templates/instance-card.go.tmpl +++ b/web/templates/instance-card.go.tmpl @@ -41,11 +41,15 @@ {{if and (eq .NodeStatus "online") (eq .Status "running")}} - + + + {{else if and (eq .NodeStatus "online") (eq .Status "stopped")}} - + + + {{else if and (eq .NodeStatus "online") (eq .Status "loading")}}