2023-04-06 21:21:11 +00:00
import { requestPVE , requestAPI , goToPage , goToURL , instances , nodes } from "./utils.js" ;
2023-05-12 21:26:26 +00:00
import { alert , dialog } from "./dialog.js" ;
2022-12-16 07:03:50 +00:00
2023-01-30 22:21:05 +00:00
export class Instance extends HTMLElement {
2022-12-12 04:20:32 +00:00
constructor ( ) {
super ( ) ;
let shadowRoot = this . attachShadow ( { mode : "open" } ) ;
2023-01-26 19:33:39 +00:00
shadowRoot . innerHTML = `
2023-04-11 21:38:51 +00:00
< link rel = "stylesheet" href = "https://www.w3schools.com/w3css/4/w3.css" >
< link rel = "stylesheet" href = "css/style.css" >
2023-05-02 03:42:58 +00:00
< div class = "w3-row" >
2023-04-12 22:59:57 +00:00
< div class = "w3-col l1 m2 s6" >
2023-04-11 21:38:51 +00:00
< p id = "instance-id" > < / p >
< / d i v >
2023-04-12 22:59:57 +00:00
< div class = "w3-col l2 m3 s6" >
2023-04-11 21:38:51 +00:00
< p id = "instance-name" > < / p >
< / d i v >
2023-04-12 22:59:57 +00:00
< div class = "w3-col l1 m2 w3-hide-small" >
2023-04-11 21:38:51 +00:00
< p id = "instance-type" > < / p >
< / d i v >
2023-04-21 22:58:15 +00:00
< div class = "w3-col l2 m3 s6 flex row nowrap" >
2023-04-11 21:38:51 +00:00
< img id = "instance-status-icon" >
< p id = "instance-status" > < / p >
< / d i v >
2023-04-12 22:59:57 +00:00
< div class = "w3-col l2 w3-hide-medium w3-hide-small" >
2023-04-11 21:38:51 +00:00
< p id = "node-name" > < / p >
< / d i v >
2023-04-21 22:58:15 +00:00
< div class = "w3-col l2 w3-hide-medium w3-hide-small flex row nowrap" >
2023-04-11 21:38:51 +00:00
< img id = "node-status-icon" >
< p id = "node-status" > < / p >
< / d i v >
2023-04-22 04:49:17 +00:00
< div class = "w3-col l2 m2 s6 flex row nowrap" style = "height: 1lh; margin-top: 15px; margin-bottom: 15px;" >
2023-04-11 21:38:51 +00:00
< img id = "power-btn" class = "clickable" >
< img id = "console-btn" class = "clickable" >
< img id = "configure-btn" class = "clickable" >
< img id = "delete-btn" class = "clickable" >
< / d i v >
< / d i v >
2023-01-26 19:33:39 +00:00
` ;
2022-12-12 04:20:32 +00:00
this . shadowElement = shadowRoot ;
2022-12-19 00:53:07 +00:00
this . actionLock = false ;
2022-12-12 04:20:32 +00:00
}
set data ( data ) {
2023-01-17 20:36:34 +00:00
if ( data . status === "unknown" ) {
data . status = "stopped" ;
}
2022-12-16 07:03:50 +00:00
this . type = data . type ;
this . status = data . status ;
2023-01-26 20:50:15 +00:00
this . vmid = data . vmid ;
this . name = data . name ;
this . node = data . node ;
this . update ( ) ;
}
update ( ) {
2022-12-15 00:10:28 +00:00
let vmidParagraph = this . shadowElement . querySelector ( "#instance-id" ) ;
2023-01-26 20:50:15 +00:00
vmidParagraph . innerText = this . vmid ;
2022-12-14 23:28:22 +00:00
2022-12-15 00:10:28 +00:00
let nameParagraph = this . shadowElement . querySelector ( "#instance-name" ) ;
2023-01-26 20:50:15 +00:00
nameParagraph . innerText = this . name ? this . name : "" ;
2022-12-14 23:38:13 +00:00
2023-04-06 04:21:03 +00:00
let typeParagraph = this . shadowElement . querySelector ( "#instance-type" ) ;
typeParagraph . innerText = this . type ;
let statusParagraph = this . shadowElement . querySelector ( "#instance-status" ) ;
statusParagraph . innerText = this . status ;
2023-04-06 21:21:11 +00:00
let statusIcon = this . shadowElement . querySelector ( "#instance-status-icon" ) ;
statusIcon . src = instances [ this . status ] . statusSrc ;
statusIcon . alt = instances [ this . status ] . statusAlt ;
2023-04-06 04:21:03 +00:00
let nodeNameParagraph = this . shadowElement . querySelector ( "#node-name" ) ;
nodeNameParagraph . innerText = this . node . name ;
2022-12-14 23:28:22 +00:00
2023-04-06 04:21:03 +00:00
let nodeStatusParagraph = this . shadowElement . querySelector ( "#node-status" ) ;
nodeStatusParagraph . innerText = this . node . status ;
2022-12-15 01:20:31 +00:00
2023-04-06 21:21:11 +00:00
let nodeStatusIcon = this . shadowElement . querySelector ( "#node-status-icon" ) ;
nodeStatusIcon . src = nodes [ this . node . status ] . statusSrc ;
nodeStatusIcon . alt = nodes [ this . node . status ] . statusAlt ;
2022-12-16 02:04:20 +00:00
let powerButton = this . shadowElement . querySelector ( "#power-btn" ) ;
2023-01-26 20:50:15 +00:00
powerButton . src = instances [ this . status ] . powerButtonSrc ;
powerButton . alt = instances [ this . status ] . powerButtonAlt ;
2023-02-01 00:02:10 +00:00
powerButton . title = instances [ this . status ] . powerButtonAlt ;
2023-02-27 23:03:19 +00:00
powerButton . onclick = this . handlePowerButton . bind ( this )
2022-12-19 00:53:07 +00:00
2023-01-26 20:50:15 +00:00
let configButton = this . shadowElement . querySelector ( "#configure-btn" ) ;
configButton . src = instances [ this . status ] . configButtonSrc ;
configButton . alt = instances [ this . status ] . configButtonAlt ;
2023-02-01 00:02:10 +00:00
configButton . title = instances [ this . status ] . configButtonAlt ;
2023-02-27 23:03:19 +00:00
configButton . onclick = this . handleConfigButton . bind ( this ) ;
2022-12-18 00:37:26 +00:00
2023-02-14 05:14:33 +00:00
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 ;
2023-02-27 23:03:19 +00:00
consoleButton . onclick = this . handleConsoleButton . bind ( this ) ;
2023-02-14 05:14:33 +00:00
2023-02-21 19:57:47 +00:00
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 ;
2023-02-27 23:03:19 +00:00
deleteButton . onclick = this . handleDeleteButton . bind ( this ) ;
2023-02-21 19:57:47 +00:00
2023-01-26 20:50:15 +00:00
if ( this . node . status !== "online" ) {
powerButton . classList . add ( "hidden" ) ;
configButton . classList . add ( "hidden" ) ;
2023-02-14 05:14:33 +00:00
consoleButton . classList . add ( "hidden" ) ;
2023-02-21 19:57:47 +00:00
deleteButton . classList . add ( "hidden" ) ;
2023-01-26 20:50:15 +00:00
}
}
2022-12-18 00:37:26 +00:00
2023-01-26 20:50:15 +00:00
async handlePowerButton ( ) {
2023-02-21 19:57:47 +00:00
2023-01-26 20:50:15 +00:00
if ( ! this . actionLock ) {
2023-05-05 21:43:15 +00:00
let header = ` ${ this . status === "running" ? "Stop" : "Start" } VM ${ this . vmid } ` ;
let body = ` <p>Are you sure you want to ${ this . status === "running" ? "stop" : "start" } VM</p><p> ${ this . vmid } </p> `
2022-12-19 05:00:58 +00:00
2023-05-05 21:43:15 +00:00
dialog ( header , body , async ( result , form ) => {
2023-02-21 19:57:47 +00:00
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" ;
2023-01-17 20:45:16 +00:00
2023-01-26 20:50:15 +00:00
this . update ( ) ;
2023-02-21 19:57:47 +00:00
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 ) {
2023-05-11 07:13:41 +00:00
let taskStatus = await requestPVE ( ` /nodes/ ${ this . node . name } /tasks/ ${ result . data } /status ` , "GET" ) ;
2023-02-21 19:57:47 +00:00
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 ;
2023-05-12 21:26:26 +00:00
alert ( ` attempted to ${ targetAction } ${ this . vmid } but process returned stopped: ${ result . data . exitstatus } ` ) ;
2023-02-21 19:57:47 +00:00
this . update ( ) ;
this . actionLock = false ;
break ;
}
else { // task has not stopped
await waitFor ( 1000 ) ;
}
}
2023-01-26 20:50:15 +00:00
}
2023-05-05 21:43:15 +00:00
} ) ;
2023-01-17 20:45:16 +00:00
}
2022-12-12 04:20:32 +00:00
}
2023-01-27 21:49:50 +00:00
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 } ) ;
}
}
2023-02-14 05:14:33 +00:00
handleConsoleButton ( ) {
2023-02-21 22:50:01 +00:00
if ( ! this . actionLock && this . status === "running" ) {
2023-02-17 05:12:28 +00:00
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 ( "https://pve.tronnet.net" , data , true ) ;
2023-02-14 05:14:33 +00:00
}
}
2023-02-21 19:57:47 +00:00
2023-02-21 22:50:01 +00:00
handleDeleteButton ( ) {
if ( ! this . actionLock && this . status === "stopped" ) {
2023-05-05 21:43:15 +00:00
let header = ` Delete VM ${ this . vmid } ` ;
let body = ` <p>Are you sure you want to <strong>delete</strong> VM </p><p> ${ this . vmid } </p> `
2023-02-21 22:50:01 +00:00
2023-05-05 21:43:15 +00:00
dialog ( header , body , async ( result , form ) => {
2023-02-21 22:50:01 +00:00
if ( result === "confirm" ) {
this . actionLock = true ;
2023-02-28 23:56:39 +00:00
let prevStatus = this . status ;
2023-02-21 22:50:01 +00:00
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 {
2023-05-12 21:26:26 +00:00
alert ( result . error ) ;
2023-02-28 23:56:39 +00:00
this . status = this . prevStatus ;
this . update ( ) ;
this . actionLock = false ;
2023-02-21 22:50:01 +00:00
}
}
2023-05-05 21:43:15 +00:00
} ) ;
2023-02-21 22:50:01 +00:00
}
}
2022-12-12 04:20:32 +00:00
}
2023-04-03 22:49:24 +00:00
customElements . define ( "instance-obj" , Instance ) ;