class CCPMethodList 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-methodlist', CCPMethodList);