First RessourceList update

This commit is contained in:
Patrick Jentsch 2020-07-30 14:17:51 +02:00
parent 889c568ceb
commit 715c37813c
12 changed files with 432 additions and 477 deletions

View File

@ -6,20 +6,24 @@ def init_logger():
''' '''
Functions initiates a logger instance. Functions initiates a logger instance.
''' '''
if not os.path.isfile('logs/nopaqued.log'): os.makedirs('logs', exist_ok=True)
file_path = os.path.join(os.getcwd(), 'logs/nopaqued.log') logging.basicConfig(filename='logs/nopaqued.log',
log = open(file_path, 'w+') format='[%(asctime)s] %(levelname)s in '
log.close() '%(pathname)s:%(lineno)d - %(message)s',
logging.basicConfig(datefmt='%Y-%m-%d %H:%M:%S', datefmt='%Y-%m-%d %H:%M:%S', filemode='w')
filemode='w', filename='logs/nopaqued.log', NOPAQUE_LOG_LEVEL = os.environ.get('NOPAQUE_LOG_LEVEL')
format='%(asctime)s - %(levelname)s - %(name)s - ' if NOPAQUE_LOG_LEVEL is None:
'%(filename)s - %(lineno)d - %(message)s') FLASK_CONFIG = os.environ.get('FLASK_CONFIG')
logger = logging.getLogger(__name__) if FLASK_CONFIG == 'development':
if os.environ.get('FLASK_CONFIG') == 'development': logging.basicConfig(level='DEBUG')
logger.setLevel(logging.DEBUG) elif FLASK_CONFIG == 'testing':
if os.environ.get('FLASK_CONFIG') == 'production': # TODO: Set an appropriate log level
logger.setLevel(logging.WARNING) pass
return logger elif FLASK_CONFIG == 'production':
logging.basicConfig(level='ERROR')
else:
logging.basicConfig(level=NOPAQUE_LOG_LEVEL)
return logging.getLogger(__name__)
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -40,6 +40,6 @@ services:
volumes: volumes:
- "/srv/nopaque/db:/var/lib/postgresql/data" - "/srv/nopaque/db:/var/lib/postgresql/data"
redis: redis:
image: redis:5 image: redis:6
volumes: volumes:
- "redis-trash1:/data" - "redis-trash1:/data"

View File

@ -169,10 +169,10 @@ def download_corpus_file(corpus_id, corpus_file_id):
filename=corpus_file.filename) filename=corpus_file.filename)
@corpora.route('/<int:corpus_id>/files/<int:corpus_file_id>/edit', @corpora.route('/<int:corpus_id>/files/<int:corpus_file_id>',
methods=['GET', 'POST']) methods=['GET', 'POST'])
@login_required @login_required
def edit_corpus_file(corpus_id, corpus_file_id): def corpus_file(corpus_id, corpus_file_id):
corpus = Corpus.query.get_or_404(corpus_id) corpus = Corpus.query.get_or_404(corpus_id)
corpus_file = CorpusFile.query.get_or_404(corpus_file_id) corpus_file = CorpusFile.query.get_or_404(corpus_file_id)
if not corpus_file.corpus_id == corpus_id: if not corpus_file.corpus_id == corpus_id:
@ -212,7 +212,7 @@ def edit_corpus_file(corpus_id, corpus_file_id):
edit_corpus_file_form.publishing_year.data = corpus_file.publishing_year edit_corpus_file_form.publishing_year.data = corpus_file.publishing_year
edit_corpus_file_form.school.data = corpus_file.school edit_corpus_file_form.school.data = corpus_file.school
edit_corpus_file_form.title.data = corpus_file.title edit_corpus_file_form.title.data = corpus_file.title
return render_template('corpora/edit_corpus_file.html.j2', return render_template('corpora/corpus_file.html.j2',
corpus_file=corpus_file, corpus=corpus, corpus_file=corpus_file, corpus=corpus,
edit_corpus_file_form=edit_corpus_file_form, edit_corpus_file_form=edit_corpus_file_form,
title='Edit corpus file') title='Edit corpus file')

View File

