Files
OliveTin/webui.dev/js/ActionButton.js
James Read dc6f6c2896 feature: Kill support in the UI (#297)
* feature: Kill command API (wip)

* feature: Kill support in the UI
2024-04-27 21:51:45 +00:00

158 lines
4.2 KiB
JavaScript

import './ExecutionButton.js'
import './ArgumentForm.js'
import { ExecutionFeedbackButton } from './ExecutionFeedbackButton.js'
class ActionButton extends ExecutionFeedbackButton {
constructDomFromTemplate () {
const tpl = document.getElementById('tplActionButton')
const content = tpl.content.cloneNode(true)
/*
* FIXME: Should probably be using a shadowdom here, but seem to
* get an error when combined with custom elements.
*/
this.appendChild(content)
this.btn = this.querySelector('button')
this.domTitle = this.btn.querySelector('.title')
this.domIcon = this.btn.querySelector('.icon')
}
constructFromJson (json) {
this.updateIterationTimestamp = 0
this.constructDomFromTemplate()
// Class attributes
this.updateFromJson(json)
this.actionId = json.id
// DOM Attributes
this.setAttribute('role', 'none')
this.setAttribute('id', 'actionButton-' + this.actionId)
this.btn.setAttribute('id', 'actionButtonInner-' + this.actionId)
this.btn.title = json.title
this.btn.onclick = () => {
if (json.arguments.length > 0) {
for (const oldArgumentForm of document.querySelectorAll('argument-form')) {
oldArgumentForm.remove()
}
const frm = document.createElement('argument-form')
frm.setup(json, (args) => {
this.startAction(args)
})
document.body.appendChild(frm)
frm.querySelector('dialog').showModal()
} else {
this.startAction()
}
}
this.popupOnStart = json.popupOnStart
this.updateFromJson(json)
this.domTitle.innerText = this.btn.title
this.domIcon.innerHTML = this.unicodeIcon
}
updateFromJson (json) {
// Fields that should not be updated
//
// title - as the callback URL relies on it
if (json.icon === '') {
this.unicodeIcon = '&#x1f4a9'
} else {
this.unicodeIcon = unescape(json.icon)
}
this.domIcon.innerHTML = this.unicodeIcon
}
onExecStatusChanged () {
this.btn.disabled = false
setTimeout(() => {
this.updateDom(null, this.btn.title)
}, 2000)
}
getUniqueId () {
if (window.isSecureContext) {
return window.crypto.randomUUID()
} else {
return Date.now().toString()
}
}
startAction (actionArgs) {
this.btn.classList = [] // Removes old animation classes
if (actionArgs === undefined) {
actionArgs = []
}
// UUIDs are create client side, so that we can setup a "execution-button"
// to track the execution before we send the request to the server.
const startActionArgs = {
actionId: this.actionId,
arguments: actionArgs,
uniqueTrackingId: this.getUniqueId()
}
this.onActionStarted(startActionArgs.uniqueTrackingId)
window.fetch(window.restBaseUrl + 'StartAction', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(startActionArgs)
}).then((res) => {
if (res.ok) {
return res.json()
} else {
throw new Error(res.statusText)
}
}
).then((json) => {
// The button used to wait for the action to finish, but now it is fire & forget
}).catch(err => {
throw err // We used to flash buttons red, but now hand to the global error handler
})
}
onActionStarted (executionTrackingId) {
if (this.popupOnStart === 'execution-button') {
const btnExecution = document.createElement('execution-button')
btnExecution.constructFromJson(executionTrackingId)
this.querySelector('.action-button-footer').hidden = false
this.querySelector('.action-button-footer').style.display = 'flex'
this.querySelector('.action-button-footer').prepend(btnExecution)
return
}
if (this.popupOnStart.includes('execution-dialog')) {
window.executionDialog.reset()
if (this.popupOnStart === 'execution-dialog-stdout-only') {
window.executionDialog.hideEverythingApartFromOutput()
}
window.executionDialog.executionTrackingId = executionTrackingId
window.executionDialog.show(this)
}
this.btn.disabled = true
}
}
window.customElements.define('action-button', ActionButton)