mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2025-06-27 00:10:35 +00:00
Bump Socket.IO Version and update to new List and Display logic for live data
This commit is contained in:
@ -2,85 +2,93 @@
|
||||
{% from '_colors.html.j2' import colors %}
|
||||
|
||||
{% set scheme_primary_color = colors.corpus_analysis_darken %}
|
||||
{% set scheme_secondary_color = colors.corpus_analysis %}
|
||||
{% set scheme_secondary_color = colors.corpus_analysis_lighten %}
|
||||
{% block main_attribs %} style="background-color: {{ scheme_secondary_color }};"{% endblock main_attribs %}
|
||||
|
||||
{% block nav_content %}
|
||||
{% include 'corpora/_breadcrumbs.html.j2' %}
|
||||
{% endblock nav_content %}
|
||||
|
||||
{% block main_attribs %} class="corpus-analysis-color lighten"{% endblock main_attribs %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h1 id="title">{{ corpus.title }}</h1>
|
||||
<p id="description">{{ corpus.description }}</p>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m4">
|
||||
<span class="chip status white-text hide" id="status"></span>
|
||||
<div class="active preloader-wrapper small hide status-spinner" 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 class="col s12" data-corpus-id="{{ corpus.id }}" data-user-id="{{ corpus.creator.id }}" id="corpus-display">
|
||||
<div class="row">
|
||||
<div class="col s8 m9 l10">
|
||||
<h1 id="title"><span class="corpus-title"></span></h1>
|
||||
</div>
|
||||
<div class="col s4 m3 l2 right-align">
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<span class="chip status white-text"></span>
|
||||
<div class="active preloader-wrapper small status-spinner">
|
||||
<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>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m8">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="card-content" style="border-top: 10px solid {{ scheme_primary_color }}">
|
||||
<span class="card-title">Chronometrics</span>
|
||||
<div class="row">
|
||||
<div class="col s12 m6">
|
||||
<div class="input-field">
|
||||
<input disabled value="{{ corpus.creation_date.strftime('%d/%m/%Y, %H:%M:%S %p') }}" id="creation-date" type="text" class="validate">
|
||||
<label for="creation-date">Creation date</label>
|
||||
<input class="corpus-creation-date validate" disabled id="corpus-creation-date" type="text">
|
||||
<label for="corpus-creation-date">Creation date</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s12 m6">
|
||||
<div class="input-field">
|
||||
<input disabled value="{{ corpus.last_edited_date.strftime('%d/%m/%Y, %H:%M:%S %p') }}" id="last_edited_date" type="text" class="validate">
|
||||
<label for="creation-date">Last edited</label>
|
||||
<input class="corpus-last-edited-date validate" disabled id="corpus-last-edited-date" type="text">
|
||||
<label for="corpus-last-edited-date">Last edited</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col s12 m6">
|
||||
<div class="input-field">
|
||||
<input disabled value="{{ corpus.current_nr_of_tokens }} / {{ corpus.max_nr_of_tokens }}" id="nr_of_tokens" type="text" class="validate">
|
||||
<label for="creation-date">Nr. of tokens used
|
||||
<i class="material-icons tooltipped" data-position="bottom" data-tooltip="Current number of tokens in this corpus. Updates after every analyze session.">help</i>
|
||||
</label>
|
||||
<input class="corpus-token-ratio validate" disabled id="corpus-token-ratio" type="text">
|
||||
<label for="corpus-token-ratio">Nr. of tokens used <sup><i class="material-icons tooltipped tiny" data-position="bottom" data-tooltip="Current number of tokens in this corpus. Updates after every analyze session.">help</i></sup></label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-action right-align">
|
||||
<a href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}" class="btn disabled hide waves-effect waves-light" id="analyze"><i class="material-icons left">search</i>Analyze</a>
|
||||
<a href="{{ url_for('corpora.prepare_corpus', corpus_id=corpus.id) }}" class="btn disabled hide waves-effect waves-light" id="build"><i class="material-icons left">build</i>Build</a>
|
||||
<a class="btn hide waves-effect waves-light download" id="corpus_create_zip"><i class="material-icons left">import_export</i>Export Corpus</a>
|
||||
<a data-target="delete-corpus-modal" class="btn modal-trigger red waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
|
||||
<a class="btn disabled hide waves-effect waves-light" href="{{ url_for('corpora.analyse_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">search</i>Analyze</a>
|
||||
<a class="btn disabled hide waves-effect waves-light" href="{{ url_for('corpora.prepare_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">build</i>Build</a>
|
||||
<a class="btn hide waves-effect waves-light" id="corpus-export"><i class="material-icons left">import_export</i>Export Corpus</a>
|
||||
<a class="btn modal-trigger red waves-effect waves-light" data-target="delete-corpus-modal"><i class="material-icons left">delete</i>Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="delete-corpus-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Confirm corpus deletion</h4>
|
||||
<p>Do you really want to delete the corpus <span class="corpus-title"></span>? All files will be permanently deleted!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a class="btn modal-close waves-effect waves-light" href="#!">Cancel</a>
|
||||
<a class="btn modal-close red waves-effect waves-light" href="{{ url_for('corpora.delete_corpus', corpus_id=corpus.id) }}"><i class="material-icons left">delete</i>Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col s12"></div>
|
||||
|
||||
<div class="col s12">
|
||||
<div class="col s12" id="corpus-files" data-corpus-id="{{ corpus.id }}" data-user-id="{{ corpus.creator.id }}">
|
||||
<div class="card">
|
||||
<div class="card-content" id="corpus-files" style="overflow: hidden;">
|
||||
<div class="card-content">
|
||||
<span class="card-title" id="files">Corpus files</span>
|
||||
<div class="input-field">
|
||||
<i class="material-icons prefix">search</i>
|
||||
<input id="search-results" class="search" type="search"></input>
|
||||
<label for="search-results">Search results</label>
|
||||
<input class="search" id="search-corpus-files" type="search"></input>
|
||||
<label for="search-corpus-files">Search corpus files</label>
|
||||
</div>
|
||||
<table class="highlight responsive-table">
|
||||
<thead>
|
||||
@ -89,18 +97,10 @@
|
||||
<th class="sort" data-sort="author">Author</th>
|
||||
<th class="sort" data-sort="title">Title</th>
|
||||
<th class="sort" data-sort="publishing-year">Publishing year</th>
|
||||
<th>{# Actions #}</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list">
|
||||
{% if corpus_files|length == 0 %}
|
||||
<tr class="show-if-only-child">
|
||||
<td colspan="5">
|
||||
<span class="card-title"><i class="material-icons left">book</i>Nothing here...</span>
|
||||
<p>Corpus is empty. Add texts using the option below.</p>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
<tbody class="list"></tbody>
|
||||
</table>
|
||||
<ul class="pagination"></ul>
|
||||
</div>
|
||||
@ -111,140 +111,14 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modals -->
|
||||
<div id="delete-corpus-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Confirm corpus deletion</h4>
|
||||
<p>Do you really want to delete the corpus {{ corpus.title }}? All files will be permanently deleted!</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
|
||||
<a href="{{ url_for('corpora.delete_corpus', corpus_id=corpus.id) }}" class="btn modal-close red waves-effect waves-light"><i class="material-icons left">delete</i>Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock page_content %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<script type="module">
|
||||
import {
|
||||
RessourceList
|
||||
} from '../../static/js/nopaque.lists.js';
|
||||
|
||||
class InformationUpdater {
|
||||
constructor(corpusId, foreignCorpusFlag) {
|
||||
this.corpusId = corpusId;
|
||||
this.foreignCorpusFlag = foreignCorpusFlag;
|
||||
|
||||
if (this.foreignCorpusFlag) {
|
||||
nopaque.foreignCorporaSubscribers.push(this);
|
||||
} else {
|
||||
nopaque.corporaSubscribers.push(this);
|
||||
}
|
||||
}
|
||||
|
||||
_init() {
|
||||
let corpus;
|
||||
|
||||
corpus = (this.foreignCorpusFlag ? nopaque.foreignUser.corpora[this.corpusId]
|
||||
: nopaque.user.corpora[this.corpusId]);
|
||||
|
||||
// Status
|
||||
this.setStatus(corpus.status);
|
||||
}
|
||||
|
||||
_update(patch) {
|
||||
let pathArray;
|
||||
|
||||
for (let operation of patch) {
|
||||
/* "/corpora/{corpusId}/valueName" -> ["{corpusId}", ...] */
|
||||
pathArray = operation.path.split("/").slice(2);
|
||||
if (pathArray[0] != this.corpusId) {continue;}
|
||||
switch(operation.op) {
|
||||
case "add":
|
||||
location.reload();
|
||||
break;
|
||||
case "delete":
|
||||
location.reload();
|
||||
break;
|
||||
case "replace":
|
||||
if (pathArray[1] === "status") {
|
||||
this.setStatus(operation.value);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setStatus(status) {
|
||||
let analyzeElement, buildElement, numFiles, progressIndicatorElement, statusElement;
|
||||
|
||||
numFiles = Object.keys((this.foreignCorpusFlag ? nopaque.foreignUser.corpora[this.corpusId] : nopaque.user.corpora[this.corpusId]).files).length;
|
||||
|
||||
progressIndicatorElement = document.getElementById("progress-indicator");
|
||||
if (["queued", "running", "start analysis", "stop analysis"].includes(status)) {
|
||||
progressIndicatorElement.classList.remove("hide");
|
||||
} else {
|
||||
progressIndicatorElement.classList.add("hide");
|
||||
}
|
||||
|
||||
statusElement = document.getElementById("status");
|
||||
statusElement.dataset.status = status;
|
||||
statusElement.classList.remove("hide");
|
||||
|
||||
analyzeElement = document.getElementById("analyze");
|
||||
if (["analysing", "prepared", "start analysis"].includes(status)) {
|
||||
analyzeElement.classList.remove("disabled", "hide");
|
||||
} else {
|
||||
analyzeElement.classList.add("disabled", "hide");
|
||||
}
|
||||
|
||||
buildElement = document.getElementById("build");
|
||||
if (status === "unprepared" && numFiles > 0) {
|
||||
buildElement.classList.remove("disabled", "hide");
|
||||
} else {
|
||||
buildElement.classList.add("disabled", "hide");
|
||||
}
|
||||
|
||||
let downloadBtn = document.querySelector('#corpus_create_zip');
|
||||
if (status === "prepared") {
|
||||
downloadBtn.classList.toggle('hide', false);
|
||||
} else {
|
||||
downloadBtn.classList.toggle('hide', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{% if corpus.creator == current_user %}
|
||||
var informationUpdater = new InformationUpdater({{ corpus.id }}, false);
|
||||
{% else %}
|
||||
var informationUpdater = new InformationUpdater({{ corpus.id }}, true);
|
||||
nopaque.socket.emit("foreign_user_data_stream_init", {{ corpus.user_id }});
|
||||
{% endif %}
|
||||
|
||||
let corpusFilesList = new RessourceList("corpus-files", null, "CorpusFile");
|
||||
corpusFilesList._add({{ corpus_files|tojson|safe }});
|
||||
|
||||
// Events to handle full corpus download
|
||||
let downloadBtn = document.querySelector('#corpus_create_zip');
|
||||
downloadBtn.addEventListener('click', () => {
|
||||
nopaque.flash('Compressing your corpus', 'corpus')
|
||||
nopaque.socket.emit('corpus_create_zip', {{ corpus.id }});
|
||||
downloadBtn.classList.toggle('disabled', true);
|
||||
});
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
nopaque.socket.on('corpus_zip_created', () => {
|
||||
nopaque.flash('Downloading your corpus', 'corpus');
|
||||
downloadBtn.classList.toggle('disabled', false);
|
||||
// Little trick to call the download view after ziping has finished
|
||||
let fakeBtn = document.createElement('a');
|
||||
fakeBtn.href = '{{ url_for('corpora.export_corpus',
|
||||
corpus_id=corpus.id) }}';
|
||||
fakeBtn.click();
|
||||
});
|
||||
});
|
||||
<script>
|
||||
nopaque.appClient.loadUser({{ corpus.creator.id }});
|
||||
let corpusDisplay = new CorpusDisplay(document.querySelector('#corpus-display'));
|
||||
let corpusFileList = new CorpusFileList(document.querySelector('#corpus-files'));
|
||||
//let jobInputList = new CorpusFileList(document.querySelector('#job-inputs'));
|
||||
</script>
|
||||
{% endblock scripts %}
|
||||
|
@ -2,112 +2,132 @@
|
||||
{% from '_colors.html.j2' import colors %}
|
||||
|
||||
{% if job.service == 'file-setup' %}
|
||||
{% set border_color = colors.file_setup_darken %}
|
||||
{% set main_class = 'file-setup-color lighten' %}
|
||||
{% set scheme_color = colors.file_setup_darken %}
|
||||
{% set scheme_primary_color = colors.file_setup_darken %}
|
||||
{% set scheme_secondary_color = colors.file_setup_lighten %}
|
||||
{% elif job.service == 'nlp' %}
|
||||
{% set border_color = colors.nlp_darken %}
|
||||
{% set main_class = 'nlp-color lighten' %}
|
||||
{% set scheme_color = colors.nlp_darken %}
|
||||
{% set scheme_primary_color = colors.nlp_darken %}
|
||||
{% set scheme_secondary_color = colors.nlp_lighten %}
|
||||
{% elif job.service == 'ocr' %}
|
||||
{% set border_color = colors.ocr_darken %}
|
||||
{% set main_class = 'ocr-color lighten' %}
|
||||
{% set scheme_color = colors.ocr_darken %}
|
||||
{% set scheme_primary_color = colors.ocr_darken %}
|
||||
{% set scheme_secondary_color = colors.ocr_lighten %}
|
||||
{% endif %}
|
||||
{% block main_attribs %} style="background-color: {{ scheme_secondary_color }};"{% endblock main_attribs %}
|
||||
|
||||
{% block nav_content %}
|
||||
{% include 'jobs/_breadcrumbs.html.j2' %}
|
||||
{% endblock nav_content %}
|
||||
|
||||
{% block main_attribs %} class="{{ main_class }}"{% endblock main_attribs %}
|
||||
|
||||
{% block page_content %}
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h1>[{{ job.service }}] {{ job.title }}</h1>
|
||||
</div>
|
||||
<div class="col s12" data-job-id="{{ job.id }}" data-user-id="{{ job.creator.id }}" id="job-display">
|
||||
<div class="row">
|
||||
<div class="col s8 m9 l10">
|
||||
<h1 id="title">[<span class="job-service"></span>] <span class="job-title"></span></h1>
|
||||
</div>
|
||||
<div class="col s4 m3 l2 right-align">
|
||||
<p> </p>
|
||||
<p> </p>
|
||||
<span class="chip status white-text"></span>
|
||||
<div class="active preloader-wrapper small status-spinner">
|
||||
<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>
|
||||
|
||||
<div class="col s12">
|
||||
<div class="card" style="border-top: 10px solid {{border_color}}">
|
||||
<div class="card" style="border-top: 10px solid {{ scheme_primary_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 status-spinner" 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>
|
||||
<input class="job-description" disabled id="job-description" type="text">
|
||||
<label for="job-description">Description</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>
|
||||
<input class="job-creation-date" disabled id="job-creation-date" type="text">
|
||||
<label for="job-creation-date">Creation date</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col s12 m6">
|
||||
<div class="input-field">
|
||||
<input class="job-end-date" disabled id="job-end-date" type="text">
|
||||
<label for="job-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>
|
||||
<input class="job-service" disabled id="job-service" type="text">
|
||||
<label for="job-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>
|
||||
<input class="job-service-args" disabled id="job-service-args" type="text">
|
||||
<label for="job-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>
|
||||
<input class="job-service-version" disabled id="job-service-version" type="text">
|
||||
<label for="job-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>
|
||||
{% if current_user.is_administrator() %}
|
||||
<a class="btn hide modal-trigger restart-job-trigger waves-effect waves-light" data-target="restart-job-modal"><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>
|
||||
<a class="btn modal-trigger red waves-effect waves-light" data-target="delete-job-modal"><i class="material-icons left">delete</i>Delete</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="delete-job-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Confirm deletion</h4>
|
||||
<p>Do you really want to delete the job <span class="job-title"></span>? 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>
|
||||
|
||||
{% if current_user.is_administrator() %}
|
||||
<div id="restart-job-modal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h4>Confirm restart</h4>
|
||||
<p>Do you really want to restart the job <span class="job-title"></span>? All log and result 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.restart', job_id=job.id) }}"><i class="material-icons left">restart</i>Restart</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<div class="col s12">
|
||||
<div class="col s12" id="job-inputs" data-job-id="{{ job.id }}" data-user-id="{{ job.creator.id }}">
|
||||
<div class="card">
|
||||
<div class="card-content" id="inputs">
|
||||
<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>
|
||||
@ -118,11 +138,10 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="sort" data-sort="filename">Filename</th>
|
||||
<th>{# Actions #}</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="list">
|
||||
</tbody>
|
||||
<tbody class="list"></tbody>
|
||||
</table>
|
||||
<ul class="pagination"></ul>
|
||||
</div>
|
||||
@ -131,7 +150,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col s12">
|
||||
<div class="col s12" id="job-results" data-job-id="{{ job.id }}" data-user-id="{{ job.creator.id }}">
|
||||
<div class="card">
|
||||
<div class="card-content">
|
||||
<div class="row">
|
||||
@ -143,24 +162,14 @@
|
||||
<table class="highlight responsive-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Result Type</th>
|
||||
<th>Archive Name</th>
|
||||
<th>{# Actions #}</th>
|
||||
<th>Description</th>
|
||||
<th>Filename</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>
|
||||
<tbody class="list"></tbody>
|
||||
</table>
|
||||
<ul class="pagination"></ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -168,158 +177,14 @@
|
||||
</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>
|
||||
{% endblock page_content %}
|
||||
|
||||
{% block scripts %}
|
||||
{{ super() }}
|
||||
<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);
|
||||
nopaque.socket.emit("foreign_user_data_stream_init", {{ job.user_id }});
|
||||
{% endif %}
|
||||
let jobInputsList = new RessourceList("inputs", null, "JobInput");
|
||||
jobInputsList._add({{ job_inputs|tojson|safe }});
|
||||
<script>
|
||||
nopaque.appClient.loadUser({{ job.creator.id }});
|
||||
let jobDisplay = new JobDisplay(document.querySelector('#job-display'));
|
||||
let jobInputList = new JobInputList(document.querySelector('#job-inputs'));
|
||||
let jobResultList = new JobResultList(document.querySelector('#job-results'));
|
||||
</script>
|
||||
{% endblock scripts %}
|
||||
|
@ -252,9 +252,10 @@
|
||||
{% endif %}
|
||||
<script src="{{ url_for('static', filename='js/jsonpatch.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/list.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/socket.io.slim.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/nopaque.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/nopaque.lists.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/socket.io.min.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/nopaque/index.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/nopaque/RessourceDisplays.js') }}"></script>
|
||||
<script src="{{ url_for('static', filename='js/nopaque/RessorceLists.js') }}"></script>
|
||||
<script>
|
||||
// Disable all option elements with no value
|
||||
for (let optionElement of document.querySelectorAll('option[value=""]')) {optionElement.disabled = true;}
|
||||
|
Reference in New Issue
Block a user