overall fixes and refactorings for alpha testers

This commit is contained in:
dcore94 2022-07-18 18:08:53 +02:00
parent b2b1caf9db
commit c91a3dbdfe
7 changed files with 386 additions and 92 deletions

View File

@ -6,15 +6,15 @@ class CCPExecutionForm extends HTMLElement{
#method; #method;
#executionmonitor; #executionmonitor;
#serviceurl = "https://nubis1.int.d4science.net:8080" #serviceurl;
#cdnurl = "https://cdn.dev.d4science.org/ccp/executionformfragment.html"
//#cdnurl = "http://d4science-cdn-public:8984/resources/ccp/executionformfragment.html"
constructor(){ constructor(){
super() super()
this.#boot = document.querySelector("d4s-boot-2") this.#boot = document.querySelector("d4s-boot-2")
this.#serviceurl = this.getAttribute("serviceurl")
this.#rootdoc = this.attachShadow({ "mode" : "open"}) this.#rootdoc = this.attachShadow({ "mode" : "open"})
this.fetchMarkup() this.render()
this.showMethod()
} }
static get observedAttributes() { static get observedAttributes() {
@ -28,18 +28,68 @@ class CCPExecutionForm extends HTMLElement{
} }
} }
fetchMarkup(){ render(){
return fetch(this.#cdnurl).then( this.#rootdoc.innerHTML = `
(reply)=>{ <div>
if(reply.status === 200){ <link rel="stylesheet" href="https://cdn.dev.d4science.org/ccp/css/common.css"></link>
return reply.text() <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">
}else{ throw new Exception("Unable to fetch markup") } <style>
}).then(data=>{
this.#rootdoc.innerHTML = data </style>
this.showMethod() <template id="EXECUTION_FORM_TEMPLATE">
}).catch(err=>{ <div class="ccp-execution-form" name="execution_form">
console.error(err) <h5 class="ccp-method-title"></h5>
}) <p class="description font-italic font-weight-lighter"></p>
<div name="plexiglass" class="ccp-invisible">
<span name="status"></span>
<span class="fas fa-spinner fa-spin"></span>
</div>
<form name="execution_form" class="d-flex flex-column gap-3" style="gap:5px">
<div class="card">
<div class="card-header">
<h5>Inputs</h5>
</div>
<div class="card-body ccp-inputs">
<div class="card-body">
<div class="form-group"></div>
</div>
</div>
</div>
<div class="card">
<div class="card-header">
<h5>Outputs</h5>
</div>
<div class="card-body">
<div class="form-row ccp-outputs">
<div class="col form-group"></div>
</div>
</div>
</div>
<!--div class="card">
<div class="card-header">
<h5>Runtimes <span alt="refresh" title="refresh" style="cursor:pointer" name="refresh-runtimes" class="text-info">&#8634;</span></h5>
</div>
<div class="card-body">
<div class="ccp-runtimes">
<div class="form-row">
<select class="form-control">
</select>
</div>
</div>
</div>
</div-->
<button id="execute_method_button" class="btn btn-info">Execute</button>
</form>
</div>
</template>
<template id="EXECUTION_FORM_EMPTY_TEMPLATE">
<div name="execution_form">
<i style="padding:3rem">Select a method</i>
</div>
</template>
<div name="execution_form"></div>
</div>
`
} }
loadMethod(){ loadMethod(){

View File

@ -49,12 +49,18 @@ class CCPInfrastructureList extends HTMLElement{
</style> </style>
`; `;
#serviceurl = "https://nubis1.int.d4science.net:8080" #serviceurl;
#broadcasturl = "ws://nubis1.int.d4science.net:8989/ws/notification" #broadcasturl;
constructor(){ constructor(){
super() super()
this.#boot = document.querySelector("d4s-boot-2") this.#boot = document.querySelector("d4s-boot-2")
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.#rootdoc = this.attachShadow({ "mode" : "open"}) this.#rootdoc = this.attachShadow({ "mode" : "open"})
} }

View File

@ -79,11 +79,16 @@ class Renderer{
} }
static isCode(input){ static isCode(input){
return (input.schema.type === "string") && ("format" in input.schema) && (input.schema.format.toLowerCase() === "code") return (input.schema.type === "string") &&
("format" in input.schema) &&
(input.schema.format != null) &&
(input.schema.format.toLowerCase() === "code")
} }
static isDateTime(input){ static isDateTime(input){
return (input.schema.type === "string") && ("format" in input.schema) && return (input.schema.type === "string") &&
("format" in input.schema) &&
(input.schema.format != null) &&
(["date", "time", "datetime"].indexOf(input.schema.format.toLowerCase()) !== -1) (["date", "time", "datetime"].indexOf(input.schema.format.toLowerCase()) !== -1)
} }
} }

View File

@ -30,7 +30,7 @@ class CCPInputWidgetEditorController extends HTMLElement{
this.innerHTML = ` this.innerHTML = `
<details> <details>
<summary class="mb-3"> <summary class="mb-3">
<input class="form-control" style="width:auto;display:inline" required="required" name="id" value="${this.#input.id}"/> <input class="form-control" style="width:auto;display:inline" required="required" name="id" value="${this.#input.id}" title="Id of input"/>
<button data-index="${this.#index}" name="delete-input" title="Delete" class="btn btn-danger ccp-toolbar-button"> <button data-index="${this.#index}" name="delete-input" title="Delete" class="btn btn-danger ccp-toolbar-button">
${this.#delete_icon} ${this.#delete_icon}
</button> </button>
@ -38,19 +38,19 @@ class CCPInputWidgetEditorController extends HTMLElement{
<div style="padding-left: 1rem;border-left: 1px solid gray;"> <div style="padding-left: 1rem;border-left: 1px solid gray;">
<div class="row mb-3"> <div class="row mb-3">
<div class="col"> <div class="col">
<div class="form-field"> <div class="form-field" title="Title">
<input name="title" class="form-control" placeholder="title" value="${this.#input.title}" required="required"/> <input name="title" class="form-control" placeholder="title" value="${this.#input.title}" required="required"/>
</div> </div>
</div> </div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="form-field"> <div class="form-field" title="description">
<input name="description" class="form-control" placeholder="description" value="${this.#input.description}" required="required"/> <input name="description" class="form-control" placeholder="description" value="${this.#input.description}" required="required"/>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col-3"> <div class="col-3">
<div class="form-field"> <div class="form-field" title="Type">
<label>Type</label> <label>Type</label>
<select name="type" class="form-control" placeholder="type" value="${this.#input.schema.type}"> <select name="type" class="form-control" placeholder="type" value="${this.#input.schema.type}">
<option value="string">String</option> <option value="string">String</option>
@ -59,13 +59,13 @@ class CCPInputWidgetEditorController extends HTMLElement{
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<div class="form-field"> <div class="form-field" title="Minimum">
<label>Min</label> <label>Min</label>
<input value="${this.#input.minOccurs}" type="number" min="0" step="1" name="minOccurs" value="${this.#input.minOccurs}" required="required" class="form-control" placeholder="minOccurs"/> <input value="${this.#input.minOccurs}" type="number" min="0" step="1" name="minOccurs" value="${this.#input.minOccurs}" required="required" class="form-control" placeholder="minOccurs"/>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<div class="form-field"> <div class="form-field" title="Maximum">
<label>Max</label> <label>Max</label>
<input value="${this.#input.maxOccurs}" type="number" min="0" step="1" name="maxOccurs" value="${this.#input.maxOccurs}" required="required" class="form-control" placeholder="maxOccurs"/> <input value="${this.#input.maxOccurs}" type="number" min="0" step="1" name="maxOccurs" value="${this.#input.maxOccurs}" required="required" class="form-control" placeholder="maxOccurs"/>
</div> </div>
@ -73,9 +73,9 @@ class CCPInputWidgetEditorController extends HTMLElement{
</div> </div>
<div name="string-input" class="${this.#type === 'enum' ? 'd-none' : ''} row mb-3"> <div name="string-input" class="${this.#type === 'enum' ? 'd-none' : ''} row mb-3">
<div class="col-3"> <div class="col-3">
<div class="form-field"> <div class="form-field" title="Format">
<label>Format</label> <label>Format</label>
<select value="${this.#input.schema.format}" name="format" class="form-control" value="${this.#input.schema.format}"> <select value="${this.#input.schema.format}" name="format" class="form-control">
<option value="none">None</option> <option value="none">None</option>
<option value="date">Date</option> <option value="date">Date</option>
<option value="time">Time</option> <option value="time">Time</option>
@ -84,7 +84,7 @@ class CCPInputWidgetEditorController extends HTMLElement{
</select> </select>
</div> </div>
</div> </div>
<div class="col"> <div class="col" title="Mime type">
<label>Mime</label> <label>Mime</label>
<div class="form-field"> <div class="form-field">
<input value="${this.#input.schema.contentMediaType}" name="contentMediaType" class="form-control" placeholder="mime"/> <input value="${this.#input.schema.contentMediaType}" name="contentMediaType" class="form-control" placeholder="mime"/>
@ -92,13 +92,13 @@ class CCPInputWidgetEditorController extends HTMLElement{
</div> </div>
</div> </div>
<div name="enum-input" class="${this.#type !== 'enum' ? 'd-none' : ''} mb-3"> <div name="enum-input" class="${this.#type !== 'enum' ? 'd-none' : ''} mb-3">
<div class="form-field"> <div class="form-field" title="options">
<input name="options" class="form-control" type="text" placeholder="option"/> <input name="options" class="form-control" type="text" placeholder="option"/>
<small class="form-text text-muted">Comma separated list of options</small> <small class="form-text text-muted">Comma separated list of options</small>
</div> </div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="form-field"> <div class="form-field" title="Default value">
<input value="${this.#input.schema.default}" name="default" class="form-control" placeholder="default"/> <input value="${this.#input.schema.default}" name="default" class="form-control" placeholder="default"/>
</div> </div>
</div> </div>

View File

@ -3,10 +3,12 @@ class CCPMethodEditorController extends HTMLElement{
#boot; #boot;
#rootdoc; #rootdoc;
#serviceurl = "https://nubis1.int.d4science.net:8080" #serviceurl;
#runtimes; #runtimes;
#locked = false; #locked = false;
#isupdate = false;
#tmp_inputs = [] #tmp_inputs = []
#tmp_outputs = [] #tmp_outputs = []
#current = null; #current = null;
@ -103,6 +105,18 @@ class CCPMethodEditorController extends HTMLElement{
position: relative; position: relative;
} }
.ccp-toolbar-header {
display: inline-flex;
align-items: center;
gap: 5px;
padding: .2rem;
}
.ccp-toolbar-right {
position:absolute;
right: 1rem;
}
.ccp-toolbar-button { .ccp-toolbar-button {
font-weight: bold; font-weight: bold;
padding:.3rem; padding:.3rem;
@ -151,6 +165,11 @@ class CCPMethodEditorController extends HTMLElement{
<path d="M23,12L19,8V11H10V13H19V16M1,18V6C1,4.89 1.9,4 3,4H15A2,2 0 0,1 17,6V9H15V6H3V18H15V15H17V18A2,2 0 0,1 15,20H3A2,2 0 0,1 1,18Z" /> <path d="M23,12L19,8V11H10V13H19V16M1,18V6C1,4.89 1.9,4 3,4H15A2,2 0 0,1 17,6V9H15V6H3V18H15V15H17V18A2,2 0 0,1 15,20H3A2,2 0 0,1 1,18Z" />
</svg> </svg>
` `
#delete_icon = `
<svg style="width:24px;height:24px;pointer-events: none;" 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" />
</svg>
`
#ansible_icon = ` #ansible_icon = `
<svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10s10-4.5 10-10S17.5 2 12 2m4.1 15c-.19 0-.34-.1-.55-.27l-5.16-4.17l-1.73 4.34H7.17l4.37-10.51c.11-.28.35-.42.63-.42s.5.14.62.42l3.98 9.58c.04.11.07.22.07.29c-.01.42-.34.74-.74.74m-3.93-8.89l2.59 6.39l-3.91-3.08l1.32-3.31Z"></path> <svg viewBox="0 0 24 24"><path fill="currentColor" d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10s10-4.5 10-10S17.5 2 12 2m4.1 15c-.19 0-.34-.1-.55-.27l-5.16-4.17l-1.73 4.34H7.17l4.37-10.51c.11-.28.35-.42.63-.42s.5.14.62.42l3.98 9.58c.04.11.07.22.07.29c-.01.42-.34.74-.74.74m-3.93-8.89l2.59 6.39l-3.91-3.08l1.32-3.31Z"></path>
@ -161,6 +180,8 @@ class CCPMethodEditorController extends HTMLElement{
super(); super();
this.#boot = document.querySelector("d4s-boot-2") this.#boot = document.querySelector("d4s-boot-2")
this.#rootdoc = this.attachShadow({ "mode" : "open"}) this.#rootdoc = this.attachShadow({ "mode" : "open"})
this.#serviceurl = this.getAttribute("serviceurl")
this.initMethod()
this.fetchRuntimes() this.fetchRuntimes()
} }
@ -181,13 +202,72 @@ class CCPMethodEditorController extends HTMLElement{
}) })
} }
saveCurrent(){ saveMethod(){
if(this.#locked) return;
if(this.#current != null){ if(this.#current != null){
this.adoptTemporaries() this.adoptTemporaries()
console.log(this.#current) const text = `Confirm ${this.#isupdate ? "updating" : "creation"} of ${this.#current.title} version ${this.#current.version}`
if(window.confirm(text)){
this.lockRender()
const url = this.#serviceurl + "/methods"
const args = {
body : JSON.stringify(this.#current),
method : this.#isupdate ? "PUT" : "POST",
headers : {"Content-type" : "application/json"}
}
this.#boot.secureFetch(url, args).then(
(resp)=>{
if(resp.status === 201 || resp.status === 204){
return resp.text()
}else throw "Error saving process"
}).then(data=>{
if(!this.#isupdate) this.#isupdate = true;
this.unlockRender()
}).catch(err=>{
alert(err)
this.unlockRender()
})
}
} }
} }
deleteMethod(){
if(this.#locked) return;
if(this.#current != null){
const text = `Confirm deletion of ${this.#current.title} version ${this.#current.version}`
if(window.confirm(text)){
this.lockRender()
const url = this.#serviceurl + "/methods/" + this.#current.id
const args = {
method : "DELETE"
}
this.#boot.secureFetch(url, args).then(
(resp)=>{
if(resp.status === 404 || resp.status === 204){
return null
}else throw "Error deleting method"
}).then(data=>{
this.unlockRender()
}).catch(err=>{
alert(err)
this.unlockRender()
})
}
}
}
initMethod(){
this.#current = JSON.parse(JSON.stringify(this.#method_template))
this.#current.id = Math.abs((Math.random() * 10e11)|0)
this.#tmp_inputs = []
this.#tmp_outputs = []
}
resetMethod(){
this.initMethod()
this.render()
}
cloneMethod(method){ cloneMethod(method){
if(this.#locked) return; if(this.#locked) return;
this.lockRender() this.lockRender()
@ -199,7 +279,30 @@ class CCPMethodEditorController extends HTMLElement{
} }
).then(data=>{ ).then(data=>{
this.#current = data this.#current = data
this.#current.id = "" this.#current.id = Math.abs((Math.random() * 10e11)|0)
this.#isupdate = false
this.#current.title = "Clone of " + this.#current.title
this.#current.description = "[Clone of] " + this.#current.description
this.#tmp_inputs = Object.keys(this.#current.inputs).map(k=>this.#current.inputs[k])
this.#tmp_outputs = Object.keys(this.#current.outputs).map(k=>this.#current.outputs[k])
this.unlockRender()
}).catch(err=>{
this.unlockRender()
})
}
editMethod(method){
if(this.#locked) return;
this.lockRender()
this.#boot.secureFetch(this.#serviceurl + "/processes/" + method).then(
(resp)=>{
if(resp.status === 200){
return resp.json()
}else throw "Error retrieving process"
}
).then(data=>{
this.#current = data
this.#isupdate = true
this.#tmp_inputs = Object.keys(this.#current.inputs).map(k=>this.#current.inputs[k]) this.#tmp_inputs = Object.keys(this.#current.inputs).map(k=>this.#current.inputs[k])
this.#tmp_outputs = Object.keys(this.#current.outputs).map(k=>this.#current.outputs[k]) this.#tmp_outputs = Object.keys(this.#current.outputs).map(k=>this.#current.outputs[k])
this.unlockRender() this.unlockRender()
@ -243,10 +346,6 @@ class CCPMethodEditorController extends HTMLElement{
} }
render(){ render(){
if(this.#current == null){
this.#current = JSON.parse(JSON.stringify(this.#method_template))
this.#current.id = Math.random(10e6)|0
}
this.#rootdoc.innerHTML = ` this.#rootdoc.innerHTML = `
<div class="ccp-method-editor"> <div class="ccp-method-editor">
<div class="d-none plexiglass"> <div class="d-none plexiglass">
@ -258,10 +357,15 @@ class CCPMethodEditorController extends HTMLElement{
<div class="ccp-method-editor-form"> <div class="ccp-method-editor-form">
<div class="card"> <div class="card">
<div class="card-header"> <div class="card-header">
<div> <div class="ccp-toolbar-header">
<span class="mr-2">${this.#current.title}</span> <div>
${this.renderSaveButton()} <span name="header" class="mr-2">${this.#current.title}</span>
${this.renderResetButton()} </div>
<div class="ccp-toolbar-right">
${this.renderSaveButton()}
${this.renderResetButton()}
${ this.#isupdate ? this.renderDeleteButton() : "" }
</div>
</div> </div>
</div> </div>
<div class="card-body"> <div class="card-body">
@ -299,17 +403,29 @@ class CCPMethodEditorController extends HTMLElement{
</div> </div>
<details class="card"> <details class="card">
<summary class="card-header"> <summary class="card-header">
<span class="mr-2">Inputs</span> <div class="ccp-toolbar-header">
${this.renderPlusButton("add-input")} <div>
<span class="mr-2">Inputs</span>
</div>
<div class="ccp-toolbar-right">
${this.renderPlusButton("add-input")}
</div>
</div>
</summary> </summary>
<div class="card-body" name="input-list"> <div class="card-body" name="input-list">
</div> </div>
</details> </details>
<details class="card"> <details class="card">
<summary class="card-header" name="output-buttons"> <summary class="card-header" name="output-buttons">
<span class="mr-2">Outputs</span> <div class="ccp-toolbar-header">
${this.renderStandardOutputButtons()} <div>
${this.renderPlusButton("add-output")} <span class="mr-2">Outputs</span>
</div>
<div class="ccp-toolbar-right">
${this.renderStandardOutputButtons()}
${this.renderPlusButton("add-output")}
</div>
</div>
</summary> </summary>
<div class="card-body" name="output-list"> <div class="card-body" name="output-list">
<d4s-ccp-output-editor></d4s-ccp-output-editor> <d4s-ccp-output-editor></d4s-ccp-output-editor>
@ -317,15 +433,22 @@ class CCPMethodEditorController extends HTMLElement{
</div> </div>
<details class="card" name="script-list"> <details class="card" name="script-list">
<summary class="card-header"> <summary class="card-header">
<span>Scripts</span> <div class="ccp-toolbar-header">
<select name="script-selector" style="border:none; padding:.3rem"> <div>
<option value="deploy-script">Deploy</option> <span>Scripts</span>
<option value="execute-script">Execute</option> <select name="script-selector" style="border:none; padding:.3rem">
<option value="fetch-output-script">Fetch output</option> <option value=""></option>
<option value="undeploy-script">Undeploy</option> <option value="deploy-script">Deploy</option>
<option value="cancel-script">Cancel</option> <option value="execute-script">Execute</option>
</select> <option value="fetch-output-script">Fetch output</option>
${ this.renderAnsibleIcon() } <option value="undeploy-script">Undeploy</option>
<option value="cancel-script">Cancel</option>
</select>
</div>
<div>
${ this.renderAnsibleIcon() }
</div>
</div>
</summary> </summary>
<div class="card-body" name="input_container"> <div class="card-body" name="input_container">
${this.renderScripts()} ${this.renderScripts()}
@ -337,12 +460,30 @@ class CCPMethodEditorController extends HTMLElement{
this.renderInputs() this.renderInputs()
this.renderOutputs() this.renderOutputs()
this.#rootdoc.querySelector("input[name=title]").addEventListener("input", ev=>{
this.#current.title = ev.currentTarget.value
this.#rootdoc.querySelector("span[name=header]").innerText = this.#current.title
})
this.#rootdoc.querySelector("input[name=version]").addEventListener("input", ev=>{
this.#current.version = ev.currentTarget.value
})
this.#rootdoc.querySelector("input[name=description]").addEventListener("input", ev=>{
this.#current.description = ev.currentTarget.value
})
this.#rootdoc.addEventListener("drop", ev=>{ this.#rootdoc.addEventListener("drop", ev=>{
if(ev.dataTransfer && ev.dataTransfer.getData('text/plain+ccpmethod')){ if(ev.dataTransfer && ev.dataTransfer.getData('text/plain+ccpmethod')){
const id = ev.dataTransfer.getData('text/plain+ccpmethod') const id = ev.dataTransfer.getData('text/plain+ccpmethod')
ev.stopImmediatePropagation()
ev.preventDefault() ev.preventDefault()
ev.stopPropagation() ev.stopPropagation()
this.cloneMethod(id) if(window.confirm("Do you want to create a new clone?")){
this.cloneMethod(id)
} else {
this.editMethod(id)
}
} }
}) })
@ -351,10 +492,9 @@ class CCPMethodEditorController extends HTMLElement{
}) })
this.#rootdoc.querySelector("button[name=reset]").addEventListener("click", ev=>{ this.#rootdoc.querySelector("button[name=reset]").addEventListener("click", ev=>{
this.#current = this.#method_template if(window.confirm("All unsaved data will be lost. Proceed?")){
this.#tmp_inputs = [] this.resetMethod()
this.#tmp_outputs = [] }
this.render()
ev.preventDefault() ev.preventDefault()
ev.stopPropagation() ev.stopPropagation()
}) })
@ -362,9 +502,17 @@ class CCPMethodEditorController extends HTMLElement{
this.#rootdoc.querySelector("button[name=save]").addEventListener("click", ev=>{ this.#rootdoc.querySelector("button[name=save]").addEventListener("click", ev=>{
ev.preventDefault() ev.preventDefault()
ev.stopPropagation() ev.stopPropagation()
this.saveCurrent() this.saveMethod()
}) })
if(this.#isupdate){
this.#rootdoc.querySelector("button[name=delete]").addEventListener("click", ev=>{
ev.preventDefault()
ev.stopPropagation()
this.deleteMethod()
})
}
this.#rootdoc.querySelector("input[name=keyword-input]").addEventListener("keypress", ev=>{ this.#rootdoc.querySelector("input[name=keyword-input]").addEventListener("keypress", ev=>{
if(ev.key === "Enter" || ev.which === 13){ if(ev.key === "Enter" || ev.which === 13){
ev.preventDefault() ev.preventDefault()
@ -432,7 +580,7 @@ class CCPMethodEditorController extends HTMLElement{
schema : { schema : {
type : "string", type : "string",
format : null, format : null,
contentMediaType : null, contentMediaType : "text/plain",
default : "" default : ""
} }
} }
@ -464,7 +612,7 @@ class CCPMethodEditorController extends HTMLElement{
maxOccurs : 1, maxOccurs : 1,
schema : { schema : {
type : "string", type : "string",
contentMediaType : null contentMediaType : "text/plain"
} }
} }
) )
@ -543,7 +691,7 @@ class CCPMethodEditorController extends HTMLElement{
renderAnsibleIcon(){ renderAnsibleIcon(){
return ` return `
<div title="Ansible" style="width:2rem;height:2rem;display:inline-block;vertical-align:middle;position:absolute;right:0;margin-right:1rem;opacity:0.4;"> <div title="Ansible" style="width:2rem;height:2rem;position:absolute;right:5px;top:30%;opacity:0.4;">
${ this.#ansible_icon } ${ this.#ansible_icon }
</div> </div>
` `
@ -557,6 +705,14 @@ class CCPMethodEditorController extends HTMLElement{
` `
} }
renderDeleteButton(){
return `
<button title="Delete" name="delete" class="btn btn-danger ccp-toolbar-button">
${this.#delete_icon}
</button>
`
}
renderResetButton(){ renderResetButton(){
return ` return `
<button name="reset" title="Reset" class="btn btn-primary ccp-toolbar-button"> <button name="reset" title="Reset" class="btn btn-primary ccp-toolbar-button">
@ -658,7 +814,7 @@ class CCPMethodEditorController extends HTMLElement{
renderScripts(){ renderScripts(){
return this.#current.additionalParameters.parameters.map( return this.#current.additionalParameters.parameters.map(
(script, i) => `<textarea rows="5" class="script-area form-control ${ i > 0 ? 'd-none' : ''}" name="${script.name}">${script.value[0]}</textarea>` (script, i) => `<textarea rows="5" class="script-area form-control d-none" name="${script.name}">${script.value[0]}</textarea>`
).join("\n") ).join("\n")
} }
} }

View File

@ -6,29 +6,107 @@ class CCPMethodList extends HTMLElement{
#filtered; #filtered;
#dragged = null; #dragged = null;
#serviceurl = "https://nubis1.int.d4science.net:8080" #serviceurl;
#cdnurl = "https://cdn.dev.d4science.org/ccp/methodlistfragment.html"
constructor(){ constructor(){
super() super()
this.#boot = document.querySelector("d4s-boot-2") this.#boot = document.querySelector("d4s-boot-2")
this.#serviceurl = this.getAttribute("serviceurl")
this.#rootdoc = this.attachShadow({ "mode" : "open"}) this.#rootdoc = this.attachShadow({ "mode" : "open"})
this.fetchMarkup() this.render()
this.fetchProcesses()
} }
fetchMarkup(){ render(){
return fetch(this.#cdnurl).then( this.#rootdoc.innerHTML = `
(reply)=>{ <div>
if(reply.status === 200){ <style>
return reply.text() .process_container{
}else{ throw new Exception("Unable to fetch markup") } display: flex;
}).then(data=>{ flex-direction:column;
this.#rootdoc.innerHTML = data }
console.log(this.#boot) input[name=search]{
this.fetchProcesses() display: block;
}).catch(err=>{ padding: 0.375rem 0.75rem;
console.error(err) color: #495057;
}) background-color: #fff;
background-clip: padding-box;
border: 1px solid #ced4da;
border-radius: 0.25rem;
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
}
input:focus{
border-color: #80bdff;
outline: 0;
box-shadow: 0 0 0 0.2rem rgb(0 123 255 / 25%);
}
ul.process_list{
list-style: none;
padding-left: 0;
color: #495057;
display: flex;
flex-direction: column;
gap: .25rem;
user-select: none;
}
li.process_list_item{
display: flex;
flex-direction: column;
gap: 0.25rem;
cursor: pointer;
border: solid 1px rgba(0,0,0,.3);
padding: 0.3rem;
border-radius: 0.3rem;
box-shadow: #333333 1px 1px 4px;
background: #eeeeee;
transition: background .3s;
}
li.process_list_item:hover{
background: #ffffff;
}
ul.keyword_list{
list-style: none;
display: flex;
flex-direction: row;
gap:2px;
padding-left: 0;
font-size: x-small;
font-weight: 300;
}
li.keyword_list_item{
display: inline-block;
padding: 0.25em 0.4em;
line-height: 1;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: 0.25rem;
background-color: #eeffff;
color: #0099CC;
border: solid 1px #0099CC;
}
.process_list_item_header{
margin: 0;
}
</style>
<template id="PROCESS_LIST_TEMPLATE">
<ul class="process_list" name="process_list">
<li class="process_list_item" draggable="true">
<h4 class="process_list_item_header"></h4>
<ul name="keywords" class="keyword_list">
<li class="keyword_list_item"></li>
</ul>
<i></i>
</li>
</ul>
</template>
<div class="process_container">
<input name="search" type="text"/>
<ul name="process_list"></ul>
</div>
</div>
`
} }
connectedCallback(){ connectedCallback(){
@ -51,7 +129,6 @@ class CCPMethodList extends HTMLElement{
} }
showList(){ showList(){
//this.#data = JSON.parse(resp)
this.enableSearch() this.enableSearch()
this.updateList() this.updateList()
} }

View File

@ -29,7 +29,7 @@ class CCPOutputWidgetEditorController extends HTMLElement {
this.innerHTML = ` this.innerHTML = `
<details> <details>
<summary class="mb-3"> <summary class="mb-3">
<input class="form-control" style="width:auto;display:inline" required="required" name="id" value="${this.#output.id}"/> <input class="form-control" style="width:auto;display:inline" required="required" name="id" value="${this.#output.id}" title="Id of output"/>
<button data-index="${this.#index}" name="delete-output" title="Delete" class="btn btn-danger ccp-toolbar-button"> <button data-index="${this.#index}" name="delete-output" title="Delete" class="btn btn-danger ccp-toolbar-button">
${this.#delete_icon} ${this.#delete_icon}
</button> </button>
@ -37,38 +37,38 @@ class CCPOutputWidgetEditorController extends HTMLElement {
<div style="padding-left: 1rem;border-left: 1px solid gray;"> <div style="padding-left: 1rem;border-left: 1px solid gray;">
<div class="row mb-3"> <div class="row mb-3">
<div class="col"> <div class="col">
<div class="form-field"> <div class="form-field" title="Title">
<input name="title" class="form-control" placeholder="title" value="${this.#output.title}" required="required"/> <input name="title" class="form-control" placeholder="title" value="${this.#output.title}" required="required"/>
</div> </div>
</div> </div>
</div> </div>
<div class="mb-3"> <div class="mb-3">
<div class="form-field"> <div class="form-field" title="Description">
<input name="description" class="form-control" placeholder="description" value="${this.#output.description}" required="required"/> <input name="description" class="form-control" placeholder="description" value="${this.#output.description}" required="required"/>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col"> <div class="col">
<div class="form-field"> <div class="form-field" title="Mininum cardinality">
<input value="${this.#output.minOccurs}" type="number" min="0" step="1" name="minOccurs" class="form-control" placeholder="minOccurs"/> <input value="${this.#output.minOccurs}" type="number" min="0" step="1" name="minOccurs" class="form-control" placeholder="minOccurs"/>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<div class="form-field"> <div class="form-field" title="Maximum cardinality">
<input value="${this.#output.maxOccurs}" type="number" min="0" step="1" name="maxOccurs" class="form-control" placeholder="maxOccurs"/> <input value="${this.#output.maxOccurs}" type="number" min="0" step="1" name="maxOccurs" class="form-control" placeholder="maxOccurs"/>
</div> </div>
</div> </div>
</div> </div>
<div class="row mb-3"> <div class="row mb-3">
<div class="col-3"> <div class="col-3">
<div class="form-field"> <div class="form-field" title="Type">
<select name="type" class="form-control" placeholder="type"> <select name="type" class="form-control" placeholder="type">
<option value="string">String</option> <option value="string">String</option>
</select> </select>
</div> </div>
</div> </div>
<div class="col"> <div class="col">
<div class="form-field"> <div class="form-field" title="Mime type">
<input value="${this.#output.schema.contentMediaType}" name="contentMediaType" class="form-control" placeholder="mime"/> <input value="${this.#output.schema.contentMediaType}" name="contentMediaType" class="form-control" placeholder="mime"/>
</div> </div>
</div> </div>