added execution history controller

This commit is contained in:
dcore94 2023-01-26 15:03:47 +01:00
parent 90b8348d8c
commit 2c4352c7c5
1 changed files with 261 additions and 0 deletions

View File

@ -0,0 +1,261 @@
class CCPExecutionHistory extends HTMLElement {
#boot = null;
#rootdoc = null;
#serviceurl = null;
#broadcasturl = null;
#executions = [];
#socket = null;
constructor(){
super()
this.#boot = document.querySelector("d4s-boot-2")
this.#rootdoc = this.attachShadow({ "mode" : "open"})
this.#serviceurl = this.getAttribute("serviceurl")
this.#broadcasturl = this.getAttribute("broadcasturl")
if(!this.#broadcasturl){
this.#broadcasturl = this.#serviceurl.replace(/^http/, "ws")
}
this.#broadcasturl = this.#broadcasturl + "/ws/notification"
this.connectNewExecution()
this.connectBroadcast()
}
connectedCallback(){
this.#rootdoc.innerHTML = this.render()
this.refreshExecutions()
}
render(){
return `
<style>
.noselect{
user-select: none;
}
.lxd{
background-color: #dd4814;
color: white;
}
.docker{
color: white;
background-color: #2496ed;
}
.ccp-toolbar-button {
font-weight: bold;
padding: 0.3rem !important;
line-height: .8rem !important;
cursor: pointer;
}
.ccp-toolbar-button svg {
fill: white;
width: 24px;
height: 24px;
pointer-events: none;
}
</style>
<template id="EXECUTIOM_LIST_TEMPLATE">
<ol name="ccp_execution_list" class="ccp-execution-list list-group">
<li class="ccp-execution-item list-group-item" style="border: none">
<details open>
<summary class="noselect">
<span name="runtime" class="badge"></span>
<h5 style="display:inline"></h5>
<span name="status" class="badge"></span>
<button data-index="0" name="delete" title="Delete" class="btn btn-danger ccp-toolbar-button">
<svg viewBox="0 0 24 24">
<path d="M19,4H15.5L14.5,3H9.5L8.5,4H5V6H19M6,19A2,2 0 0,0 8,21H16A2,2 0 0,0 18,19V7H6V19Z"></path>
</svg>
</button>
</summary>
<p name="message" class="font-weight-light font-italic" style="margin-top:revert">
<span name="updated"></span>:
<span name="message" class="ml-1"></span>
</p>
<ul class="list-group">
<li class="list-group-item" style="border: none"></li>
</ul>
</details>
</li>
</ol>
</template>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<ol name="ccp_execution_list" style="display:none"></ol>
`
}
refreshExecution(id){
this.#boot.secureFetch(`${this.#serviceurl}/executions?id=${id}`).then(reply =>{
if(reply.status === 200) return reply.json();
else throw `Unable to load execution ${id}`
}).then(data=>{
const exec = data[0]
for(var i=0; i < this.#executions.length; i++){
if(this.#executions[i].id == exec.id){
this.#executions[i] = exec
break
}
if(i === this.#executions.length){
this.#executions = data.concat(this.#executions)
}
}
BSS.apply(this.execution_list_bss, this.#rootdoc)
}).catch(err=>{ console.error(err)})
}
deleteExecution(id){
this.#boot.secureFetch(`${this.#serviceurl}/executions/${id}`, { method: "DELETE"}).then(reply =>{
if(reply.status === 200) this.refreshExecutions();
else throw `Unable to delete execution ${id}`
}).catch(err=>{ console.error(err)})
}
refreshExecutions(){
this.#boot.secureFetch(`${this.#serviceurl}/executions`).then(reply =>{
if(reply.status === 200) return reply.json();
else throw "Unable to load executions"
}).then(data=>{
this.#executions = data
BSS.apply(this.execution_list_bss, this.#rootdoc)
}).catch(err=>{ console.error(err)})
}
connectNewExecution(){
document.addEventListener("newexecution", ev=>{
this.#executions = [ {id: ev.detail } ].concat(this.#executions)
})
}
connectBroadcast(){
this.#socket = new WebSocket(this.#broadcasturl + "/executions");
this.#socket.onmessage = event=>{
const data = JSON.parse(event.data)
let exec = this.#executions.filter(e=>e.id === data.jobID)[0]
if(exec){
this.refreshExecution(exec.id)
}
}
window.setInterval( ()=>this.#socket.send("ping"), 30000)
}
download(url, name) {
this.#boot.secureFetch(url).then(reply => {
if (reply.status !== 200) {
throw "Unable to download"
}
return reply.blob()
}).then(blob => {
const objectURL = URL.createObjectURL(blob)
var tmplnk = document.createElement("a")
tmplnk.download = name
tmplnk.href = objectURL
//tmplnk.target="_blank"
document.body.appendChild(tmplnk)
tmplnk.click()
document.body.removeChild(tmplnk)
}).catch(err => console.error(err))
}
execution_list_bss = {
template : "#EXECUTIOM_LIST_TEMPLATE",
target : "ol[name=ccp_execution_list]",
in : ()=>{ return {executions : this.#executions} },
recurse:[
{
target : "li",
in : (e,d)=>d.executions,
apply: (e,d,i)=>e.setAttribute("data-index", i),
on_click: ev=>{
if(ev.target.getAttribute("name") === "delete"){
if(window.confirm("Confirm deletion of this execution?")){
const index = Number(ev.target.getAttribute("data-index"))
this.deleteExecution(this.#executions[index].id)
}
}
},
recurse : [
{
target : "details",
apply : (e,d)=>{
e.alt = e.title = d.id
if(sessionStorage.getItem(d.id) === "open") e.open = "open";
else e.removeAttribute("open");
},
on_toggle : ev=>{
if(ev.target.open){
sessionStorage.setItem(ev.currentTarget.alt, 'open')
}else{
sessionStorage.removeItem(ev.currentTarget.alt)
}
}
},
{
target : "span[name=runtime]",
apply : (e,d)=>{
e.classList.add(d.infrastructuretype)
e.title = e.alt = `${d.runtime} (image: ${d.runtimeimage}) on ${d.infrastructure}`
e.textContent = d.runtime
}
},
{
target : "h5",
apply : (e,d)=>{
e.textContent = `${d.method} v. ${d.methodversion}`
}
},
{
target : "span[name=updated]",
apply : (e,d)=>{
const dt = new Date(d.updated)
e.textContent = `Last update ${dt.toLocaleDateString()} @ ${dt.toLocaleTimeString()}`
}
},
{
target : "span[name=status]",
apply : (e,d)=>{
if(d.status){
const status = d.status
e.textContent = status
if (status === "running") e.classList.add("badge-primary");
else if (status === "successful") e.classList.add("badge-success");
else if (status === "failure") e.classList.add("badge-danger");
else e.classList.add("badge-secondary");
}
}
},
{
target : "span[name=message]",
apply : (e,d)=>{
if(d.message){
e.textContent = d.message
}
}
},
{
target : "ul",
recurse : [
{
target : "li",
"in" : (e,d)=>{
return d.resources.map(l=>{
return { href : this.#serviceurl + "/executions/" + d.id + "/" + l.path, path : l.path}
})
},
on_click : ev=>{
const href = ev.currentTarget.bss_input.data.href
const name = ev.currentTarget.bss_input.data.path
this.download(href, name)
},
apply : (e,d)=>{
e.innerHTML = `<a href="${d.href}" onclick="event.preventDefault()">${d.path}</a>`
}
}
]
}
]
}
]
}
}
window.customElements.define('d4s-ccp-executionhistory', CCPExecutionHistory);