@ -43,7 +43,6 @@ nopaque.socket.init = function() {
for (let subscriber of nopaque.queryResultsSubscribers) { for (let subscriber of nopaque.queryResultsSubscribers) {
subscriber._init(nopaque.user.query_results); subscriber._init(nopaque.user.query_results);
} }
RessourceList.modifyTooltips(false)
}); });
nopaque.socket.on("user_data_stream_update", function(msg) { nopaque.socket.on("user_data_stream_update", function(msg) {
@ -86,7 +85,6 @@ nopaque.socket.init = function() {
for (let subscriber of nopaque.foreignQueryResultsSubscribers) { for (let subscriber of nopaque.foreignQueryResultsSubscribers) {
subscriber._init(nopaque.foreignUser.query_results); subscriber._init(nopaque.foreignUser.query_results);
} }
RessourceList.modifyTooltips(false)
}); });
nopaque.socket.on("foreign_user_data_stream_update", function(msg) { nopaque.socket.on("foreign_user_data_stream_update", function(msg) {

View File

@ -1,27 +1,19 @@
class RessourceList extends List { class RessourceList extends List {
constructor(idOrElement, subscriberList, type, options={}) { constructor(idOrElement, subscriberList, type, options) {
if (!["Corpus", "CorpusFile", "Job", "JobInput", "QueryResult", "User"].includes(type)) { if (!type || !["Corpus", "CorpusFile", "Job", "JobInput", "QueryResult", "User"].includes(type)) {
console.error("Unknown Type!"); throw "Unknown Type!";
return;
}
if (subscriberList) {
super(idOrElement, {...RessourceList.options['common'],
...RessourceList.options[type],
...options});
this.type = type;
subscriberList.push(this);
} else {
super(idOrElement, {...RessourceList.options['extended'],
...RessourceList.options[type],
...options});
this.type = type;
} }
super(idOrElement, {...RessourceList.options['common'],
...RessourceList.options[type],
...(options ? options : {})});
if (subscriberList) {subscriberList.push(this);}
this.type = type;
} }
_init(ressources) { _init(ressources) {
this.clear(); this.clear();
this.addRessources(Object.values(ressources)); this._add(Object.values(ressources));
this.sort("creation_date", {order: "desc"}); this.sort("creation_date", {order: "desc"});
} }
@ -35,7 +27,7 @@ class RessourceList extends List {
switch(operation.op) { switch(operation.op) {
case "add": case "add":
if (pathArray.includes("results")) {break;} if (pathArray.includes("results")) {break;}
this.addRessources([operation.value]); this._add([operation.value]);
break; break;
case "remove": case "remove":
this.remove("id", pathArray[0]); this.remove("id", pathArray[0]);
@ -56,30 +48,17 @@ class RessourceList extends List {
} }
} }
addRessources(ressources) { _add(values, callback) {
this.add(ressources.map(x => RessourceList.dataMapper[this.type](x))); this.add(values.map(x => RessourceList.dataMappers[this.type](x)), callback);
} // Initialize modal and tooltipped elements in list
M.AutoInit(this.listContainer);
// Use this to modify tooltips to show after 750ms. If loaded is set to
// true (default) tooltips will only be initialized if DOMContentLoaded event
// triggered. If you do not want to wait for this event set pass false.
static modifyTooltips(waitForDOMContentLoaded=true) {
if (waitForDOMContentLoaded) {
document.addEventListener('DOMContentLoaded', function() {
var elems = document.querySelectorAll('.tooltipped');
var instances = M.Tooltip.init(elems, {enterDelay: 750});
});
} else {
var elems = document.querySelectorAll('.tooltipped');
var instances = M.Tooltip.init(elems, {enterDelay: 750});
}
} }
} }
RessourceList.dataMapper = { RessourceList.dataMappers = {
// A data mapper describes entitys rendered per row. One key value pair holds // A data mapper describes entitys rendered per row. One key value pair holds
// the data to be rendered in the list.js table. Key has to correspond // the data to be rendered in the list.js table. Key has to correspond
// with the ValueNames defined below in RessourceList.options ValueNames. // with the ValueNames defined below in RessourceList.options ValueNames.
@ -87,221 +66,361 @@ RessourceList.dataMapper = {
// have to correspond with the class of an <a> element in the // have to correspond with the class of an <a> element in the
// RessourceList.options item blueprint. // RessourceList.options item blueprint.
// Mapping for Corpus entities shown in the dashboard table. /* ### Corpus mapper ### */
Corpus: corpus => ({creation_date: corpus.creation_date, Corpus: corpus => ({
"delete-onclick": `prepareDeleteCorpusModal(${corpus.id})`, creation_date: corpus.creation_date,
description: corpus.description, description: corpus.description,
id: corpus.id, id: corpus.id,
"analyse-link": ["analysing", "prepared", "start analysis"].includes(corpus.status) ? `/corpora/${corpus.id}/analyse` : "", link: `/corpora/${corpus.id}`,
"edit-link": `/corpora/${corpus.id}`, status: corpus.status,
status: corpus.status, title: corpus.title,
title: corpus.title}), title1: corpus.title,
// Mapping for corpus file entities shown in the corpus overview "analyse-link": ["analysing", "prepared", "start analysis"].includes(corpus.status) ? `/corpora/${corpus.id}/analyse` : "",
CorpusFile: corpus_file => ({filename: corpus_file.filename, "delete-link": `/corpora/${corpus.id}/delete`,
author: corpus_file.author, "delete-modal": `delete-corpus-${corpus.id}-modal`,
title: corpus_file.title, "delete-modal-trigger": `delete-corpus-${corpus.id}-modal`,
publishing_year: corpus_file.publishing_year, }),
"edit-link": `${corpus_file.corpus_id}/files/${corpus_file.id}/edit`, /* ### CorpusFile mapper ### TODO: replace delete-modal with delete-onclick */
"download-link": `${corpus_file.corpus_id}/files/${corpus_file.id}/download`, CorpusFile: corpus_file => ({
"delete-modal": `delete-corpus-file-${corpus_file.id}-modal`}), author: corpus_file.author,
// Mapping for job entities shown in the dashboard table. filename: corpus_file.filename,
Job: job => ({creation_date: job.creation_date, link: `${corpus_file.corpus_id}/files/${corpus_file.id}`,
"delete-onclick": `prepareDeleteJobModal(${job.id})`, publishing_year: corpus_file.publishing_year,
description: job.description, title: corpus_file.title,
id: job.id, title1: corpus_file.title,
link: `/jobs/${job.id}`, "delete-link": `/corpora/${corpus_file.corpus_id}/files/${corpus_file.id}/delete`,
service: job.service, "delete-modal": `delete-corpus-file-${corpus_file.id}-modal`,
status: job.status, "delete-modal-trigger": `delete-corpus-file-${corpus_file.id}-modal`,
title: job.title}), "download-link": `${corpus_file.corpus_id}/files/${corpus_file.id}/download`,
// Mapping for job input files shown in table on every job page }),
JobInput: job_input => ({filename: job_input.filename, /* ### Job mapper ### */
id: job_input.job_id, Job: job => ({
"download-link": `${job_input.job_id}/inputs/${job_input.id}/download`}), creation_date: job.creation_date,
// Mapping for imported result entities from corpus analysis. description: job.description,
// Shown in imported results table id: job.id,
QueryResult: query_result => ({corpus_name: query_result.query_metadata.corpus_name, link: `/jobs/${job.id}`,
"delete-onclick": `prepareDeleteQueryResultModal(${query_result.id})`, service: job.service,
description: query_result.description, status: job.status,
id: query_result.id, title: job.title,
"inspect-link": `/query_results/${query_result.id}/inspect`, title1: job.title,
link: `/query_results/${query_result.id}`, "delete-link": `/jobs/${job.id}/delete`,
query: query_result.query_metadata.query, "delete-modal": `delete-job-${job.id}-modal`,
title: query_result.title}), "delete-modal-trigger": `delete-job-${job.id}-modal`,
// Mapping for user entities shown in admin table }),
User: user => ({username: user.username, /* ### JobInput mapper ### */
email: user.email, JobInput: job_input => ({
role_id: user.role_id, filename: job_input.filename,
confirmed: user.confirmed, id: job_input.job_id,
id: user.id, "download-link": `${job_input.job_id}/inputs/${job_input.id}/download`
"profile-link": `user/${user.id}`}) }),
/* ### QueryResult mapper ### */
QueryResult: query_result => ({
corpus_name: query_result.query_metadata.corpus_name,
description: query_result.description,
id: query_result.id,
link: `/query_results/${query_result.id}`,
query: query_result.query_metadata.query,
title: query_result.title,
"delete-link": `/query_results/${query_result.id}/delete`,
"delete-modal": `delete-query-result-${query_result.id}-modal`,
"delete-modal-trigger": `delete-query-result-${query_result.id}-modal`,
"inspect-link": `/query_results/${query_result.id}/inspect`,
}),
/* ### User mapper ### */
User: user => ({
confirmed: user.confirmed,
email: user.email,
id: user.id,
link: `user/${user.id}`,
role_id: user.role_id,
username: user.username,
username2: user.username,
"delete-link": `/admin/user/${user.id}/delete`,
"delete-modal": `delete-user-${user.id}-modal`,
"delete-modal-trigger": `delete-user-${user.id}-modal`,
}),
}; };
RessourceList.options = { RessourceList.options = {
// common list.js options for 4 rows per page etc. // common list.js options for 4 rows per page etc.
common: {page: 4, pagination: {innerWindow: 8, outerWindow: 1}}, common: {
page: 4,
pagination: {
innerWindow: 8,
outerWindow: 1,
},
},
// extended list.js options for 10 rows per page etc. // extended list.js options for 10 rows per page etc.
extended: {page: 10, extended: {
pagination: [{name: "paginationTop", page: 10,
paginationClass: "paginationTop", pagination: [
innerWindow: 8, {
outerWindow: 1}, name: "paginationTop",
{paginationClass: "paginationBottom", paginationClass: "paginationTop",
innerWindow: 8, innerWindow: 8,
outerWindow: 1}]}, outerWindow: 1
},
{
paginationClass: "paginationBottom",
innerWindow: 8,
outerWindow: 1,
},
],
},
/* Type specific List.js options. Usually only "item" and "valueNames" gets /* Type specific List.js options. Usually only "item" and "valueNames" gets
* defined here but it is possible to define other List.js options. * defined here but it is possible to define other List.js options.
* item: https://listjs.com/api/#item * item: https://listjs.com/api/#item
* valueNames: https://listjs.com/api/#valueNames * valueNames: https://listjs.com/api/#valueNames
*/ */
Corpus: {item: `<tr> Corpus: {
<td> item: `<tr>
<a class="btn-floating disabled"> <td>
<i class="material-icons service">book</i> <a class="btn-floating disabled">
</a> <i class="material-icons service">book</i>
</td> </a>
<td> </td>
<b class="title"></b><br> <td>
<i class="description"></i> <b class="title"></b><br>
</td> <i class="description"></i>
<td> </td>
<span class="badge new status" data-badge-caption=""> <td>
</span> <span class="badge new status" data-badge-caption=""></span>
</td> </td>
<td class="actions right-align"> <td>
<a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-onclick" data-position="top" data-tooltip="Delete"> <div class="right-align">
<i class="material-icons">delete</i> <a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-modal-trigger" data-position="top" data-tooltip="Delete">
</a> <i class="material-icons">delete</i>
<a class="btn-floating tooltipped waves-effect waves-light edit-link" data-position="top" data-tooltip="Edit"> </a>
<i class="material-icons">edit</i> <a class="btn-floating tooltipped waves-effect waves-light link" data-position="top" data-tooltip="Edit">
</a> <i class="material-icons">edit</i>
<a class="btn-floating tooltipped waves-effect waves-light analyse-link" data-position="top" data-tooltip="Analyse"> </a>
<i class="material-icons">search</i> <a class="btn-floating tooltipped waves-effect waves-light analyse-link" data-position="top" data-tooltip="Analyse">
</a> <i class="material-icons">search</i>
</td> </a>
</tr>`, </div>
valueNames: ["creation_date", <div class="modal delete-modal">
"description", <div class="modal-content">
"title", <h4>Confirm corpus deletion</h4>
{data: ["id"]}, <p>Do you really want to delete the corpus <b class="title1"></b>? All files will be permanently deleted!</p>
{name: "analyse-link", attr: "href"}, </div>
{name: "delete-onclick", attr: "onclick"}, <div class="modal-footer">
{name: "edit-link", attr: "href"}, <a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
{name: "status", attr: "data-status"}]}, <a class="btn modal-close red waves-effect waves-light delete-link"><i class="material-icons left">delete</i>Delete</a>
CorpusFile: {item: `<tr> </div>
<td class="filename" style="word-break: break-word;"></td> </div>
<td class="author" style="word-break: break-word;"></td> </td>
<td class="title" style="word-break: break-word;"></td> </tr>`,
<td class="publishing_year" style="word-break: break-word;"></td> valueNames: [
<td class="actions right-align"> "creation_date",
<a class="btn-floating tooltipped waves-effect waves-light edit-link" data-position="top" data-tooltip="Edit"> "description",
<i class="material-icons">edit</i> "title",
</a> "title1",
<a class="btn-floating tooltipped waves-effect waves-light download-link" data-position="top" data-tooltip="Download"> {data: ["id"]},
<i class="material-icons">file_download</i> {name: "analyse-link", attr: "href"},
</a> {name: "delete-link", attr: "href"},
<a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-modal" data-position="top" data-tooltip="Delete"> {name: "delete-modal-trigger", attr: "data-target"},
<i class="material-icons">delete</i> {name: "delete-modal", attr: "id"},
</a> {name: "link", attr: "href"},
</td> {name: "status", attr: "data-status"},
</tr>`, ]
valueNames: ["filename", },
"author", CorpusFile: {
"title", item: `<tr>
"publishing_year", <td class="filename" style="word-break: break-word;"></td>
{name: "edit-link", attr: "href"}, <td class="author" style="word-break: break-word;"></td>
{name: "download-link", attr: "href"}, <td class="title" style="word-break: break-word;"></td>
{name: "delete-modal", attr: "data-target"}]}, <td class="publishing_year" style="word-break: break-word;"></td>
Job: {item: `<tr> <td>
<td> <div class="right-align">
<a class="btn-floating disabled"> <a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-modal-trigger" data-position="top" data-tooltip="Delete">
<i class="material-icons service"></i> <i class="material-icons">delete</i>
</a> </a>
</td> <a class="btn-floating tooltipped waves-effect waves-light download-link" data-position="top" data-tooltip="Download">
<td> <i class="material-icons">file_download</i>
<b class="title"></b><br> </a>
<i class="description"></i> <a class="btn-floating tooltipped waves-effect waves-light link" data-position="top" data-tooltip="Edit">
</td> <i class="material-icons">edit</i>
<td> </a>
<span class="badge new status" data-badge-caption=""></span> </div>
</td> <div class="modal delete-modal">
<td class="actions right-align"> <div class="modal-content">
<a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-onclick" data-position="top" data-tooltip="Delete"> <h4>Confirm corpus file deletion</h4>
<i class="material-icons">delete</i> <p>Do you really want to delete the corpus file <b class="title1"></b>? It be permanently deleted!</p>
</a> </div>
<a class="btn-floating tooltipped waves-effect waves-light link" data-position="top" data-tooltip="Go to Job"> <div class="modal-footer">
<i class="material-icons">send</i> <a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
</a> <a class="btn modal-close red waves-effect waves-light delete-link"><i class="material-icons left">delete</i>Delete</a>
</td> </div>
</tr>`, </div>
valueNames: ["creation_date", </td>
"description", </tr>`,
"title", valueNames: [
{data: ["id"]}, "author",
{name: "delete-onclick", attr: "onclick"}, "filename",
{name: "link", attr: "href"}, "publishing_year",
{name: "service", attr: "data-service"}, "title",
{name: "status", attr: "data-status"}]}, "title1",
JobInput: {item : `<tr> {name: "delete-link", attr: "href"},
<td class="filename"></td> {name: "delete-modal-trigger", attr: "data-target"},
<td class="actions right-align"> {name: "delete-modal", attr: "id"},
<a class="btn-floating tooltipped waves-effect waves-light download-link" data-position="top" data-tooltip="Download"> {name: "download-link", attr: "href"},
<i class="material-icons">file_download</i> {name: "link", attr: "href"},
</a> ],
</td> },
</tr>`, Job: {
valueNames: ["filename", item: `<tr>
"id", <td>
{name: "download-link", attr: "href"}]}, <a class="btn-floating disabled">
QueryResult: {item: `<tr> <i class="material-icons service"></i>
<td> </a>
<b class="title"></b><br> </td>
<i class="description"></i><br> <td>
</td> <b class="title"></b><br>
<td> <i class="description"></i>
<span class="corpus_name"></span><br> </td>
<span class="query"></span> <td>
</td> <span class="badge new status" data-badge-caption=""></span>
<td class="actions right-align"> </td>
<a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-onclick" data-position="top" data-tooltip="Delete"> <td>
<i class="material-icons">delete</i> <div class="right-align">
</a> <a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-modal-trigger" data-position="top" data-tooltip="Delete">
<a class="btn-floating tooltipped link waves-effect waves-light" data-position="top" data-tooltip="Info"> <i class="material-icons">delete</i>
<i class="material-icons">info</i> </a>
</a> <a class="btn-floating tooltipped waves-effect waves-light link" data-position="top" data-tooltip="Go to job">
<a class="btn-floating tooltipped waves-effect waves-light inspect-link" data-position="top" data-tooltip="Analyse"> <i class="material-icons">send</i>
<i class="material-icons">search</i> </a>
</a> </div>
</td> <div class="modal delete-modal">
</tr>`, <div class="modal-content">
valueNames: ["corpus_name", <h4>Confirm job deletion</h4>
"description", <p>Do you really want to delete the job <b class="title1"></b>? All files will be permanently deleted!</p>
"query", </div>
"title", <div class="modal-footer">
{data: ["id"]}, <a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
{name: "delete-onclick", attr: "onclick"}, <a class="btn modal-close red waves-effect waves-light delete-link"><i class="material-icons left">delete</i>Delete</a>
{name: "inspect-link", attr: "href"}, </div>
{name: "link", attr: "href"}]}, </div>
// User entity blueprint setting html strucuture per entity per row </td>
// Link classes have to correspond with Links defined in the Mapping process </tr>`,
User: {item: `<tr> valueNames: [
<td class="username"></td> "creation_date",
<td class="email"></td> "description",
<td class="role_id"></td> "title",
<td class="confirmed"></td> "title1",
<td class="id"></td> {data: ["id"]},
<td class="actions right-align"> {name: "delete-link", attr: "href"},
<a class="btn-floating tooltipped profile-link waves-effect waves-light" data-position="top" data-tooltip="Edit User"> {name: "delete-modal-trigger", attr: "data-target"},
<i class="material-icons">edit</i> {name: "delete-modal", attr: "id"},
</a> {name: "link", attr: "href"},
</td> {name: "service", attr: "data-service"},
</tr>`, {name: "status", attr: "data-status"},
valueNames: ["username", ],
"email", },
"role_id", JobInput: {
"confirmed", item : `<tr>
"id", <td class="filename"></td>
{name: "profile-link", attr: "href"}]} <td class="right-align">
<a class="btn-floating tooltipped waves-effect waves-light download-link" data-position="top" data-tooltip="Download">
<i class="material-icons">file_download</i>
</a>
</td>
</tr>`,
valueNames: [
"filename",
"id",
{name: "download-link", attr: "href"},
],
},
QueryResult: {
item: `<tr>
<td>
<b class="title"></b><br>
<i class="description"></i><br>
</td>
<td>
<span class="corpus_name"></span><br>
<span class="query"></span>
</td>
<td>
<div class="right-align">
<a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-modal-trigger" data-position="top" data-tooltip="Delete">
<i class="material-icons">delete</i>
</a>
<a class="btn-floating tooltipped waves-effect waves-light link" data-position="top" data-tooltip="Info">
<i class="material-icons">info</i>
</a>
<a class="btn-floating tooltipped waves-effect waves-light inspect-link" data-position="top" data-tooltip="Analyse">
<i class="material-icons">search</i>
</a>
</div>
<div class="modal delete-modal">
<div class="modal-content">
<h4>Confirm query result deletion</h4>
<p>Do you really want to delete the query result <b class="title1"></b>? It 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 delete-link"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
</td>
</tr>`,
valueNames: [
"corpus_name",
"description",
"query",
"title",
"title2",
{data: ["id"]},
{name: "delete-link", attr: "href"},
{name: "delete-modal-trigger", attr: "data-target"},
{name: "delete-modal", attr: "id"},
{name: "inspect-link", attr: "href"},
{name: "link", attr: "href"},
],
},
User: {
item: `<tr>
<td class="username"></td>
<td class="email"></td>
<td class="role_id"></td>
<td class="confirmed"></td>
<td class="id"></td>
<td>
<div class="right-align">
<a class="btn-floating modal-trigger red tooltipped waves-effect waves-light delete-modal-trigger" data-position="top" data-tooltip="Delete">
<i class="material-icons">delete</i>
</a>
<a class="btn-floating tooltipped waves-effect waves-light link" data-position="top" data-tooltip="Go to user">
<i class="material-icons">send</i>
</a>
</div>
<div class="modal delete-modal">
<div class="modal-content">
<h4>Confirm corpus deletion</h4>
<p>Do you really want to delete the job <b class="title1"></b>? 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 class="btn modal-close red waves-effect waves-light delete-link"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
</td>
</tr>`,
valueNames: [
"username",
"username2",
"email",
"role_id",
"confirmed",
"id",
{name: "link", attr: "href"},
{name: "delete-link", attr: "href"},
{name: "delete-modal-trigger", attr: "data-target"},
{name: "delete-modal", attr: "id"},
],
},
}; };

View File

@ -33,9 +33,10 @@
</div> </div>
<script> <script>
var ressources = {{ users|tojson|safe }}; var users = {{ users|tojson|safe }};
var userList = new RessourceList('users', null, "User"); var userList = new RessourceList('users', null, "User");
userList.addRessources(ressources); document.addEventListener("DOMContentLoaded", () => {
RessourceList.modifyTooltips(); userList.addRessources(users);
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -122,12 +122,6 @@
<script> <script>
// create corpus file table
var ressources = {{ corpus_files|tojson|safe }};
var corpusFilesList = new RessourceList("corpus-files", null, "CorpusFile");
corpusFilesList.addRessources(ressources);
RessourceList.modifyTooltips();
class InformationUpdater { class InformationUpdater {
constructor(corpusId, foreignCorpusFlag) { constructor(corpusId, foreignCorpusFlag) {
this.corpusId = corpusId; this.corpusId = corpusId;
@ -215,5 +209,9 @@
nopaque.socket.emit("foreign_user_data_stream_init", {{ corpus.user_id }}); nopaque.socket.emit("foreign_user_data_stream_init", {{ corpus.user_id }});
}); });
{% endif %} {% endif %}
var corpusFilesList = new RessourceList("corpus-files", null, "CorpusFile");
document.addEventListener("DOMContentLoaded", () => {
corpusFilesList._add({{ corpus_files|tojson|safe }});
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -158,12 +158,6 @@
<script> <script>
// job_input_table code
var ressources = {{ job_inputs|tojson|safe }};
var jobInputsList = new RessourceList("inputs", null, "JobInput");
jobInputsList.addRessources(ressources);
RessourceList.modifyTooltips();
class InformationUpdater { class InformationUpdater {
constructor(jobId, foreignJobFlag) { constructor(jobId, foreignJobFlag) {
this.jobId = jobId; this.jobId = jobId;
@ -299,5 +293,9 @@
nopaque.socket.emit("foreign_user_data_stream_init", {{ job.user_id }}); nopaque.socket.emit("foreign_user_data_stream_init", {{ job.user_id }});
}); });
{% endif %} {% endif %}
let jobInputsList = new RessourceList("inputs", null, "JobInput");
document.addEventListener("DOMContentLoaded", () => {
jobInputsList._add({{ job_inputs|tojson|safe }});
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -112,143 +112,49 @@
<p><a class="modal-trigger waves-effect waves-light btn" href="#" data-target="new-job-modal"><i class="material-icons left">add</i>New job</a></p> <p><a class="modal-trigger waves-effect waves-light btn" href="#" data-target="new-job-modal"><i class="material-icons left">add</i>New job</a></p>
</div> </div>
</div> </div>
</div> <div id="new-job-modal" class="modal">
<div class="modal-content">
<!-- Modals --> <h4>Select a service</h4>
<div id="delete-corpus-modal" class="modal"> <div class="row">
<div class="modal-content"> <div class="col s12 m4">
<h4>Confirm corpus deletion</h4> <a href="{{ url_for('services.service', service='file-setup') }}" style="color: rgba(0,0,0,0.87);">
<p>Do you really want to delete the corpus <b id="selected-corpus-title"></b>? All files will be permanently deleted!</p> <div class="card-panel center-align hoverable">
</div> <i class="large material-icons" style="color: #ee6e73;">burst_mode</i>
<div class="modal-footer"> <p>File setup</p>
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a> <p class="light">Digital copies of text based research data (books, letters, etc.) often comprise various files and formats. nopaque converts and merges those files to facilitate further processing and the application of other services.</p>
<a class="btn modal-close red waves-effect waves-light" id="selected-corpus-delete-link"><i class="material-icons left">delete</i>Delete</a> </div>
</div> </a>
</div> </div>
<div class="col s12 m4">
<div id="delete-job-modal" class="modal"> <a href="{{ url_for('services.service', service='ocr') }}" style="color: rgba(0,0,0,0.87);">
<div class="modal-content"> <div class="card-panel center-align hoverable">
<h4>Confirm job deletion</h4> <i class="large material-icons" style="color: #ee6e73;">find_in_page</i>
<p>Do you really want to delete the job <b id="selected-job-title"></b>? All files will be permanently deleted!</p> <p>Optical Character Recognition</p>
</div> <p class="light">nopaque converts your image data like photos or scans into text data through a process called OCR. This step enables you to proceed with further computational analysis of your documents.</p>
<div class="modal-footer"> </div>
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a> </a>
<a class="btn modal-close red waves-effect waves-light" id="selected-job-delete-link"><i class="material-icons left">delete</i>Delete</a> </div>
</div> <div class="col s12 m4">
</div> <a href="{{ url_for('services.service', service='nlp') }}" style="color: rgba(0,0,0,0.87);">
<div class="card-panel center-align hoverable">
<div id="delete-query-result-modal" class="modal no-autoinit"> <i class="large material-icons" style="color: #ee6e73;">format_textdirection_l_to_r</i>
<div class="modal-content"> <p>Natural Language Processing</p>
<h4>Confirm query result deletion</h4> <p class="light">By means of computational linguistic data processing (tokenization, lemmatization, part-of-speech tagging and named-entity recognition) nopaque extracts additional information from your text.</p>
<p>Do you really want to delete the query result <b id="selected-query-result-title"></b>? It will be permanently deleted.</p> </div>
</div> </a>
<div class="modal-footer"> </div>
<a href="#!" class="btn modal-close waves-effect waves-light">Cancel</a>
<a class="btn modal-close red waves-effect waves-light" id="selected-query-result-delete-link"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
<div id="new-job-modal" class="modal">
<div class="modal-content">
<h4>Select a service</h4>
<div class="row">
<div class="col s12 m4">
<a href="{{ url_for('services.service', service='file-setup') }}" style="color: rgba(0,0,0,0.87);">
<div class="card-panel center-align hoverable">
<i class="large material-icons" style="color: #ee6e73;">burst_mode</i>
<p>File setup</p>
<p class="light">Digital copies of text based research data (books, letters, etc.) often comprise various files and formats. nopaque converts and merges those files to facilitate further processing and the application of other services.</p>
</div>
</a>
</div>
<div class="col s12 m4">
<a href="{{ url_for('services.service', service='ocr') }}" style="color: rgba(0,0,0,0.87);">
<div class="card-panel center-align hoverable">
<i class="large material-icons" style="color: #ee6e73;">find_in_page</i>
<p>Optical Character Recognition</p>
<p class="light">nopaque converts your image data like photos or scans into text data through a process called OCR. This step enables you to proceed with further computational analysis of your documents.</p>
</div>
</a>
</div>
<div class="col s12 m4">
<a href="{{ url_for('services.service', service='nlp') }}" style="color: rgba(0,0,0,0.87);">
<div class="card-panel center-align hoverable">
<i class="large material-icons" style="color: #ee6e73;">format_textdirection_l_to_r</i>
<p>Natural Language Processing</p>
<p class="light">By means of computational linguistic data processing (tokenization, lemmatization, part-of-speech tagging and named-entity recognition) nopaque extracts additional information from your text.</p>
</div>
</a>
</div> </div>
</div> </div>
</div> <div class="modal-footer">
<div class="modal-footer"> <a href="#!" class="modal-close waves-effect waves-light btn-flat">Close</a>
<a href="#!" class="modal-close waves-effect waves-light btn-flat">Close</a> </div>
</div> </div>
</div> </div>
<script> <script>
var corpusList = new RessourceList("corpora", nopaque.corporaSubscribers, var corpusList = new RessourceList("corpora", nopaque.corporaSubscribers, "Corpus");
"Corpus");
var jobList = new RessourceList("jobs", nopaque.jobsSubscribers, "Job"); var jobList = new RessourceList("jobs", nopaque.jobsSubscribers, "Job");
var queryResultList = new RessourceList("query-results", var queryResultList = new RessourceList("query-results", nopaque.queryResultsSubscribers, "QueryResult");
nopaque.queryResultsSubscribers,
"QueryResult", {page: 10});
var deleteCorpusModalElement = document.getElementById("delete-corpus-modal");
var deleteCorpusModal;
var deleteJobModalElement = document.getElementById("delete-job-modal");
var deleteJobModal;
var deleteQueryResultModalElement = document.getElementById("delete-query-result-modal");
var deleteQueryResultModal;
var selectedCorpusDeleteLinkElement = document.getElementById("selected-corpus-delete-link");
var selectedCorpusTitleElement = document.getElementById("selected-corpus-title");
var selectedJobDeleteLinkElement = document.getElementById("selected-job-delete-link");
var selectedJobTitleElement = document.getElementById("selected-job-title");
var selectedQueryResultDeleteLinkElement = document.getElementById("selected-query-result-delete-link");
var selectedQueryResultTitleElement = document.getElementById("selected-query-result-title");
function prepareDeleteCorpusModal(selectedCorpusId) {
var selectedCorpus;
if (selectedCorpusId in nopaque.user.corpora) {
selectedCorpus = nopaque.user.corpora[selectedCorpusId];
selectedCorpusDeleteLinkElement.href = `/corpora/${selectedCorpus.id}/delete`;
selectedCorpusTitleElement.innerText = selectedCorpus.title;
} else {
selectedQueryResult = undefined;
selectedCorpusDeleteLinkElement.href = "";
selectedCorpusTitleElement.innerText = "";
}
deleteCorpusModal.open();
}
function prepareDeleteJobModal(selectedJobId) {
var selectedJob;
if (selectedJobId in nopaque.user.jobs) {
selectedJob = nopaque.user.jobs[selectedJobId];
selectedJobDeleteLinkElement.href = `/jobs/${selectedJob.id}/delete`;
selectedJobTitleElement.innerText = selectedJob.title;
} else {
selectedJob = undefined;
selectedJobDeleteLinkElement.href = "";
selectedJobTitleElement.innerText = "";
}
deleteJobModal.open();
}
function prepareDeleteQueryResultModal(selectedQueryResultId) {
var selectedQueryResult;
if (selectedQueryResultId in nopaque.user.query_results) {
selectedQueryResult = nopaque.user.query_results[selectedQueryResultId];
selectedQueryResultDeleteLinkElement.href = `/query_results/${selectedQueryResult.id}/delete`;
selectedQueryResultTitleElement.innerText = selectedQueryResult.title;
} else {
selectedQueryResult = undefined;
selectedQueryResultDeleteLinkElement.href = "";
selectedQueryResultTitleElement.innerText = "";
}
deleteQueryResultModal.open();
}
document.addEventListener("DOMContentLoaded", () => {
deleteCorpusModal = M.Modal.init(deleteCorpusModalElement);
deleteJobModal = M.Modal.init(deleteJobModalElement);
deleteQueryResultModal = M.Modal.init(deleteQueryResultModalElement);
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -83,72 +83,8 @@
</div> </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 <b id="selected-corpus-title"></b>? 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 class="btn modal-close red waves-effect waves-light" id="selected-corpus-delete-link"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
<div id="delete-query-result-modal" class="modal no-autoinit">
<div class="modal-content">
<h4>Confirm query result deletion</h4>
<p>Do you really want to delete the query result <b id="selected-query-result-title"></b>? It 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" id="selected-query-result-delete-link"><i class="material-icons left">delete</i>Delete</a>
</div>
</div>
<script> <script>
var corpusList = new RessourceList("corpora", nopaque.corporaSubscribers, var corpusList = new RessourceList("corpora", nopaque.corporaSubscribers, "Corpus");
"Corpus", {page: 10}); var queryResultList = new RessourceList("query-results", nopaque.queryResultsSubscribers, "QueryResult");
var queryResultList = new RessourceList("query-results",
nopaque.queryResultsSubscribers,
"QueryResult", {page: 10});
var deleteCorpusModalElement = document.getElementById("delete-corpus-modal");
var deleteCorpusModal;
var deleteQueryResultModalElement = document.getElementById("delete-query-result-modal");
var deleteQueryResultModal;
var selectedCorpusDeleteLinkElement = document.getElementById("selected-corpus-delete-link");
var selectedCorpusTitleElement = document.getElementById("selected-corpus-title");
var selectedQueryResultDeleteLinkElement = document.getElementById("selected-query-result-delete-link");
var selectedQueryResultTitleElement = document.getElementById("selected-query-result-title");
function prepareDeleteCorpusModal(selectedCorpusId) {
var selectedCorpus;
if (selectedCorpusId in nopaque.user.corpora) {
selectedCorpus = nopaque.user.corpora[selectedCorpusId];
selectedCorpusDeleteLinkElement.href = `/corpora/${selectedCorpus.id}/delete`;
selectedCorpusTitleElement.innerText = selectedCorpus.title;
} else {
selectedQueryResult = undefined;
selectedCorpusDeleteLinkElement.href = "";
selectedCorpusTitleElement.innerText = "";
}
deleteCorpusModal.open();
}
function prepareDeleteQueryResultModal(selectedQueryResultId) {
var selectedQueryResult;
if (selectedQueryResultId in nopaque.user.query_results) {
selectedQueryResult = nopaque.user.query_results[selectedQueryResultId];
selectedQueryResultDeleteLinkElement.href = `/query_results/${selectedQueryResult.id}/delete`;
selectedQueryResultTitleElement.innerText = selectedQueryResult.title;
} else {
selectedQueryResult = undefined;
selectedQueryResultDeleteLinkElement.href = "";
selectedQueryResultTitleElement.innerText = "";
}
deleteQueryResultModal.open();
}
document.addEventListener("DOMContentLoaded", () => {
deleteCorpusModal = M.Modal.init(deleteCorpusModalElement);
deleteQueryResultModal = M.Modal.init(deleteQueryResultModalElement);
});
</script> </script>
{% endblock %} {% endblock %}

View File

@ -47,12 +47,7 @@ class Config:
@staticmethod @staticmethod
def init_app(app): def init_app(app):
proxy_fix_kwargs = { proxy_fix_kwargs = {'x_for': 1, 'x_host': 1, 'x_port': 1, 'x_proto': 1}
'x_for': 1,
'x_host': 1,
'x_port': 1,
'x_proto': 1,
}
app.wsgi_app = ProxyFix(app.wsgi_app, **proxy_fix_kwargs) app.wsgi_app = ProxyFix(app.wsgi_app, **proxy_fix_kwargs)