{% extends "nopaque.html.j2" %} {% set headline = '<i class="left material-icons service" data-service="{service}" style="font-size: inherit;"></i>Job ({service}) - {title}'.format(service=job.service, title=job.title) %} {% if job.service == 'file-setup' %} {% set main_class = 'file-setup-color lighten' %} {% elif job.service == 'nlp' %} {% set main_class = 'nlp-color lighten' %} {% elif job.service == 'ocr' %} {% set main_class = 'ocr-color lighten' %} {% endif %} {% block page_content %} {% if job.service == 'file-setup' %} {{ Macros.insert_color_scheme(file_setup_color_darken) }} {% set border_color = file_setup_color_darken %} {% elif job.service == 'nlp' %} {{ Macros.insert_color_scheme(nlp_color_darken) }} {% set border_color = nlp_color_darken %} {% elif job.service == 'ocr' %} {{ Macros.insert_color_scheme(ocr_color_darken) }} {% set border_color = ocr_color_darken %} {% endif %} <div class="col s12"> <div class="card" style="border-top: 10px solid {{border_color}}"> <div class="card-content"> <div class="row"> <div class="col s8 m9 l10"> <span class="card-title title">{{ job.title }}</span> </div> <div class="col s4 m3 l2 right-align"> <span class="chip status white-text"></span> <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> </div> <div class="col s12"> <p class="description">{{ job.description }}</p> </div> <div class="col s12"> </div> <div class="col s12 m6"> <div class="input-field"> <input disabled id="creation-date" type="text" value="{{ job.creation_date.strftime('%d/%m/%Y, %H:%M:%S %p') }}"> <label for="creation-date">Creation date</label> </div> </div> <div class="col s12 m6"> <div class="input-field"> <input class="end-date" disabled id="end-date" type="text" value=""> <label for="end-date">End date</label> </div> </div> <div class="col s12 m4"> <div class="input-field"> <input disabled id="service" type="text" value="{{ job.service }}"> <label for="service">Service</label> </div> </div> <div class="col s12 m4"> <div class="input-field"> <input disabled id="service-args" type="text" value="{{ job.service_args|e }}"> <label for="service-args">Service arguments</label> </div> </div> <div class="col s12 m4"> <div class="input-field"> <input disabled id="service-version" type="text" value="{{ job.service_version }}"> <label for="service-version">Service version</label> </div> </div> </div> </div> <div class="card-action right-align"> {% if current_user.is_administrator() and job.status == 'failed' %} <a href="{{ url_for('jobs.restart', job_id=job.id) }}" class="btn waves-effect waves-light"><i class="material-icons left">repeat</i>Restart</a> {% endif %} <!-- <a href="#" class="btn disabled waves-effect waves-light"><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> <div class="col s12"> <div class="card"> <div class="card-content" id="inputs"> <div class="row"> <div class="col s12 m2"> <span class="card-title"><i class="left material-icons" style="font-size: inherit;">input</i>Inputs</span> <p>Original input files.</p> </div> <div class="col s12 m10"> <ul class="pagination paginationTop"></ul> <table class="highlight responsive-table"> <thead> <tr> <th class="sort" data-sort="filename">Filename</th> <th>{# Actions #}</th> </tr> </thead> <tbody class="list"> </tbody> </table> <ul class="pagination paginationBottom"></ul> </div> </div> </div> </div> </div> <div class="col s12"> <div class="card"> <div class="card-content"> <div class="row"> <div class="col s12 m2"> <span class="card-title"><i class="left material-icons" style="font-size: inherit;">done</i>Results</span> <p>Processed result files.</p> </div> <div class="col s12 m10"> <table class="highlight responsive-table"> <thead> <tr> <th>Result Type</th> <th>Archive Name</th> <th>{# Actions #}</th> </tr> </thead> <tbody class="results"> <tr class="show-if-only-child"> <td colspan="3"> <span class="card-title"> <i class="left material-icons" style="font-size: inherit;">file_download</i>Nothing here... </span> <p> No results available (yet). Is the job already completed? </p> </td> </tr> </tbody> </table> </div> </div> </div> </div> </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 type="module"> import {RessourceList} from '../../static/js/nopaque.lists.js'; 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; job = (this.foreignJobFlag ? nopaque.foreignUser.jobs[this.jobId] : nopaque.user.jobs[this.jobId]); // Results this.addResults(job.results); // End date this.setEndDate(job.end_date); // Status this.setStatus(job.status); } _update(patch) { let pathArray; for (let operation of patch) { /* "/jobs/{jobId}/..." -> ["{jobId}", ...] */ pathArray = operation.path.split("/").slice(2); if (pathArray[0] != this.jobId) {continue;} switch(operation.op) { case "add": if (pathArray[1] === "results") { this.addResults([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; } } } addResults(results) { let resultsArray, resultsElements, resultsHTML, resultType; resultsArray = Object.values(results); resultsArray.sort(function (a, b) { if (a.filename < b.filename) {return -1;} if (a.filename > b.filename) {return 1;} return 0; }); resultsHTML = ``; for (let result of resultsArray) { if (result.filename.endsWith(".pdf.zip")) { resultType = "PDF file with text layer"; } else if (result.filename.endsWith(".txt.zip")) { resultType = "Raw text files"; } else if (result.filename.endsWith(".vrt.zip")) { resultType = "VRT(XML dialect) files holding the NLP data"; } else if (result.filename.endsWith(".xml.zip")) { resultType = "XML files"; } else if (result.filename.endsWith(".poco.zip")) { resultType = "HCOR und image files needed for Post correction(PoCo)"; } else { resultType = "All result files created during this job"; } resultsHTML += ` <tr> <td>${resultType}</td> <td>${result.filename}</td> <td class="right-align"> <a class="btn-floating tooltipped waves-effect waves-light" download href="/jobs/${result.job_id}/results/${result.id}/download" data-position="top" data-tooltip="Download"> <i class="material-icons">file_download</i> </a> </td> </tr> `; }; resultsHTML += ` </tbody> </table> `; resultsElements = document.querySelectorAll(".results"); for (let resultsElement of resultsElements) { resultsElement.innerHTML += resultsHTML; } } setEndDate(timestamp) { let endDate; if (timestamp === null) { endDate = "N.a."; } else { endDate = new Date(timestamp * 1000).toLocaleString("en-US"); } document.getElementById("end-date").value = endDate; M.updateTextFields(); } setStatus(status) { let progressIndicator, statusElements; if (status === "complete" || status === "failed") { progressIndicator = document.getElementById("progress-indicator"); progressIndicator.classList.add("hide"); } statusElements = document.querySelectorAll(".status"); for (let statusElement of statusElements) { statusElement.dataset.status = status; } } } {% if job.creator == current_user %} var informationUpdater = new InformationUpdater({{ job.id }}, false); {% else %} var informationUpdater = new InformationUpdater({{ job.id }}, true); document.addEventListener("DOMContentLoaded", () => { nopaque.socket.emit("foreign_user_data_stream_init", {{ job.user_id }}); }); {% endif %} let jobInputsList = new RessourceList("inputs", null, "JobInput"); document.addEventListener("DOMContentLoaded", () => { jobInputsList._add({{ job_inputs|tojson|safe }}); }); </script> {% endblock %}