class CCPExecutionForm extends HTMLElement{ #boot; #rootdoc; #data; #method; #executionmonitor; #serviceurl; constructor(){ super() this.#boot = document.querySelector("d4s-boot-2") this.#serviceurl = this.getAttribute("serviceurl") this.#rootdoc = this.attachShadow({ "mode" : "open"}) this.connectNewExecutionRequest() this.render() this.showMethod() } static get observedAttributes() { return ["method"]; } attributeChangedCallback(name, oldValue, newValue) { if((oldValue != newValue) && (name === "method")){ this.#method = newValue this.loadMethod() } } connectNewExecutionRequest(){ document.addEventListener("newexecutionrequest", ev=>{ if(window.confirm("Please confirm overwrite of execution form?")){ this.setAttribute("method", ev.detail) this.parentElement.scrollIntoViewIfNeeded() } }) } render(){ this.#rootdoc.innerHTML = `
` } lockRender(){ const plexi = this.#rootdoc.querySelector(".plexiglass") plexi.innerHTML = `` plexi.classList.toggle("d-none") } unlockRender(){ this.#rootdoc.querySelector(".plexiglass").classList.toggle("d-none") } writeToPlexi(message){ const plexi = this.#rootdoc.querySelector(".plexiglass") plexi.innerHTML = `
${message}
` } loadMethod(){ return this.#boot.secureFetch(this.#serviceurl + "/processes/" + this.#method).then( (resp)=>{ if(resp.status === 200){ return resp.json() }else throw "Error retrieving process" } ).then(data=>{ this.#data = data const infra = this.#data.links.filter(l => l.rel === "compatibleWith")[0] return this.#boot.secureFetch(this.#serviceurl + "/" + infra.href) }).then(resp=>{ this.#data.executable = resp.status === 200 }).then(()=>{ this.showMethod() }).catch(err=>alert(err)) } showEmpty(resp){ BSS.apply(this.#empty_executionform_bss, this.#rootdoc) } showMethod(){ if(this.#method == null) this.showEmpty(); else{ BSS.apply(this.#executionform_bss, this.#rootdoc) } } sendExecutionRequest(){ this.lockRender() const url = this.#serviceurl + "/processes/" + this.#method + "/execution" const req = this.buildRequest() this.#boot.secureFetch( url, { method : "POST", body : JSON.stringify(req), headers : { "Content-Type" : "application/json"}} ).then(reply=>{ if(reply.status !== 200 && reply.status !== 201){ throw "Error while requesting resource" } return reply.json() }).then(data=>{ if(data.status !== "accepted"){ throw "Execution has not been accepted by server" } const event = new CustomEvent('newexecution', { detail: data.jobID }); document.dispatchEvent(event) this.writeToPlexi("Execution request accepted with id: " + data.jobID) window.setTimeout(()=>this.unlockRender(), 3000) }).catch(err => {alert("Unable to call execute: " + err); this.unlockRender()}) } generateCode(mime, filename){ const url = this.#serviceurl + "/methods/" + this.#method + "/code" const req = this.buildRequest() this.#boot.secureFetch( url, { method : "POST", body : JSON.stringify(req), headers : { "Content-Type" : "application/json", "Accept" : mime}} ).then(reply=>{ if(reply.status !== 200) throw "Error while requesting code:"; return reply.blob() }).then(blob => { const objectURL = URL.createObjectURL(blob) var tmplnk = document.createElement("a") tmplnk.download = filename tmplnk.href = objectURL document.body.appendChild(tmplnk) tmplnk.click() document.body.removeChild(tmplnk) }).catch(err=>{ alert(err)}) } buildRequest(){ let request = { inputs : {}, outputs : {}, response : "raw"} //fill inputs const inputs = this.getInputs() inputs.forEach(i=>{ request.inputs[i.name] = i.value }) //fill outputs const outputs = this.getOutputs() outputs.forEach(o=>{ if(o.enabled) request.outputs[o.name] = { transmissionMode : "value" }; }) return request } getInputs(){ return Array.prototype.slice.call(this.#rootdoc.querySelectorAll("d4s-ccp-input")) } getOutputs(){ return Array.prototype.slice.call(this.#rootdoc.querySelectorAll("d4s-ccp-output")) } initValues(inputs){ Object.keys(inputs).forEach(k=>{ const w = this.#rootdoc.querySelector(`d4s-ccp-input[name=${k}]`) if(w){ w.value = (inputs[k]) } }) } prepareFromExecution(exec){ let f1 = this.#boot.secureFetch(this.#serviceurl + `/executions/${exec.id}/metadata/method.json`) .then(resp=>{ if(resp.status === 200){ return resp.json() }else throw "Error retrieving process" } ).then(data=>data) let f2 = this.#boot.secureFetch(this.#serviceurl + `/executions/${exec.id}/metadata/request.json`) .then(resp=>{ if(resp.status === 200){ return resp.json() }else throw "Error retrieving process" } ).then(data=>data) var requestdata = null Promise.all([f1, f2]).then(m_and_r => { this.#data = m_and_r[0] requestdata = m_and_r[1] this.#method = this.#data.id const infra = this.#data.links.filter(l => l.rel === "compatibleWith")[0] return this.#boot.secureFetch(this.#serviceurl + "/" + infra.href) }).then(resp=>{ this.#data.executable = resp.status === 200 }).then(()=>{ this.showMethod() this.initValues(requestdata.inputs) }).catch(err=>alert(err)) } #empty_executionform_bss = { template : "#EXECUTION_FORM_EMPTY_TEMPLATE", target : "div[name=execution_form]", on_drop : ev=>{ if(ev.dataTransfer){ if(ev.dataTransfer.getData('text/plain+ccpmethod')){ const id = ev.dataTransfer.getData('text/plain+ccpmethod') this.setAttribute("method", id); ev.preventDefault() ev.stopPropagation() ev.currentTarget.style.backgroundColor = "white" }else if(ev.dataTransfer.getData('text/plain+ccpexecution')){ this.prepareFromExecution(JSON.parse(ev.dataTransfer.getData('application/json+ccpexecution'))) ev.preventDefault() ev.stopPropagation() ev.currentTarget.style.backgroundColor = "white" } } }, on_dragover : ev=>{ ev.preventDefault() }, } #executionform_bss = { template : "#EXECUTION_FORM_TEMPLATE", target : "div[name=execution_form]", in : ()=>this.#data, on_drop : ev=>{ if(ev.dataTransfer){ if(ev.dataTransfer.getData('text/plain+ccpmethod')){ const id = ev.dataTransfer.getData('text/plain+ccpmethod'); this.setAttribute("method", id); ev.preventDefault() ev.stopPropagation() }else if(ev.dataTransfer.getData('text/plain+ccpexecution')){ this.prepareFromExecution(JSON.parse(ev.dataTransfer.getData('application/json+ccpexecution'))) ev.preventDefault() ev.stopPropagation() ev.currentTarget.style.backgroundColor = "white" } } }, on_dragover : ev=>{ ev.preventDefault() }, recurse : [ { target: ".ccp-method-title", apply : (e,d)=>e.innerHTML = ` ${d.title} ${d.version} ${ d.metadata.filter(md=>md.role === 'author').map(a=>`${a.title}`)} ` }, { target: "p.description", apply : (e,d)=>e.textContent = d.description }, { target: "div.ccp-inputs", in : (e,d)=>d, recurse : [ { "in" : (e,d)=>{ return Object.values(d.inputs) }, target : "div", apply : (e,d)=>{ e.innerHTML = `` } } ] }, { target: "div.ccp-outputs", in : (e,d)=>d, recurse : [ { "in" : (e,d)=>{ return Object.values(d.outputs) }, target : "div", apply : (e,d)=>{ e.innerHTML = `` } } ] }, { target: "div.ccp-runtimes *[name=refresh-runtimes]", on_click : ev=>{ BSS.apply(this.#executionform_bss) } }, { target: "#execute_method_button", on_click : ev=>{ ev.preventDefault() ev.stopPropagation() if(this.#data.executable) this.sendExecutionRequest(); else alert("This method has no compatible runtimes available") return false; } }, { target: "button[name=codegen]", on_click : ev=>{ ev.preventDefault() ev.stopPropagation() const langsel = ev.target.parentElement.querySelector("select[name=language-selector]") const lang = langsel.value const ext = langsel.selectedOptions[0].getAttribute("data-ext") this.generateCode(lang, `ccprequest.${ext}`) return false } }, ] } } window.customElements.define('d4s-ccp-executionform', CCPExecutionForm);