{% extends "nopaque.html.j2" %} {% set title = '<i class="material-icons left service" data-service="{service}" style="font-size: inherit;"></i>Job'.format(service=job.service) %} {% block page_content %} <div class="col s12 m4"> <h3 id="title">{{ job.title }}</h3> <p id="description">{{ job.description }}</p> <div class="active preloader-wrapper small" id="progress-indicator"> <div class="spinner-layer spinner-blue-only"> <div class="circle-clipper left"> <div class="circle"></div> </div> <div class="gap-patch"> <div class="circle"></div> </div> <div class="circle-clipper right"> <div class="circle"></div> </div> </div> </div> <span class="chip status white-text" id="status"></span> </div> <div class="col s12 m8"> <ul class="collapsible expandable" id="job-list"> <li class="active"> <div class="collapsible-header"> <i class="material-icons">input</i>Input files </div> <div class="collapsible-body"> <table class="highlight responsive-table"> <thead> <tr> <th>Filename</th> <th>Download</th> </tr> </thead> <tbody id="inputs"> {% for input in job.inputs %} <tr> <td id="input-{{ input.id }}-filename">{{ input.filename }}</td> <td id="input-{{ input.id }}-download"> <a class="waves-effect waves-light btn-small" download href="{{ url_for('jobs.download_job_input', job_id=job.id, job_input_id=input.id) }}"> <i class="material-icons">file_download</i> </a> </td> </tr> {% endfor %} </tbody> </table> </div> </li> <li> <div class="collapsible-header"><i class="material-icons">done</i>Result files</div> <div class="collapsible-body"> <table class="highlight responsive-table"> <thead> <tr> <th>Bundlename</th> <th>Download</th> </tr> </thead> <tbody id="results"></tbody> </table> </div> </li> <li> <div class="collapsible-header"><i class="material-icons">settings</i>Settings</div> <div class="collapsible-body"> <div class="row"> <div class="col s12">Chronometrics</div> <div class="col s12 m6"> <div class="input-field"> <input disabled value="{{ job.creation_date.strftime('%m/%d/%Y, %H:%M:%S %p') }}" id="creation-date" type="text" class="validate"> <label for="creation-date">Creation date</label> </div> </div> <div class="col s12 m6"> <div class="input-field"> <input disabled value="" id="end-date" type="text" class="validate"> <label for="end-date">End date</label> </div> </div> <div class="col s12">Ressource allocations</div> <div class="col s12 m6"> <div class="input-field"> <input disabled value="{{ job.mem_mb }}" id="mem-mb" type="text" class="validate"> <label for="mem-mb">Memory</label> </div> </div> <div class="col s12 m6"> <div class="input-field"> <input disabled value="{{ job.n_cores }}" id="n-cores" type="text" class="validate"> <label for="n-cores">CPU cores</label> </div> </div> <div class="col s12">Service informations</div> <div class="col s12 m4"> <div class="input-field"> <input disabled value="{{ job.service }}" id="service" type="text" class="validate"> <label for="service">Service</label> </div> </div> <div class="col s12 m4"> <div class="input-field"> <input disabled value="{{ job.service_args|e }}" id="service-args" type="text" class="validate"> <label for="service-args">Service arguments</label> </div> </div> <div class="col s12 m4"> <div class="input-field"> <input disabled value="{{ job.service_version }}" id="service-version" type="text" class="validate"> <label for="service-version">Service version</label> </div> </div> <div class="col s12 right-align"> <a href="#" class="waves-effect waves-light btn"><i class="material-icons left">settings</i>Export Parameters</a> <a data-target="delete-job-modal" class="waves-effect waves-light btn red modal-trigger"><i class="material-icons left">delete</i>Delete</a> </div> </div> </div> </li> </ul> </div> <!-- Modals --> <div id="delete-job-modal" class="modal"> <div class="modal-content"> <h4>Confirm deletion</h4> <p>Do you really want to delete the job {{job.title}}? All associated files will be permanently deleted.</p> </div> <div class="modal-footer"> <a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a> <a class="btn modal-close red waves-effect waves-light" href="{{ url_for('jobs.delete_job', job_id=job.id) }}"><i class="material-icons left">delete</i>Delete</a> </div> </div> <script> class InformationUpdater { constructor(jobId, foreignJobFlag) { this.jobId = jobId; this.foreignJobFlag = foreignJobFlag; if (this.foreignJobFlag) { nopaque.foreignJobsSubscribers.push(this); } else { nopaque.jobsSubscribers.push(this); } } _init() { let job; if (this.foreignJobFlag) { job = nopaque.foreignJobs[this.jobId]; } else { job = nopaque.jobs[this.jobId]; } // End date this.setEndDate(job.end_date); // Status this.setStatus(job.status); // End date if (job.end_date) {this.setEndDate(job.end_date);} // Results if (job.results) {this.setResults(job.results);} } _update(patch) { let pathArray; for (let operation of patch) { /* "/jobId/valueName" -> ["jobId", "valueName"] */ pathArray = operation.path.split("/").slice(1); if (pathArray[0] != this.jobId) {continue;} switch(operation.op) { case "add": if (pathArray[1] === "results") { this.setResults([operation.value]); } break; case "delete": location.reload(); break; case "replace": if (pathArray[1] === "end_date") { this.setEndDate(operation.value); } else if (pathArray[1] === "status") { this.setStatus(operation.value); } break; default: break; } } } setEndDate(timestamp) { let end_date; if (timestamp === null) { end_date = "N.a."; } else { end_date = new Date(timestamp * 1000).toLocaleString("en-US"); } document.getElementById("end-date").value = end_date; M.updateTextFields(); } setResults(results) { let resultsElement; resultsElement = document.getElementById("results"); for (let result of results) { resultsElement.insertAdjacentHTML( "beforeend", `<tr> <td>${result.filename}</td> <td> <a class="btn-small waves-effect waves-light" download href="/jobs/${result.job_id}/results/${result.id}/download"> <i class="material-icons">file_download</i> </a> </td> </tr>` ); } } setStatus(status) { let progressIndicator, statusElement; if (status === "complete") { progressIndicator = document.getElementById("progress-indicator"); progressIndicator.classList.add("hide"); M.Collapsible.getInstance(document.getElementById("job-list")).open(1); } statusElement = document.getElementById("status"); statusElement.dataset.status = status; } } {% if job.creator == current_user %} var informationUpdater = new InformationUpdater({{ job.id }}, false); {% else %} var informationUpdater = new InformationUpdater({{ job.id }}, true); nopaque.socket.emit('foreign_user_ressources_init', {{ job.user_id }}); {% endif %} </script> {% endblock %}