mirror of
				https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
				synced 2025-10-31 02:32:45 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			262 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Django/Jinja
		
	
	
	
	
	
			
		
		
	
	
			262 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			Django/Jinja
		
	
	
	
	
	
| {% extends "nopaque.html.j2" %}
 | |
| 
 | |
| {% set headline = '<i class="left material-icons service" data-service="{service}" style="font-size: inherit;"></i>Job view'.format(service=job.service) %}
 | |
| 
 | |
| {% block page_content %}
 | |
| <div class="col s12">
 | |
|   <div class="card">
 | |
|     <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('%m/%d/%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">
 | |
|       <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">
 | |
|       <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">
 | |
|           <div class="inputs row">
 | |
|             {% for input in job.inputs %}
 | |
|               <div class="col s12 m6">
 | |
|                 <a class="btn waves-effect waves-light" download href="{{ url_for('jobs.download_job_input', job_id=job.id, job_input_id=input.id) }}">
 | |
|                   <i class="material-icons left">file_download</i>{{ input.filename }}
 | |
|                 </a>
 | |
|               </div>
 | |
|             {% endfor %}
 | |
|           </div>
 | |
|         </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">
 | |
|           <div class="results row">
 | |
|             <div class="show-if-only-child">
 | |
|               <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>
 | |
|             </div>
 | |
|           </div>
 | |
|         </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>
 | |
|   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";
 | |
|         } else if (result.filename.endsWith(".txt.zip")) {
 | |
|           resultType = "TXT";
 | |
|         } else if (result.filename.endsWith(".vrt.zip")) {
 | |
|           resultType = "VRT";
 | |
|         } else if (result.filename.endsWith(".xml.zip")) {
 | |
|           resultType = "XML";
 | |
|         } else {
 | |
|           resultType = "ALL";
 | |
|         }
 | |
|         resultsHTML += `<div class="col s4 m3 l2">
 | |
|                           <a class="btn waves-effect waves-light" download href="/jobs/${result.job_id}/results/${result.id}/download">
 | |
|                             <i class="material-icons left">file_download</i>${resultType}
 | |
|                           </a>
 | |
|                         </div>`;
 | |
|       }
 | |
|       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") {
 | |
|         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 %}
 | |
| </script>
 | |
| {% endblock %}
 |