diff --git a/ccp/js/executionmonitorcontroller.js b/ccp/js/executionmonitorcontroller.js deleted file mode 100644 index 2fdcac6..0000000 --- a/ccp/js/executionmonitorcontroller.js +++ /dev/null @@ -1,183 +0,0 @@ -class CCPExecutionMonitor extends HTMLElement { - - #boot = null; - #rootdoc = null; - #serviceurl = null; - #broadcasturl = null; - #executions = []; - #socket = null; - #interval = 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.connectBroadcast() - } - - connectedCallback(){ - this.#rootdoc.innerHTML = this.renderDeprecated() - } - - renderDeprecated(){ - return ` -
- DEPRECATED! -
- ` - } - - render(){ - return ` - - -
    - ` - } - - addExecution(execution){ - this.#executions.push(execution) - this.refreshExecution(execution) - } - - refreshExecution(execution){ - this.#boot.secureFetch(`${this.#serviceurl}/executions/${execution.jobID}`).then(reply =>{ - if(reply.status === 200) return reply.json(); - else throw "Unable to load job links" - }).then(data=>{ - execution.links = data - BSS.apply(this.execution_list_bss, this.#rootdoc) - }).catch(err=>{ console.error(err)}) - } - - 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.jobID === data.jobID)[0] - if(exec){ - exec.events.push(data) - if(!exec.self) exec.self = data.links[0].href; - this.refreshExecution(exec) - } - } - this.#interval = window.setInterval( ()=>{ - if(this.#socket.readyState === 3){ - this.#socket.close() - window.clearInterval(this.#interval) - this.connectBroadcast() - }else{ - 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)=>{ - if(d.events && d.events.length > 0){ - e.alt = e.title = (new Date(d.events[d.events.length - 1].updated)).toLocaleString() - } - }, - recurse : [ - { - target : "h5", - apply : (e,d)=>{ - e.textContent = d.method - } - }, - { - target : "span[name=status]", - apply : (e,d)=>{ - if(d.events && d.events.length > 0){ - const status = d.events[d.events.length - 1].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 : ".status-message", - apply : (e,d)=>{ - if(d.events && d.events.length > 0){ - e.textContent = d.events[d.events.length - 1].message - } - } - }, - { - target : "ul", - recurse : [ - { - target : "li", - "in" : (e,d)=>{ - return d.links.map(l=>{ - return { href : this.#serviceurl + "/executions/" + d.jobID + "/" + 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}` - } - } - ] - } - ] - } - ] - } -} -window.customElements.define('d4s-ccp-executionmonitor', CCPExecutionMonitor); diff --git a/ccp/js/methodlistcontroller.js b/ccp/js/methodlistcontroller.js index 1c19c73..771953d 100644 --- a/ccp/js/methodlistcontroller.js +++ b/ccp/js/methodlistcontroller.js @@ -1,230 +1,361 @@ class CCPMethodList extends HTMLElement{ - #boot; - #rootdoc; - #data; - #filtered; - #dragged = null; + #boot; + #rootdoc; + #data; + #filtered; + #dragged = null; + #searchfield = null; + + #serviceurl; + + constructor(){ + super() + this.#boot = document.querySelector("d4s-boot-2") + this.#serviceurl = this.getAttribute("serviceurl") + this.#rootdoc = this.attachShadow({ "mode" : "open"}) + this.render() + this.fetchProcesses() + } - #serviceurl; - - constructor(){ - super() - this.#boot = document.querySelector("d4s-boot-2") - this.#serviceurl = this.getAttribute("serviceurl") - this.#rootdoc = this.attachShadow({ "mode" : "open"}) - this.render() - this.fetchProcesses() - } - - render(){ - this.#rootdoc.innerHTML = ` -
    + render(){ + this.#rootdoc.innerHTML = ` + + -
    - -
      +
      +
      +
      +
      + List of available methods +
      +
      + +
      +
      +
      +
      +
      + +
      +
      +
        +
        +
        -
        - ` - } - - connectedCallback(){ - - } - - fetchProcesses(){ - console.log("Calling fetch processes") - this.#boot.secureFetch(this.#serviceurl + "/methods"). - then(resp=>{ - console.log("Received resp for processes ", resp.status) - return resp.json() - }).then(data=>{ - console.log("Processes parsed to json", data) - this.#data = data - this.showList() - }).catch(err=>{ - alert("Error while downloading methods: ", err) - }) - } - - showList(){ - this.enableSearch() - this.updateList() - } - - updateList(filter){ - if(filter === "" || filter == null || filter == undefined){ - this.#filtered = [] - }else{ - const f = filter.toLowerCase() - this.#filtered = this.#data.filter(d=>{ - return false || - (d.title.toLowerCase().indexOf(f) !== -1)|| - (d.description.indexOf(f) !== -1) || - (d.keywords.map(k=>k.toLowerCase()).indexOf(f) !== -1) + ` + + this.#rootdoc.querySelector("button[name=refresh]").addEventListener("click", ev=>{ + this.fetchProcesses() + }) + + this.#searchfield = this.#rootdoc.querySelector("input[name=search]") + this.#searchfield.addEventListener("input", ev=>{ + this.updateList() }) } - BSS.apply(this.#process_list_bss, this.#rootdoc) - } - enableSearch(){ - const search = this.#rootdoc.querySelector("input[name=search]") - search.addEventListener("input", ev=>{ - this.updateList(ev.currentTarget.value) - }) - } + connectedCallback(){ + + } - #process_list_bss = { - template : "#PROCESS_LIST_TEMPLATE", - target : "ul[name=process_list]", - "in" : this, - recurse : [ - { - target : "li", - "in" : (e,d)=>this.#filtered, - on_dragstart : ev=>{ - ev.dataTransfer.effectAllowed = 'move' - ev.dataTransfer.setData('text/html', ev.currentTarget.innerHTML) - ev.dataTransfer.setData('text/plain+ccpmethod', ev.currentTarget.bss_input.data.id) - ev.dataTransfer.setData('application/json+ccpmethod', JSON.stringify(ev.currentTarget.bss_input.data)) - }, - on_dragend : ev=>{ - ev.preventDefault() - }, - recurse : [ - { - target : "h4", - apply : (e,d)=>{ e.textContent = `${d.title} v. ${d.version}` } - }, - { - target : "i", - apply : (e,d)=>{ e.textContent = d.description } - }, - { - target : "ul[name=authors]", - recurse : { - target : "li", - "in" : (e,d)=>d.metadata.filter(md=>md.role === "author"), - apply : (e,d)=>{ e.textContent = d.title } - } - }, - { - target : "ul[name=keywords]", - recurse : { - target : "li", - "in" : (e,d)=>d.keywords, - apply : (e,d)=>{ e.alt = e.title = e.textContent = d } - } + fetchProcesses(){ + console.log("Calling fetch processes") + this.#boot.secureFetch(this.#serviceurl + "/methods"). + then(resp=>{ + console.log("Received resp for processes ", resp.status) + return resp.json() + }).then(data=>{ + console.log("Processes parsed to json", data) + this.#data = data + this.updateList() + return this.fetchInfrastructures() + }).then(d => { + this.updateList() + }).catch(err=>{ + alert("Error while downloading methods") + console.error("Error while downloading methods: " + err) + }) + } + + fetchInfrastructures(){ + const url = this.#serviceurl + "/infrastructures" + this.#boot.secureFetch(url). + then(resp=>{ + if(resp.status !== 200) throw "Unable to fetch infrastructures " + resp.status; + else return resp.json() + }).then(infras=>{ + for(let m=0; m < this.#data.length; m++){ + const method = this.#data[m] + method["executable"] = false + for(let i=0; i < infras.length; i++){ + const infra = infras[i] + const matches = method.links.filter(l => l.rel === "compatibleWith" && l.href === "infrastructures/" + infra.id) + if(matches.length > 0){ + method["executable"] = true + break + } } - ] - } - ] + } + this.updateList() + }).catch(err=>{ + alert("Error while checking runtimes for method") + console.error("Error while checking runtimes for method: " + err) + }) + } + + 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.title.toLowerCase().indexOf(f) !== -1)|| + (d.description.indexOf(f) !== -1) || + (d.keywords.map(k=>k.toLowerCase()).filter(i=>i.indexOf(f) !== -1)).length + }) + } + this.groupBy() + BSS.apply(this.#process_list_bss, this.#rootdoc) + } + + groupBy(){ + this.#filtered = this.#filtered.reduce((catalog, meth)=>{ + const category = meth.title + catalog[category] = catalog[category] ?? [] + catalog[category].push(meth) + return catalog + }, {}) + } + + exportCategory(category){ + Promise.all( + this.#filtered[category].map(m=>this.exportMethod(m.id)) + ) + } + + exportMethod(method){ + this.#boot.secureFetch(this.#serviceurl + "/methods/" + method + "/shareable").then( + (resp)=>{ + if(resp.status === 200){ + return resp.json() + }else throw "Error exporting sharable process: " + resp.status + } + ).then(data=>{ + const filename = data.title + "-" + data.version + ".json" + const datastr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); + var tmplnk = document.createElement("a") + tmplnk.download = filename + tmplnk.href = datastr + document.body.appendChild(tmplnk) + tmplnk.click() + document.body.removeChild(tmplnk) + }).catch(err=>{ + console.log(err) + }) + } + + importMethods(files){ + if(files && files.length) { + let formdata = new FormData(); + files.reduce((formdata, f)=>{ + formdata.append("files[]", f) + return formdata + }, formdata) + this.#boot.secureFetch(`${this.#serviceurl}/methods`, { body: formdata, method : "POST"}) + .then(reply=>{ + if (reply.status !== 200) { + throw "Unable to import" + }else return reply.text() + }).then(data=>{ + this.fetchProcesses() + }).catch(err=>{ alert(err) }) + } + } + + #process_list_bss = { + template : "#PROCESS_LIST_TEMPLATE", + target : "ul[name=process_category_list]", + "in" : this, + on_dragover : (ev)=> ev.preventDefault(), + on_dragenter : (ev)=> ev.target.classList.toggle("border-info"), + on_dragleave : (ev)=> ev.target.classList.toggle("border-info"), + on_drop : (ev)=>{ + if(ev.dataTransfer && ev.dataTransfer.files && ev.dataTransfer.files.length){ + const files = Array.prototype.slice.call(ev.dataTransfer.files) + const jsons = files.filter(f=>f.type === "application/json") + if(confirm("Confirm import of method files?")){ + this.importMethods(files) + } + ev.preventDefault() + ev.stopPropagation() + } + ev.target.classList.toggle("border-info") + }, + recurse : [ + { + target : "li.ccp-process-category", + "in" : (e,d)=>Object.keys(this.#filtered), + on_click : ev=>{ + if(ev.target.getAttribute("name") === "export_category"){ + this.exportCategory(ev.currentTarget.bss_input.data) + } + }, + recurse : [ + { + target : "summary", + apply : (e,d)=>{ + const executables = this.#filtered[d].filter(m=>m.executable).length + e.querySelector("h5").textContent = d + e.querySelector("span[name=count_notexecutables]").textContent = this.#filtered[d].length - executables + e.querySelector("span[name=count_executables]").textContent = executables + } + }, + { + target : "details", + apply : (e,d)=>{ + e.alt = e.title = d + if(sessionStorage.getItem(d) === "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 : "details ul[name=process_list]", + in : (e,d)=>d, + recurse: [ + { + target : "li.ccp-process", + "in" : (e,d)=>this.#filtered[d], + on_click : ev=>{ + const id = ev.currentTarget.bss_input.data.id + if(ev.target.getAttribute("name") === "export_method"){ + this.exportMethod(id) + }else if(ev.target.getAttribute("name") === "executable"){ + const event = new CustomEvent('newexecutionrequest', { detail: id }); + document.dispatchEvent(event) + }else if(ev.target.getAttribute("name") === "edit"){ + const event = new CustomEvent('neweditrequest', { detail: ev.currentTarget.bss_input.data }); + document.dispatchEvent(event) + } + }, + on_dragstart : ev=>{ + ev.dataTransfer.effectAllowed = 'move' + ev.dataTransfer.setData('text/html', ev.currentTarget.innerHTML) + ev.dataTransfer.setData('text/plain+ccpmethod', ev.currentTarget.bss_input.data.id) + ev.dataTransfer.setData('application/json+ccpmethod', JSON.stringify(ev.currentTarget.bss_input.data)) + }, + on_dragend : ev=>{ + ev.preventDefault() + }, + recurse : [ + { + target: "span[name=version]", + apply : (e,d)=>{ e.textContent = d.version } + }, + { + target: "button[name=executable]", + apply : (e,d)=>{ e.style.display = d.executable ? "revert" : "none" } + }, + { + target : "span[name=author]", + "in" : (e,d)=>d.metadata.filter(md=>md.role === "author"), + apply : (e,d)=>{ e.textContent = d.title; e.alt = e.title = "author" } + }, + { + target : "span[name=keyword]", + "in" : (e,d)=>d.keywords, + apply : (e,d)=>{ e.alt = e.title = e.textContent = d } + }, + { + target : "span[name=infrastructures]", + "in" : (e,d)=>d.links.filter(md=>md.rel === "compatibleWith"), + apply : (e,d)=>{ e.alt = e.title = e.textContent = d.title } + }, + { + target : "p[name=description]", + apply : (e,d)=>{ e.textContent = d.description } + }, + ] + } + ] + } + ] + } + ] + } } - -} - + window.customElements.define('d4s-ccp-methodlist', CCPMethodList); diff --git a/ccp/js/methodlistcontroller2.js b/ccp/js/methodlistcontroller2.js deleted file mode 100644 index 22817c3..0000000 --- a/ccp/js/methodlistcontroller2.js +++ /dev/null @@ -1,361 +0,0 @@ -class CCPMethodList2 extends HTMLElement{ - - #boot; - #rootdoc; - #data; - #filtered; - #dragged = null; - #searchfield = null; - - #serviceurl; - - constructor(){ - super() - this.#boot = document.querySelector("d4s-boot-2") - this.#serviceurl = this.getAttribute("serviceurl") - this.#rootdoc = this.attachShadow({ "mode" : "open"}) - this.render() - this.fetchProcesses() - } - - render(){ - this.#rootdoc.innerHTML = ` - - - - -
        -
        -
        -
        - List of available methods -
        -
        - -
        -
        -
        -
        -
        - -
        -
        -
          -
          -
          -
          - ` - - this.#rootdoc.querySelector("button[name=refresh]").addEventListener("click", ev=>{ - this.fetchProcesses() - }) - - this.#searchfield = this.#rootdoc.querySelector("input[name=search]") - this.#searchfield.addEventListener("input", ev=>{ - this.updateList() - }) - } - - connectedCallback(){ - - } - - fetchProcesses(){ - console.log("Calling fetch processes") - this.#boot.secureFetch(this.#serviceurl + "/methods"). - then(resp=>{ - console.log("Received resp for processes ", resp.status) - return resp.json() - }).then(data=>{ - console.log("Processes parsed to json", data) - this.#data = data - this.updateList() - return this.fetchInfrastructures() - }).then(d => { - this.updateList() - }).catch(err=>{ - alert("Error while downloading methods") - console.error("Error while downloading methods: " + err) - }) - } - - fetchInfrastructures(){ - const url = this.#serviceurl + "/infrastructures" - this.#boot.secureFetch(url). - then(resp=>{ - if(resp.status !== 200) throw "Unable to fetch infrastructures " + resp.status; - else return resp.json() - }).then(infras=>{ - for(let m=0; m < this.#data.length; m++){ - const method = this.#data[m] - method["executable"] = false - for(let i=0; i < infras.length; i++){ - const infra = infras[i] - const matches = method.links.filter(l => l.rel === "compatibleWith" && l.href === "infrastructures/" + infra.id) - if(matches.length > 0){ - method["executable"] = true - break - } - } - } - this.updateList() - }).catch(err=>{ - alert("Error while checking runtimes for method") - console.error("Error while checking runtimes for method: " + err) - }) - } - - 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.title.toLowerCase().indexOf(f) !== -1)|| - (d.description.indexOf(f) !== -1) || - (d.keywords.map(k=>k.toLowerCase()).filter(i=>i.indexOf(f) !== -1)).length - }) - } - this.groupBy() - BSS.apply(this.#process_list_bss, this.#rootdoc) - } - - groupBy(){ - this.#filtered = this.#filtered.reduce((catalog, meth)=>{ - const category = meth.title - catalog[category] = catalog[category] ?? [] - catalog[category].push(meth) - return catalog - }, {}) - } - - exportCategory(category){ - Promise.all( - this.#filtered[category].map(m=>this.exportMethod(m.id)) - ) - } - - exportMethod(method){ - this.#boot.secureFetch(this.#serviceurl + "/methods/" + method + "/shareable").then( - (resp)=>{ - if(resp.status === 200){ - return resp.json() - }else throw "Error exporting sharable process: " + resp.status - } - ).then(data=>{ - const filename = data.title + "-" + data.version + ".json" - const datastr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(data)); - var tmplnk = document.createElement("a") - tmplnk.download = filename - tmplnk.href = datastr - document.body.appendChild(tmplnk) - tmplnk.click() - document.body.removeChild(tmplnk) - }).catch(err=>{ - console.log(err) - }) - } - - importMethods(files){ - if(files && files.length) { - let formdata = new FormData(); - files.reduce((formdata, f)=>{ - formdata.append("files[]", f) - return formdata - }, formdata) - this.#boot.secureFetch(`${this.#serviceurl}/methods`, { body: formdata, method : "POST"}) - .then(reply=>{ - if (reply.status !== 200) { - throw "Unable to import" - }else return reply.text() - }).then(data=>{ - this.fetchProcesses() - }).catch(err=>{ alert(err) }) - } - } - - #process_list_bss = { - template : "#PROCESS_LIST_TEMPLATE", - target : "ul[name=process_category_list]", - "in" : this, - on_dragover : (ev)=> ev.preventDefault(), - on_dragenter : (ev)=> ev.target.classList.toggle("border-info"), - on_dragleave : (ev)=> ev.target.classList.toggle("border-info"), - on_drop : (ev)=>{ - if(ev.dataTransfer && ev.dataTransfer.files && ev.dataTransfer.files.length){ - const files = Array.prototype.slice.call(ev.dataTransfer.files) - const jsons = files.filter(f=>f.type === "application/json") - if(confirm("Confirm import of method files?")){ - this.importMethods(files) - } - ev.preventDefault() - ev.stopPropagation() - } - ev.target.classList.toggle("border-info") - }, - recurse : [ - { - target : "li.ccp-process-category", - "in" : (e,d)=>Object.keys(this.#filtered), - on_click : ev=>{ - if(ev.target.getAttribute("name") === "export_category"){ - this.exportCategory(ev.currentTarget.bss_input.data) - } - }, - recurse : [ - { - target : "summary", - apply : (e,d)=>{ - const executables = this.#filtered[d].filter(m=>m.executable).length - e.querySelector("h5").textContent = d - e.querySelector("span[name=count_notexecutables]").textContent = this.#filtered[d].length - executables - e.querySelector("span[name=count_executables]").textContent = executables - } - }, - { - target : "details", - apply : (e,d)=>{ - e.alt = e.title = d - if(sessionStorage.getItem(d) === "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 : "details ul[name=process_list]", - in : (e,d)=>d, - recurse: [ - { - target : "li.ccp-process", - "in" : (e,d)=>this.#filtered[d], - on_click : ev=>{ - const id = ev.currentTarget.bss_input.data.id - if(ev.target.getAttribute("name") === "export_method"){ - this.exportMethod(id) - }else if(ev.target.getAttribute("name") === "executable"){ - const event = new CustomEvent('newexecutionrequest', { detail: id }); - document.dispatchEvent(event) - }else if(ev.target.getAttribute("name") === "edit"){ - const event = new CustomEvent('neweditrequest', { detail: ev.currentTarget.bss_input.data }); - document.dispatchEvent(event) - } - }, - on_dragstart : ev=>{ - ev.dataTransfer.effectAllowed = 'move' - ev.dataTransfer.setData('text/html', ev.currentTarget.innerHTML) - ev.dataTransfer.setData('text/plain+ccpmethod', ev.currentTarget.bss_input.data.id) - ev.dataTransfer.setData('application/json+ccpmethod', JSON.stringify(ev.currentTarget.bss_input.data)) - }, - on_dragend : ev=>{ - ev.preventDefault() - }, - recurse : [ - { - target: "span[name=version]", - apply : (e,d)=>{ e.textContent = d.version } - }, - { - target: "button[name=executable]", - apply : (e,d)=>{ e.style.display = d.executable ? "revert" : "none" } - }, - { - target : "span[name=author]", - "in" : (e,d)=>d.metadata.filter(md=>md.role === "author"), - apply : (e,d)=>{ e.textContent = d.title; e.alt = e.title = "author" } - }, - { - target : "span[name=keyword]", - "in" : (e,d)=>d.keywords, - apply : (e,d)=>{ e.alt = e.title = e.textContent = d } - }, - { - target : "span[name=infrastructures]", - "in" : (e,d)=>d.links.filter(md=>md.rel === "compatibleWith"), - apply : (e,d)=>{ e.alt = e.title = e.textContent = d.title } - }, - { - target : "p[name=description]", - apply : (e,d)=>{ e.textContent = d.description } - }, - ] - } - ] - } - ] - } - ] - } - } - -window.customElements.define('d4s-ccp-methodlist2', CCPMethodList2);