diff --git a/ccp/js/executionhistorycontroller.js b/ccp/js/executionhistorycontroller.js
index b3bc15f..0b11e66 100644
--- a/ccp/js/executionhistorycontroller.js
+++ b/ccp/js/executionhistorycontroller.js
@@ -1,11 +1,13 @@
class CCPExecutionHistory extends HTMLElement {
-
+
#boot = null;
#rootdoc = null;
#serviceurl = null;
#broadcasturl = null;
- #executions = [];
+ #data = [];
+ #filtered = [];
#socket = null;
+ #searchfield = null;
constructor(){
super()
@@ -22,12 +24,12 @@ class CCPExecutionHistory extends HTMLElement {
}
connectedCallback(){
- this.#rootdoc.innerHTML = this.render()
+ this.render()
this.refreshExecutions()
}
render(){
- return `
+ this.#rootdoc.innerHTML = `
-
- -
-
-
-
-
-
-
-
+
+ -
+
+
-
- :
-
-
-
-
+
+ -
+
+
+
+
+
+
+
+
+ :
+
+
+
+
+
+
-
+
-
+
`
+ this.#rootdoc.querySelector("button[name=refresh]").addEventListener("click", ev=>{
+ this.refreshExecutions()
+ })
+
+ this.#searchfield = this.#rootdoc.querySelector("input[name=search]")
+ this.#searchfield.addEventListener("input", ev=>{
+ this.updateList()
+ })
+ }
+
+ updateList(){
+ const filter = this.#searchfield.value
+ if(filter === "" || filter == null || filter == undefined){
+ this.#filtered = this.#data
+ }else{
+ const f = filter.toLowerCase()
+ this.#filtered = this.#data.filter(d=>{
+ return false ||
+ (d.status.toLowerCase().indexOf(f) !== -1)||
+ (d.method.indexOf(f) !== -1)
+ })
+ }
+ this.groupBy()
+ BSS.apply(this.#execution_list_bss, this.#rootdoc)
+ }
+
+ groupBy(){
+ this.#filtered = this.#filtered.reduce((catalog, exec)=>{
+ const category = exec.method
+ catalog[category] = catalog[category] ?? []
+ catalog[category].push(exec)
+ return catalog
+ }, {})
}
refreshExecution(id){
@@ -92,16 +178,16 @@ class CCPExecutionHistory extends HTMLElement {
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
+ for(var i=0; i < this.#data.length; i++){
+ if(this.#data[i].id == exec.id){
+ this.#data[i] = exec
break
}
- if(i === this.#executions.length){
- this.#executions = data.concat(this.#executions)
+ if(i === this.#data.length){
+ this.#data = data.concat(this.#data)
}
}
- BSS.apply(this.execution_list_bss, this.#rootdoc)
+ this.updateList()
}).catch(err=>{ console.error(err)})
}
@@ -117,14 +203,14 @@ class CCPExecutionHistory extends HTMLElement {
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)
+ this.#data = data
+ this.updateList()
}).catch(err=>{ console.error(err)})
}
connectNewExecution(){
document.addEventListener("newexecution", ev=>{
- this.#executions = [ {id: ev.detail } ].concat(this.#executions)
+ this.#data = [ {id: ev.detail } ].concat(this.#data)
})
}
@@ -132,7 +218,7 @@ class CCPExecutionHistory extends HTMLElement {
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]
+ let exec = this.#data.filter(e=>e.id === data.jobID)[0]
if(exec){
this.refreshExecution(exec.id)
}
@@ -159,17 +245,17 @@ class CCPExecutionHistory extends HTMLElement {
}).catch(err => console.error(err))
}
- downloadZIP(id){
+ export(id, mime, filename){
this.#boot.secureFetch(`${this.#serviceurl}/executions/${id}`,
- { method: "GET", headers : { "Accept" : "application/zip"} }).then(reply =>{
+ { method: "GET", headers : { "Accept" : mime} }).then(reply =>{
if (reply.status !== 200) {
- throw "Unable to download"
+ throw "Unable to export " + mime
}
return reply.blob()
}).then(blob => {
const objectURL = URL.createObjectURL(blob)
var tmplnk = document.createElement("a")
- tmplnk.download = id + ".zip"
+ tmplnk.download = filename
tmplnk.href = objectURL
document.body.appendChild(tmplnk)
tmplnk.click()
@@ -177,33 +263,20 @@ class CCPExecutionHistory extends HTMLElement {
}).catch(err=>{ console.error(err)})
}
- execution_list_bss = {
+ #execution_list_bss = {
template : "#EXECUTIOM_LIST_TEMPLATE",
- target : "ol[name=ccp_execution_list]",
- in : ()=>{ return {executions : this.#executions} },
+ target : "ul[name=ccp_execution_list]",
+ in : ()=>this,
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.currentTarget.getAttribute("data-index"))
- this.deleteExecution(this.#executions[index].id)
- }
- }
- if(ev.target.getAttribute("name") === "zip"){
- const index = Number(ev.currentTarget.getAttribute("data-index"))
- this.downloadZIP(this.#executions[index].id)
- }
- },
- recurse : [
+ target : "li.ccp-method-item",
+ "in" : (e,d)=>Object.keys(this.#filtered),
+ recurse: [
{
- target : "details",
+ target : "details[name=level1]",
apply : (e,d)=>{
- e.alt = e.title = d.id
- if(sessionStorage.getItem(d.id) === "open") e.open = "open";
+ e.alt = e.title = d
+ if(sessionStorage.getItem(d) === "open") e.open = "open";
else e.removeAttribute("open");
},
on_toggle : ev=>{
@@ -212,68 +285,118 @@ class CCPExecutionHistory extends HTMLElement {
}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 : "summary.ccp-method-item-header h5",
+ apply : (e,d) => { e.textContent = d }
},
{
- target : "h5",
- apply : (e,d)=>{
- e.textContent = `${d.method} v. ${d.methodversion}`
- }
+ target : "summary.ccp-method-item-header span[name=accepted]",
+ apply : (e,d) => { e.textContent = this.#filtered[d].filter(x=>x.status === 'accepted').length }
},
{
- target : "span[name=updated]",
- apply : (e,d)=>{
- const dt = new Date(d.updated)
- e.textContent = `Last update ${dt.toLocaleDateString()} @ ${dt.toLocaleTimeString()}`
- }
+ target : "summary.ccp-method-item-header span[name=failed]",
+ apply : (e,d) => { e.textContent = this.#filtered[d].filter(x=>x.status === 'failed').length }
},
{
- 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 : "summary.ccp-method-item-header span[name=successful]",
+ apply : (e,d) => { e.textContent = this.#filtered[d].filter(x=>x.status === 'successful').length }
+ },
+ {
+ target : "summary.ccp-method-item-header span[name=running]",
+ apply : (e,d) => { e.textContent = this.#filtered[d].filter(x=>x.status === 'running').length }
+ },
+ {
+ target : "li.ccp-execution-item",
+ "in" : (e,d)=>this.#filtered[d],
+ apply : (e,d)=>e.setAttribute("data-index", d.id),
+ on_click: ev=>{
+ if(ev.target.getAttribute("name") === "delete"){
+ if(window.confirm("Confirm deletion of this execution?")){
+ const id = ev.currentTarget.getAttribute("data-index")
+ this.deleteExecution(id)
+ }
}
- }
- },
- {
- target : "span[name=message]",
- apply : (e,d)=>{
- if(d.message){
- e.textContent = d.message
+ if(ev.target.getAttribute("name") === "zip"){
+ const id = ev.currentTarget.getAttribute("data-index")
+ this.export(id, "application/zip", id + ".zip")
}
- }
- },
- {
- target : "ul",
+ if(ev.target.getAttribute("name") === "provo"){
+ const id = ev.currentTarget.getAttribute("data-index")
+ this.export(id, "application/prov-o+xml", id + ".xml")
+ }
+ },
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)
- },
+ target : "details",
apply : (e,d)=>{
- e.innerHTML = `${d.path}`
+ 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=version]",
+ apply : (e,d)=>{
+ e.textContent = `${d.methodversion}`
+ }
+ },
+ {
+ 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=updated]",
+ apply : (e,d)=>{
+ const dt = new Date(d.updated)
+ e.textContent = `Last update ${dt.toLocaleDateString()} @ ${dt.toLocaleTimeString()}`
+ }
+ },
+ {
+ 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 = `${d.path}`
+ }
+ }
+ ]
}
]
}