Bump Socket.IO Version and update to new List and Display logic for live data

This commit is contained in:
Patrick Jentsch
2021-01-07 14:51:44 +01:00
parent 1b5b935a28
commit 9fb92c5a65
12 changed files with 1113 additions and 423 deletions

View File

@ -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>&nbsp;</p>
<p>&nbsp;</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 %}