mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-11-15 01:05:42 +00:00
Progress on list rework
This commit is contained in:
parent
1883a9bc63
commit
1003c4494d
@ -283,7 +283,7 @@ class JobInput(db.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def download_url(self):
|
def download_url(self):
|
||||||
return url_for('job.download_job_input', job_id=self.job_id,
|
return url_for('jobs.download_job_input', job_id=self.job_id,
|
||||||
job_input_id=self.id)
|
job_input_id=self.id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -323,7 +323,7 @@ class JobResult(db.Model):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def download_url(self):
|
def download_url(self):
|
||||||
return url_for('job.download_job_result', job_id=self.job_id,
|
return url_for('jobs.download_job_result', job_id=self.job_id,
|
||||||
job_result_id=self.id)
|
job_result_id=self.id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -384,8 +384,8 @@ class Job(db.Model):
|
|||||||
return os.path.join(self.creator.path, 'jobs', str(self.id))
|
return os.path.join(self.creator.path, 'jobs', str(self.id))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self):
|
def url(self):
|
||||||
return url_for('job.job', job_id=self.id)
|
return url_for('jobs.job', job_id=self.id)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
'''
|
'''
|
||||||
@ -430,9 +430,9 @@ class Job(db.Model):
|
|||||||
'description': self.description,
|
'description': self.description,
|
||||||
'end_date': (self.end_date.timestamp() if self.end_date else
|
'end_date': (self.end_date.timestamp() if self.end_date else
|
||||||
None),
|
None),
|
||||||
'service': {'args': self.service_args,
|
'service': self.service,
|
||||||
'name': self.service,
|
'service_args': self.service_args,
|
||||||
'version': self.service_version},
|
'service_version': self.service_version,
|
||||||
'status': self.status,
|
'status': self.status,
|
||||||
'title': self.title,
|
'title': self.title,
|
||||||
'inputs': {input.id: input.to_dict() for input in self.inputs},
|
'inputs': {input.id: input.to_dict() for input in self.inputs},
|
||||||
@ -529,6 +529,10 @@ class Corpus(db.Model):
|
|||||||
files = db.relationship('CorpusFile', backref='corpus', lazy='dynamic',
|
files = db.relationship('CorpusFile', backref='corpus', lazy='dynamic',
|
||||||
cascade='save-update, merge, delete')
|
cascade='save-update, merge, delete')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def analysis_url(self):
|
||||||
|
return url_for('corpora.analyse_corpus', corpus_id=self.id)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def path(self):
|
def path(self):
|
||||||
return os.path.join(self.creator.path, 'corpora', str(self.id))
|
return os.path.join(self.creator.path, 'corpora', str(self.id))
|
||||||
@ -538,7 +542,8 @@ class Corpus(db.Model):
|
|||||||
return url_for('corpora.corpus', corpus_id=self.id)
|
return url_for('corpora.corpus', corpus_id=self.id)
|
||||||
|
|
||||||
def to_dict(self):
|
def to_dict(self):
|
||||||
return {'url': self.url,
|
return {'analysis_url': self.analysis_url,
|
||||||
|
'url': self.url,
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'user_id': self.user_id,
|
'user_id': self.user_id,
|
||||||
'creation_date': self.creation_date.timestamp(),
|
'creation_date': self.creation_date.timestamp(),
|
||||||
@ -628,8 +633,10 @@ class QueryResult(db.Model):
|
|||||||
'url': self.url,
|
'url': self.url,
|
||||||
'id': self.id,
|
'id': self.id,
|
||||||
'user_id': self.user_id,
|
'user_id': self.user_id,
|
||||||
|
'corpus_title': self.query_metadata['corpus_name'],
|
||||||
'description': self.description,
|
'description': self.description,
|
||||||
'filename': self.filename,
|
'filename': self.filename,
|
||||||
|
'query': self.query_metadata['query'],
|
||||||
'query_metadata': self.query_metadata,
|
'query_metadata': self.query_metadata,
|
||||||
'title': self.title}
|
'title': self.title}
|
||||||
|
|
||||||
|
@ -27,13 +27,13 @@ nopaque.socket = io({transports: ['websocket']});
|
|||||||
nopaque.socket.on("user_data_stream_init", function(msg) {
|
nopaque.socket.on("user_data_stream_init", function(msg) {
|
||||||
nopaque.user = JSON.parse(msg);
|
nopaque.user = JSON.parse(msg);
|
||||||
for (let subscriber of nopaque.corporaSubscribers) {
|
for (let subscriber of nopaque.corporaSubscribers) {
|
||||||
subscriber._init(nopaque.user.corpora);
|
subscriber.init(nopaque.user.corpora);
|
||||||
}
|
}
|
||||||
for (let subscriber of nopaque.jobsSubscribers) {
|
for (let subscriber of nopaque.jobsSubscribers) {
|
||||||
subscriber._init(nopaque.user.jobs);
|
subscriber.init(nopaque.user.jobs);
|
||||||
}
|
}
|
||||||
for (let subscriber of nopaque.queryResultsSubscribers) {
|
for (let subscriber of nopaque.queryResultsSubscribers) {
|
||||||
subscriber._init(nopaque.user.query_results);
|
subscriber.init(nopaque.user.query_results);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -46,13 +46,13 @@ nopaque.socket.on("user_data_stream_update", function(msg) {
|
|||||||
jobs_patch = patch.filter(operation => operation.path.startsWith("/jobs"));
|
jobs_patch = patch.filter(operation => operation.path.startsWith("/jobs"));
|
||||||
query_results_patch = patch.filter(operation => operation.path.startsWith("/query_results"));
|
query_results_patch = patch.filter(operation => operation.path.startsWith("/query_results"));
|
||||||
for (let subscriber of nopaque.corporaSubscribers) {
|
for (let subscriber of nopaque.corporaSubscribers) {
|
||||||
subscriber._update(corpora_patch);
|
subscriber.update(corpora_patch);
|
||||||
}
|
}
|
||||||
for (let subscriber of nopaque.jobsSubscribers) {
|
for (let subscriber of nopaque.jobsSubscribers) {
|
||||||
subscriber._update(jobs_patch);
|
subscriber.update(jobs_patch);
|
||||||
}
|
}
|
||||||
for (let subscriber of nopaque.queryResultsSubscribers) {
|
for (let subscriber of nopaque.queryResultsSubscribers) {
|
||||||
subscriber._update(query_results_patch);
|
subscriber.update(query_results_patch);
|
||||||
}
|
}
|
||||||
if (["all", "end"].includes(nopaque.user.settings.job_status_site_notifications)) {
|
if (["all", "end"].includes(nopaque.user.settings.job_status_site_notifications)) {
|
||||||
for (operation of jobs_patch) {
|
for (operation of jobs_patch) {
|
||||||
@ -69,13 +69,13 @@ nopaque.socket.on("user_data_stream_update", function(msg) {
|
|||||||
nopaque.socket.on("foreign_user_data_stream_init", function(msg) {
|
nopaque.socket.on("foreign_user_data_stream_init", function(msg) {
|
||||||
nopaque.foreignUser = JSON.parse(msg);
|
nopaque.foreignUser = JSON.parse(msg);
|
||||||
for (let subscriber of nopaque.foreignCorporaSubscribers) {
|
for (let subscriber of nopaque.foreignCorporaSubscribers) {
|
||||||
subscriber._init(nopaque.foreignUser.corpora);
|
subscriber.init(nopaque.foreignUser.corpora);
|
||||||
}
|
}
|
||||||
for (let subscriber of nopaque.foreignJobsSubscribers) {
|
for (let subscriber of nopaque.foreignJobsSubscribers) {
|
||||||
subscriber._init(nopaque.foreignUser.jobs);
|
subscriber.init(nopaque.foreignUser.jobs);
|
||||||
}
|
}
|
||||||
for (let subscriber of nopaque.foreignQueryResultsSubscribers) {
|
for (let subscriber of nopaque.foreignQueryResultsSubscribers) {
|
||||||
subscriber._init(nopaque.foreignUser.query_results);
|
subscriber.init(nopaque.foreignUser.query_results);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -87,9 +87,9 @@ nopaque.socket.on("foreign_user_data_stream_update", function(msg) {
|
|||||||
corpora_patch = patch.filter(operation => operation.path.startsWith("/corpora"));
|
corpora_patch = patch.filter(operation => operation.path.startsWith("/corpora"));
|
||||||
jobs_patch = patch.filter(operation => operation.path.startsWith("/jobs"));
|
jobs_patch = patch.filter(operation => operation.path.startsWith("/jobs"));
|
||||||
query_results_patch = patch.filter(operation => operation.path.startsWith("/query_results"));
|
query_results_patch = patch.filter(operation => operation.path.startsWith("/query_results"));
|
||||||
for (let subscriber of nopaque.foreignCorporaSubscribers) {subscriber._update(corpora_patch);}
|
for (let subscriber of nopaque.foreignCorporaSubscribers) {subscriber.update(corpora_patch);}
|
||||||
for (let subscriber of nopaque.foreignJobsSubscribers) {subscriber._update(jobs_patch);}
|
for (let subscriber of nopaque.foreignJobsSubscribers) {subscriber.update(jobs_patch);}
|
||||||
for (let subscriber of nopaque.foreignQueryResultsSubscribers) {subscriber._update(query_results_patch);}
|
for (let subscriber of nopaque.foreignQueryResultsSubscribers) {subscriber.update(query_results_patch);}
|
||||||
});
|
});
|
||||||
|
|
||||||
nopaque.Forms = {};
|
nopaque.Forms = {};
|
||||||
|
@ -1,420 +1,140 @@
|
|||||||
class RessourceList extends List {
|
class RessourceList {
|
||||||
constructor(idOrElement, subscriberList, type, options) {
|
constructor(idOrElement, options = {}) {
|
||||||
if (!type || !["Corpus", "CorpusFile", "Job", "JobInput", "QueryResult", "User"].includes(type)) {
|
this.list = new List(idOrElement, {...RessourceList.options, ...options});
|
||||||
throw "Unknown Type!";
|
|
||||||
}
|
}
|
||||||
super(idOrElement, {...RessourceList.options['common'],
|
|
||||||
...RessourceList.options[type],
|
init(ressources) {
|
||||||
...(options ? options : {})});
|
this.list.clear();
|
||||||
if (subscriberList) {subscriberList.push(this);}
|
this.add(Object.values(ressources));
|
||||||
this.type = type;
|
this.list.sort('id', {order: 'desc'});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_init(ressources) {
|
update(patch) {
|
||||||
this.clear();
|
|
||||||
this._add(Object.values(ressources));
|
|
||||||
this.sort("id", {order: "desc"});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
_update(patch) {
|
|
||||||
let item, pathArray;
|
let item, pathArray;
|
||||||
|
|
||||||
for (let operation of patch) {
|
for (let operation of patch) {
|
||||||
/* "/{ressourceName}/{ressourceId}/..." -> ["{ressourceId}", "..."] */
|
/*
|
||||||
pathArray = operation.path.split("/").slice(2);
|
* '/{ressourceName}/{ressourceId}/{valueName}' -> ['{ressourceId}', {valueName}]
|
||||||
switch(operation.op) {
|
* Example: '/jobs/1/status' -> ['1', 'status']
|
||||||
case "add":
|
|
||||||
if (pathArray.includes("results")) {break;}
|
|
||||||
this._add([operation.value]);
|
|
||||||
break;
|
|
||||||
case "remove":
|
|
||||||
this.remove("id", pathArray[0]);
|
|
||||||
break;
|
|
||||||
case "replace":
|
|
||||||
item = this.get("id", pathArray[0])[0];
|
|
||||||
switch(pathArray[1]) {
|
|
||||||
case "status":
|
|
||||||
item.values({status: operation.value,
|
|
||||||
"analyse-link": ["analysing", "prepared", "start analysis"].includes(operation.value) ? `/corpora/${pathArray[0]}/analyse` : ""});
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_add(values, callback) {
|
|
||||||
this.add(values.map(x => RessourceList.dataMappers[this.type](x)), callback);
|
|
||||||
// Initialize modal and tooltipped elements in list
|
|
||||||
M.AutoInit(this.listContainer);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RessourceList.dataMappers = {
|
|
||||||
// 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
|
|
||||||
// with the ValueNames defined below in RessourceList.options ValueNames.
|
|
||||||
// Links are declared with double ticks(") around them. The key for links
|
|
||||||
// have to correspond with the class of an <a> element in the
|
|
||||||
// RessourceList.options item blueprint.
|
|
||||||
|
|
||||||
/* ### Corpus mapper ### */
|
|
||||||
Corpus: corpus => ({
|
|
||||||
creation_date: corpus.creation_date,
|
|
||||||
description: corpus.description,
|
|
||||||
id: corpus.id,
|
|
||||||
link: `/corpora/${corpus.id}`,
|
|
||||||
status: corpus.status,
|
|
||||||
title: corpus.title,
|
|
||||||
title1: corpus.title,
|
|
||||||
"analyse-link": ["analysing", "prepared", "start analysis"].includes(corpus.status) ? `/corpora/${corpus.id}/analyse` : "",
|
|
||||||
"delete-link": `/corpora/${corpus.id}/delete`,
|
|
||||||
"delete-modal": `delete-corpus-${corpus.id}-modal`,
|
|
||||||
"delete-modal-trigger": `delete-corpus-${corpus.id}-modal`,
|
|
||||||
}),
|
|
||||||
/* ### CorpusFile mapper ### TODO: replace delete-modal with delete-onclick */
|
|
||||||
CorpusFile: corpus_file => ({
|
|
||||||
author: corpus_file.author,
|
|
||||||
filename: corpus_file.filename,
|
|
||||||
id: corpus_file.id,
|
|
||||||
link: `${corpus_file.corpus_id}/files/${corpus_file.id}`,
|
|
||||||
"publishing-year": corpus_file.publishing_year,
|
|
||||||
title: corpus_file.title,
|
|
||||||
title1: corpus_file.title,
|
|
||||||
"delete-link": `/corpora/${corpus_file.corpus_id}/files/${corpus_file.id}/delete`,
|
|
||||||
"delete-modal": `delete-corpus-file-${corpus_file.id}-modal`,
|
|
||||||
"delete-modal-trigger": `delete-corpus-file-${corpus_file.id}-modal`,
|
|
||||||
"download-link": `${corpus_file.corpus_id}/files/${corpus_file.id}/download`,
|
|
||||||
}),
|
|
||||||
/* ### Job mapper ### */
|
|
||||||
Job: job => ({
|
|
||||||
creation_date: job.creation_date,
|
|
||||||
description: job.description,
|
|
||||||
id: job.id,
|
|
||||||
link: `/jobs/${job.id}`,
|
|
||||||
service: job.service.name,
|
|
||||||
status: job.status,
|
|
||||||
title: job.title,
|
|
||||||
title1: job.title,
|
|
||||||
"delete-link": `/jobs/${job.id}/delete`,
|
|
||||||
"delete-modal": `delete-job-${job.id}-modal`,
|
|
||||||
"delete-modal-trigger": `delete-job-${job.id}-modal`,
|
|
||||||
}),
|
|
||||||
/* ### JobInput mapper ### */
|
|
||||||
JobInput: job_input => ({
|
|
||||||
filename: job_input.filename,
|
|
||||||
id: job_input.job_id,
|
|
||||||
"download-link": `${job_input.job_id}/inputs/${job_input.id}/download`
|
|
||||||
}),
|
|
||||||
/* ### QueryResult mapper ### */
|
|
||||||
QueryResult: query_result => ({
|
|
||||||
corpus_name: query_result.query_metadata.corpus_name,
|
|
||||||
description: query_result.description,
|
|
||||||
id: query_result.id,
|
|
||||||
link: `/corpora/result/${query_result.id}`,
|
|
||||||
query: query_result.query_metadata.query,
|
|
||||||
title: query_result.title,
|
|
||||||
"delete-link": `/corpora/result/${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": `/corpora/result/${query_result.id}/inspect`,
|
|
||||||
}),
|
|
||||||
/* ### User mapper ### */
|
|
||||||
User: user => ({
|
|
||||||
confirmed: user.confirmed,
|
|
||||||
email: user.email,
|
|
||||||
id: user.id,
|
|
||||||
link: `users/${user.id}`,
|
|
||||||
role: user.role.name,
|
|
||||||
username: user.username,
|
|
||||||
username2: user.username,
|
|
||||||
"delete-link": `/admin/users/${user.id}/delete`,
|
|
||||||
"delete-modal": `delete-user-${user.id}-modal`,
|
|
||||||
"delete-modal-trigger": `delete-user-${user.id}-modal`,
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
RessourceList.options = {
|
|
||||||
// common list.js options for 5 rows per page etc.
|
|
||||||
common: {page: 5, pagination: [{innerWindow: 4, outerWindow: 1}]},
|
|
||||||
// extended list.js options for 10 rows per page etc.
|
|
||||||
extended: {
|
|
||||||
page: 10,
|
|
||||||
pagination: [
|
|
||||||
{
|
|
||||||
name: "paginationTop",
|
|
||||||
paginationClass: "paginationTop",
|
|
||||||
innerWindow: 8,
|
|
||||||
outerWindow: 1
|
|
||||||
},
|
|
||||||
{
|
|
||||||
paginationClass: "paginationBottom",
|
|
||||||
innerWindow: 8,
|
|
||||||
outerWindow: 1,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
/* Type specific List.js options. Usually only "item" and "valueNames" gets
|
|
||||||
* defined here but it is possible to define other List.js options.
|
|
||||||
* item: https://listjs.com/api/#item
|
|
||||||
* valueNames: https://listjs.com/api/#valueNames
|
|
||||||
*/
|
*/
|
||||||
Corpus: {
|
let [id, valueName] = operation.path.split("/").slice(2);
|
||||||
|
switch(operation.op) {
|
||||||
|
case 'add':
|
||||||
|
this.add(operation.value);
|
||||||
|
break;
|
||||||
|
case 'remove':
|
||||||
|
this.remove(id);
|
||||||
|
break;
|
||||||
|
case 'replace':
|
||||||
|
this.replace(id, valueName, operation.value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
add(values) {
|
||||||
|
/* WORKAROUND: Set a callback function ('() => {return;}') to force List.js
|
||||||
|
perform the add method asynchronous.
|
||||||
|
* https://listjs.com/api/#add
|
||||||
|
*/
|
||||||
|
this.list.add(values, () => {return;});
|
||||||
|
}
|
||||||
|
|
||||||
|
remove(id) {
|
||||||
|
this.list.remove('id', id);
|
||||||
|
}
|
||||||
|
|
||||||
|
replace(id, valueName, newValue) {
|
||||||
|
if (!this.list.valuesNames.includes(valueName)) {return;}
|
||||||
|
let item = this.list.get('id', id);
|
||||||
|
item.values({[valueName]: newValue});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RessourceList.options = {page: 5, pagination: [{innerWindow: 4, outerWindow: 1}]};
|
||||||
|
|
||||||
|
|
||||||
|
class CorpusList extends RessourceList {
|
||||||
|
constructor(listElementId, options = {}) {
|
||||||
|
let listElement = document.querySelector(`#${listElementId}`);
|
||||||
|
super(listElement, {...CorpusList.options, ...options});
|
||||||
|
listElement.addEventListener('click', (event) => {
|
||||||
|
let actionButtonElement = event.target.closest('.action-button');
|
||||||
|
if (actionButtonElement === null) {return;}
|
||||||
|
let corpusId = event.target.closest('tr').dataset.id;
|
||||||
|
let action = actionButtonElement.dataset.action;
|
||||||
|
switch (action) {
|
||||||
|
case 'analyse':
|
||||||
|
window.location.href = nopaque.user.corpora[corpusId].analysis_url;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
nopaque.corporaSubscribers.push(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CorpusList.options = {
|
||||||
item: `<tr>
|
item: `<tr>
|
||||||
<td>
|
<td><a class="btn-floating disabled"><i class="material-icons">book</i></a></td>
|
||||||
<a class="btn-floating disabled">
|
<td><b class="title"></b><br><i class="description"></i></td>
|
||||||
<i class="material-icons service">book</i>
|
<td><span class="badge new status" data-badge-caption=""></span></td>
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<b class="title"></b><br>
|
|
||||||
<i class="description"></i>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="badge new status" data-badge-caption=""></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="Edit">
|
|
||||||
<i class="material-icons">edit</i>
|
|
||||||
</a>
|
|
||||||
<a class="btn-floating tooltipped waves-effect waves-light analyse-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 corpus deletion</h4>
|
|
||||||
<p>Do you really want to delete the corpus <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: [
|
|
||||||
"creation_date",
|
|
||||||
"description",
|
|
||||||
"title",
|
|
||||||
"title1",
|
|
||||||
{data: ["id"]},
|
|
||||||
{name: "analyse-link", attr: "href"},
|
|
||||||
{name: "delete-link", attr: "href"},
|
|
||||||
{name: "delete-modal-trigger", attr: "data-target"},
|
|
||||||
{name: "delete-modal", attr: "id"},
|
|
||||||
{name: "link", attr: "href"},
|
|
||||||
{name: "status", attr: "data-status"},
|
|
||||||
]
|
|
||||||
},
|
|
||||||
CorpusFile: {
|
|
||||||
item: `<tr>
|
|
||||||
<td class="filename" style="word-break: break-word;"></td>
|
|
||||||
<td class="author" style="word-break: break-word;"></td>
|
|
||||||
<td class="title" style="word-break: break-word;"></td>
|
|
||||||
<td class="publishing-year" style="word-break: break-word;"></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 download-link" data-position="top" data-tooltip="Download">
|
|
||||||
<i class="material-icons">file_download</i>
|
|
||||||
</a>
|
|
||||||
<a class="btn-floating tooltipped waves-effect waves-light link" data-position="top" data-tooltip="Edit">
|
|
||||||
<i class="material-icons">edit</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="modal delete-modal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<h4>Confirm corpus file deletion</h4>
|
|
||||||
<p>Do you really want to delete the corpus file <b class="title1"></b>? It 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: [
|
|
||||||
"author",
|
|
||||||
"filename",
|
|
||||||
"publishing-year",
|
|
||||||
"title",
|
|
||||||
"title1",
|
|
||||||
{data: ["id"]},
|
|
||||||
{name: "delete-link", attr: "href"},
|
|
||||||
{name: "delete-modal-trigger", attr: "data-target"},
|
|
||||||
{name: "delete-modal", attr: "id"},
|
|
||||||
{name: "download-link", attr: "href"},
|
|
||||||
{name: "link", attr: "href"},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
Job: {
|
|
||||||
item: `<tr>
|
|
||||||
<td>
|
|
||||||
<a class="btn-floating disabled">
|
|
||||||
<i class="material-icons service"></i>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<b class="title"></b><br>
|
|
||||||
<i class="description"></i>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span class="badge new status" data-badge-caption=""></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="Go to job">
|
|
||||||
<i class="material-icons">send</i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div class="modal delete-modal">
|
|
||||||
<div class="modal-content">
|
|
||||||
<h4>Confirm job 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: [
|
|
||||||
"creation_date",
|
|
||||||
"description",
|
|
||||||
"title",
|
|
||||||
"title1",
|
|
||||||
{data: ["id"]},
|
|
||||||
{name: "delete-link", attr: "href"},
|
|
||||||
{name: "delete-modal-trigger", attr: "data-target"},
|
|
||||||
{name: "delete-modal", attr: "id"},
|
|
||||||
{name: "link", attr: "href"},
|
|
||||||
{name: "service", attr: "data-service"},
|
|
||||||
{name: "status", attr: "data-status"},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
JobInput: {
|
|
||||||
item : `<tr>
|
|
||||||
<td class="filename"></td>
|
|
||||||
<td class="right-align">
|
<td class="right-align">
|
||||||
<a class="btn-floating tooltipped waves-effect waves-light download-link" data-position="top" data-tooltip="Download">
|
<a class="action-button btn-floating red tooltipped waves-effect waves-light" data-action="delete" data-position="top" data-tooltip="Delete"><i class="material-icons">delete</i></a>
|
||||||
<i class="material-icons">file_download</i>
|
<a class="action-button btn-floating tooltipped waves-effect waves-light" data-action="edit" data-position="top" data-tooltip="Edit"><i class="material-icons">edit</i></a>
|
||||||
</a>
|
<a class="action-button btn-floating tooltipped waves-effect waves-light" data-action="analyse" data-position="top" data-tooltip="Analyse"><i class="material-icons">search</i></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>`,
|
</tr>`,
|
||||||
valueNames: [
|
valueNames: [{data: ['id']}, {name: "status", attr: "data-status"}, 'description', 'title']
|
||||||
"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="id"></td>
|
|
||||||
<td class="username"></td>
|
|
||||||
<td class="email"></td>
|
|
||||||
<td class="role"></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",
|
|
||||||
{name: "link", attr: "href"},
|
|
||||||
{name: "delete-link", attr: "href"},
|
|
||||||
{name: "delete-modal-trigger", attr: "data-target"},
|
|
||||||
{name: "delete-modal", attr: "id"},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { RessourceList, };
|
|
||||||
|
class JobList extends RessourceList {
|
||||||
|
constructor(listElementId, options = {}) {
|
||||||
|
let listElement = document.querySelector(`#${listElementId}`);
|
||||||
|
super(listElement, {...JobList.options, ...options});
|
||||||
|
nopaque.jobsSubscribers.push(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JobList.options = {
|
||||||
|
item: `<tr>
|
||||||
|
<td><a class="btn-floating disabled"><i class="material-icons service"></i></a></td>
|
||||||
|
<td><b class="title"></b><br><i class="description"></i></td>
|
||||||
|
<td><span class="badge new status" data-badge-caption=""></span></td>
|
||||||
|
<td class="right-align">
|
||||||
|
<a class="action-button btn-floating red tooltipped waves-effect waves-light" data-action="delete" data-position="top" data-tooltip="Delete"><i class="material-icons">delete</i></a>
|
||||||
|
<a class="action-button btn-floating tooltipped waves-effect waves-light" data-action="view" data-position="top" data-tooltip="View"><i class="material-icons">send</i></a>
|
||||||
|
</td>
|
||||||
|
</tr>`,
|
||||||
|
valueNames: [{data: ['id']}, {name: 'service', attr: 'data-service'}, {name: "status", attr: "data-status"}, 'description', 'title']
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class QueryResultList extends RessourceList {
|
||||||
|
constructor(listElementId, options = {}) {
|
||||||
|
let listElement = document.querySelector(`#${listElementId}`);
|
||||||
|
super(listElement, {...QueryResultList.options, ...options});
|
||||||
|
nopaque.queryResultsSubscribers.push(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QueryResultList.options = {
|
||||||
|
item: `<tr>
|
||||||
|
<td><b class="title"></b><br><i class="description"></i><br></td>
|
||||||
|
<td><span class="corpus_title"></span><br><span class="query"></span></td>
|
||||||
|
<td class="right-align">
|
||||||
|
<a class="action-button btn-floating red tooltipped waves-effect waves-light" data-action="delete" data-position="top" data-tooltip="Delete"><i class="material-icons">delete</i></a>
|
||||||
|
<a class="action-button btn-floating tooltipped waves-effect waves-light" data-action="view" data-position="top" data-tooltip="View"><i class="material-icons">send</i></a>
|
||||||
|
<a class="action-button btn-floating tooltipped waves-effect waves-light" data-action="analyse" data-position="top" data-tooltip="Analyse"><i class="material-icons">search</i></a>
|
||||||
|
</td>
|
||||||
|
</tr>`,
|
||||||
|
valueNames: [{data: ['id']}, 'corpus_title', 'description', 'query', 'title']
|
||||||
|
};
|
||||||
|
|
||||||
|
export { CorpusList, JobList, QueryResultList };
|
||||||
|
420
web/app/static/js/nopaque.lists.js.bak
Normal file
420
web/app/static/js/nopaque.lists.js.bak
Normal file
@ -0,0 +1,420 @@
|
|||||||
|
class RessourceList extends List {
|
||||||
|
constructor(idOrElement, subscriberList, type, options) {
|
||||||
|
if (!type || !["Corpus", "CorpusFile", "Job", "JobInput", "QueryResult", "User"].includes(type)) {
|
||||||
|
throw "Unknown Type!";
|
||||||
|
}
|
||||||
|
super(idOrElement, {...RessourceList.options['common'],
|
||||||
|
...RessourceList.options[type],
|
||||||
|
...(options ? options : {})});
|
||||||
|
if (subscriberList) {subscriberList.push(this);}
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_init(ressources) {
|
||||||
|
this.clear();
|
||||||
|
this._add(Object.values(ressources));
|
||||||
|
this.sort("id", {order: "desc"});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_update(patch) {
|
||||||
|
let item, pathArray;
|
||||||
|
|
||||||
|
for (let operation of patch) {
|
||||||
|
/* "/{ressourceName}/{ressourceId}/..." -> ["{ressourceId}", "..."] */
|
||||||
|
pathArray = operation.path.split("/").slice(2);
|
||||||
|
switch(operation.op) {
|
||||||
|
case "add":
|
||||||
|
if (pathArray.includes("results")) {break;}
|
||||||
|
this._add([operation.value]);
|
||||||
|
break;
|
||||||
|
case "remove":
|
||||||
|
this.remove("id", pathArray[0]);
|
||||||
|
break;
|
||||||
|
case "replace":
|
||||||
|
item = this.get("id", pathArray[0])[0];
|
||||||
|
switch(pathArray[1]) {
|
||||||
|
case "status":
|
||||||
|
item.values({status: operation.value,
|
||||||
|
"analyse-link": ["analysing", "prepared", "start analysis"].includes(operation.value) ? `/corpora/${pathArray[0]}/analyse` : ""});
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_add(values, callback) {
|
||||||
|
this.add(values.map(x => RessourceList.dataMappers[this.type](x)), callback);
|
||||||
|
// Initialize modal and tooltipped elements in list
|
||||||
|
M.AutoInit(this.listContainer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
RessourceList.dataMappers = {
|
||||||
|
// 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
|
||||||
|
// with the ValueNames defined below in RessourceList.options ValueNames.
|
||||||
|
// Links are declared with double ticks(") around them. The key for links
|
||||||
|
// have to correspond with the class of an <a> element in the
|
||||||
|
// RessourceList.options item blueprint.
|
||||||
|
|
||||||
|
/* ### Corpus mapper ### */
|
||||||
|
Corpus: corpus => ({
|
||||||
|
creation_date: corpus.creation_date,
|
||||||
|
description: corpus.description,
|
||||||
|
id: corpus.id,
|
||||||
|
link: `/corpora/${corpus.id}`,
|
||||||
|
status: corpus.status,
|
||||||
|
title: corpus.title,
|
||||||
|
title1: corpus.title,
|
||||||
|
"analyse-link": ["analysing", "prepared", "start analysis"].includes(corpus.status) ? `/corpora/${corpus.id}/analyse` : "",
|
||||||
|
"delete-link": `/corpora/${corpus.id}/delete`,
|
||||||
|
"delete-modal": `delete-corpus-${corpus.id}-modal`,
|
||||||
|
"delete-modal-trigger": `delete-corpus-${corpus.id}-modal`,
|
||||||
|
}),
|
||||||
|
/* ### CorpusFile mapper ### TODO: replace delete-modal with delete-onclick */
|
||||||
|
CorpusFile: corpus_file => ({
|
||||||
|
author: corpus_file.author,
|
||||||
|
filename: corpus_file.filename,
|
||||||
|
id: corpus_file.id,
|
||||||
|
link: `${corpus_file.corpus_id}/files/${corpus_file.id}`,
|
||||||
|
"publishing-year": corpus_file.publishing_year,
|
||||||
|
title: corpus_file.title,
|
||||||
|
title1: corpus_file.title,
|
||||||
|
"delete-link": `/corpora/${corpus_file.corpus_id}/files/${corpus_file.id}/delete`,
|
||||||
|
"delete-modal": `delete-corpus-file-${corpus_file.id}-modal`,
|
||||||
|
"delete-modal-trigger": `delete-corpus-file-${corpus_file.id}-modal`,
|
||||||
|
"download-link": `${corpus_file.corpus_id}/files/${corpus_file.id}/download`,
|
||||||
|
}),
|
||||||
|
/* ### Job mapper ### */
|
||||||
|
Job: job => ({
|
||||||
|
creation_date: job.creation_date,
|
||||||
|
description: job.description,
|
||||||
|
id: job.id,
|
||||||
|
link: `/jobs/${job.id}`,
|
||||||
|
service: job.service.name,
|
||||||
|
status: job.status,
|
||||||
|
title: job.title,
|
||||||
|
title1: job.title,
|
||||||
|
"delete-link": `/jobs/${job.id}/delete`,
|
||||||
|
"delete-modal": `delete-job-${job.id}-modal`,
|
||||||
|
"delete-modal-trigger": `delete-job-${job.id}-modal`,
|
||||||
|
}),
|
||||||
|
/* ### JobInput mapper ### */
|
||||||
|
JobInput: job_input => ({
|
||||||
|
filename: job_input.filename,
|
||||||
|
id: job_input.job_id,
|
||||||
|
"download-link": `${job_input.job_id}/inputs/${job_input.id}/download`
|
||||||
|
}),
|
||||||
|
/* ### QueryResult mapper ### */
|
||||||
|
QueryResult: query_result => ({
|
||||||
|
corpus_name: query_result.query_metadata.corpus_name,
|
||||||
|
description: query_result.description,
|
||||||
|
id: query_result.id,
|
||||||
|
link: `/corpora/result/${query_result.id}`,
|
||||||
|
query: query_result.query_metadata.query,
|
||||||
|
title: query_result.title,
|
||||||
|
"delete-link": `/corpora/result/${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": `/corpora/result/${query_result.id}/inspect`,
|
||||||
|
}),
|
||||||
|
/* ### User mapper ### */
|
||||||
|
User: user => ({
|
||||||
|
confirmed: user.confirmed,
|
||||||
|
email: user.email,
|
||||||
|
id: user.id,
|
||||||
|
link: `users/${user.id}`,
|
||||||
|
role: user.role.name,
|
||||||
|
username: user.username,
|
||||||
|
username2: user.username,
|
||||||
|
"delete-link": `/admin/users/${user.id}/delete`,
|
||||||
|
"delete-modal": `delete-user-${user.id}-modal`,
|
||||||
|
"delete-modal-trigger": `delete-user-${user.id}-modal`,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
RessourceList.options = {
|
||||||
|
// common list.js options for 5 rows per page etc.
|
||||||
|
common: {page: 5, pagination: [{innerWindow: 4, outerWindow: 1}]},
|
||||||
|
// extended list.js options for 10 rows per page etc.
|
||||||
|
extended: {
|
||||||
|
page: 10,
|
||||||
|
pagination: [
|
||||||
|
{
|
||||||
|
name: "paginationTop",
|
||||||
|
paginationClass: "paginationTop",
|
||||||
|
innerWindow: 8,
|
||||||
|
outerWindow: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
paginationClass: "paginationBottom",
|
||||||
|
innerWindow: 8,
|
||||||
|
outerWindow: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
/* Type specific List.js options. Usually only "item" and "valueNames" gets
|
||||||
|
* defined here but it is possible to define other List.js options.
|
||||||
|
* item: https://listjs.com/api/#item
|
||||||
|
* valueNames: https://listjs.com/api/#valueNames
|
||||||
|
*/
|
||||||
|
Corpus: {
|
||||||
|
item: `<tr>
|
||||||
|
<td>
|
||||||
|
<a class="btn-floating disabled">
|
||||||
|
<i class="material-icons service">book</i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b class="title"></b><br>
|
||||||
|
<i class="description"></i>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge new status" data-badge-caption=""></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="Edit">
|
||||||
|
<i class="material-icons">edit</i>
|
||||||
|
</a>
|
||||||
|
<a class="btn-floating tooltipped waves-effect waves-light analyse-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 corpus deletion</h4>
|
||||||
|
<p>Do you really want to delete the corpus <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: [
|
||||||
|
"creation_date",
|
||||||
|
"description",
|
||||||
|
"title",
|
||||||
|
"title1",
|
||||||
|
{data: ["id"]},
|
||||||
|
{name: "analyse-link", attr: "href"},
|
||||||
|
{name: "delete-link", attr: "href"},
|
||||||
|
{name: "delete-modal-trigger", attr: "data-target"},
|
||||||
|
{name: "delete-modal", attr: "id"},
|
||||||
|
{name: "link", attr: "href"},
|
||||||
|
{name: "status", attr: "data-status"},
|
||||||
|
]
|
||||||
|
},
|
||||||
|
CorpusFile: {
|
||||||
|
item: `<tr>
|
||||||
|
<td class="filename" style="word-break: break-word;"></td>
|
||||||
|
<td class="author" style="word-break: break-word;"></td>
|
||||||
|
<td class="title" style="word-break: break-word;"></td>
|
||||||
|
<td class="publishing-year" style="word-break: break-word;"></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 download-link" data-position="top" data-tooltip="Download">
|
||||||
|
<i class="material-icons">file_download</i>
|
||||||
|
</a>
|
||||||
|
<a class="btn-floating tooltipped waves-effect waves-light link" data-position="top" data-tooltip="Edit">
|
||||||
|
<i class="material-icons">edit</i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="modal delete-modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h4>Confirm corpus file deletion</h4>
|
||||||
|
<p>Do you really want to delete the corpus file <b class="title1"></b>? It 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: [
|
||||||
|
"author",
|
||||||
|
"filename",
|
||||||
|
"publishing-year",
|
||||||
|
"title",
|
||||||
|
"title1",
|
||||||
|
{data: ["id"]},
|
||||||
|
{name: "delete-link", attr: "href"},
|
||||||
|
{name: "delete-modal-trigger", attr: "data-target"},
|
||||||
|
{name: "delete-modal", attr: "id"},
|
||||||
|
{name: "download-link", attr: "href"},
|
||||||
|
{name: "link", attr: "href"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
Job: {
|
||||||
|
item: `<tr>
|
||||||
|
<td>
|
||||||
|
<a class="btn-floating disabled">
|
||||||
|
<i class="material-icons service"></i>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<b class="title"></b><br>
|
||||||
|
<i class="description"></i>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<span class="badge new status" data-badge-caption=""></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="Go to job">
|
||||||
|
<i class="material-icons">send</i>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="modal delete-modal">
|
||||||
|
<div class="modal-content">
|
||||||
|
<h4>Confirm job 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: [
|
||||||
|
"creation_date",
|
||||||
|
"description",
|
||||||
|
"title",
|
||||||
|
"title1",
|
||||||
|
{data: ["id"]},
|
||||||
|
{name: "delete-link", attr: "href"},
|
||||||
|
{name: "delete-modal-trigger", attr: "data-target"},
|
||||||
|
{name: "delete-modal", attr: "id"},
|
||||||
|
{name: "link", attr: "href"},
|
||||||
|
{name: "service", attr: "data-service"},
|
||||||
|
{name: "status", attr: "data-status"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
JobInput: {
|
||||||
|
item : `<tr>
|
||||||
|
<td class="filename"></td>
|
||||||
|
<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="id"></td>
|
||||||
|
<td class="username"></td>
|
||||||
|
<td class="email"></td>
|
||||||
|
<td class="role"></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",
|
||||||
|
{name: "link", attr: "href"},
|
||||||
|
{name: "delete-link", attr: "href"},
|
||||||
|
{name: "delete-modal-trigger", attr: "data-target"},
|
||||||
|
{name: "delete-modal", attr: "id"},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export { RessourceList, };
|
@ -1,33 +1,33 @@
|
|||||||
class RessourceList extends List {
|
class RessourceList {
|
||||||
constructor(idOrElement, options) {
|
constructor(idOrElement, options = {}) {
|
||||||
super(idOrElement, {...RessourceList.options['default'], ...(options ? options : {})});
|
this.list = new List(idOrElement, {...RessourceList.options, ...options});
|
||||||
}
|
}
|
||||||
|
|
||||||
_init(ressources) {
|
init(ressources) {
|
||||||
this.clear();
|
this.list.clear();
|
||||||
this._add(Object.values(ressources));
|
this.add(Object.values(ressources));
|
||||||
this.sort("id", {order: "desc"});
|
this.list.sort('id', {order: 'desc'});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_update(patch) {
|
update(patch) {
|
||||||
let item, pathArray;
|
let item, pathArray;
|
||||||
|
|
||||||
for (let operation of patch) {
|
for (let operation of patch) {
|
||||||
/*
|
/*
|
||||||
* '/{ressourceName}/{ressourceId}/...' -> ['{ressourceId}', ...]
|
* '/{ressourceName}/{ressourceId}/{valueName}' -> ['{ressourceId}', {valueName}]
|
||||||
* Example: '/jobs/1/status' -> ['1', 'status']
|
* Example: '/jobs/1/status' -> ['1', 'status']
|
||||||
*/
|
*/
|
||||||
pathArray = operation.path.split("/").slice(2);
|
let [id, valueName] = operation.path.split("/").slice(2);
|
||||||
switch(operation.op) {
|
switch(operation.op) {
|
||||||
case "add":
|
case 'add':
|
||||||
this.add_handler([operation.value]);
|
this.add(operation.value);
|
||||||
break;
|
break;
|
||||||
case "remove":
|
case 'remove':
|
||||||
this.remove_handler(pathArray[0]);
|
this.remove(id);
|
||||||
break;
|
break;
|
||||||
case "replace":
|
case 'replace':
|
||||||
this.replace_handler(pathArray[0], pathArray[1], operation.value);
|
this.replace(id, valueName, operation.value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -35,34 +35,93 @@ class RessourceList extends List {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
add_handler(values, callback) {
|
add(values) {
|
||||||
if (this.hasOwnProperty('add_')) {
|
/* WORKAROUND: Set a callback function ('() => {return;}') to force List.js
|
||||||
this.add_(values, callback);
|
perform the add method asynchronous.
|
||||||
} else {
|
* https://listjs.com/api/#add
|
||||||
this.add(values, callback);
|
*/
|
||||||
}
|
this.list.add(values, () => {return;});
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_handler(id) {
|
remove(id) {
|
||||||
if (this.hasOwnProperty('remove_')) {
|
this.list.remove('id', id);
|
||||||
this.remove_(id);
|
|
||||||
} else {
|
|
||||||
this.remove(id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
replace_handler(id, valueName, newValue) {
|
replace(id, valueName, newValue) {
|
||||||
let item = this.get('id', id);
|
if (!this.list.valuesNames.includes(valueName)) {return;}
|
||||||
if (this.hasOwnProperty('add_'))
|
let item = this.list.get('id', id);
|
||||||
item.values({valueName: operation.value});
|
item.values({[valueName]: newValue});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
RessourceList.options = {
|
RessourceList.options = {page: 5, pagination: [{innerWindow: 4, outerWindow: 1}]};
|
||||||
// default RessourceList options
|
|
||||||
default: {page: 5, pagination: [{innerWindow: 4, outerWindow: 1}]},
|
|
||||||
|
class CorpusList extends RessourceList {
|
||||||
|
constructor(idOrElement, options = {}) {
|
||||||
|
super(idOrElement, {...CorpusList.options, ...options});
|
||||||
|
nopaque.corporaSubscribers.push(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CorpusList.options = {
|
||||||
|
item: `<tr>
|
||||||
|
<td><a class="btn-floating disabled"><i class="material-icons">book</i></a></td>
|
||||||
|
<td><b class="title"></b><br><i class="description"></i></td>
|
||||||
|
<td><span class="badge new status" data-badge-caption=""></span></td>
|
||||||
|
<td class="right-align">
|
||||||
|
<a class="btn-floating delete red tooltipped waves-effect waves-light" data-position="top" data-tooltip="Delete"><i class="material-icons">delete</i></a>
|
||||||
|
<a class="btn-floating edit tooltipped waves-effect waves-light" data-position="top" data-tooltip="Edit"><i class="material-icons">edit</i></a>
|
||||||
|
<a class="analyse btn-floating tooltipped waves-effect waves-light" data-position="top" data-tooltip="Analyse"><i class="material-icons">search</i></a>
|
||||||
|
</td>
|
||||||
|
</tr>`,
|
||||||
|
valueNames: [{data: ['id']}, 'description', 'status', 'title']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
export { RessourceList, };
|
class JobList extends RessourceList {
|
||||||
|
constructor(idOrElement, options = {}) {
|
||||||
|
super(idOrElement, {...JobList.options, ...options});
|
||||||
|
nopaque.jobsSubscribers.push(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
JobList.options = {
|
||||||
|
item: `<tr>
|
||||||
|
<td><a class="btn-floating disabled"><i class="material-icons service"></i></a></td>
|
||||||
|
<td><b class="title"></b><br><i class="description"></i></td>
|
||||||
|
<td><span class="badge new status" data-badge-caption=""></span></td>
|
||||||
|
<td class="right-align">
|
||||||
|
<a class="btn-floating delete red tooltipped waves-effect waves-light" data-position="top" data-tooltip="Delete"><i class="material-icons">delete</i></a>
|
||||||
|
<a class="btn-floating tooltipped view waves-effect waves-light" data-position="top" data-tooltip="View"><i class="material-icons">send</i></a>
|
||||||
|
</td>
|
||||||
|
</tr>`,
|
||||||
|
valueNames: [{data: ['id']}, {name: 'service', attr: 'data-service'}, 'description', 'status', 'title']
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class QueryResultList extends RessourceList {
|
||||||
|
constructor(idOrElement, options = {}) {
|
||||||
|
super(idOrElement, {...QueryResultList.options, ...options});
|
||||||
|
nopaque.queryResultsSubscribers.push(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QueryResultList.options = {
|
||||||
|
item: `<tr>
|
||||||
|
<td><b class="title"></b><br><i class="description"></i><br></td>
|
||||||
|
<td><span class="corpus_title"></span><br><span class="query"></span></td>
|
||||||
|
<td class="right-align">
|
||||||
|
<a class="btn-floating delete red tooltipped waves-effect waves-light" data-position="top" data-tooltip="Delete"><i class="material-icons">delete</i></a>
|
||||||
|
<a class="btn-floating tooltipped view waves-effect waves-light" data-position="top" data-tooltip="View"><i class="material-icons">send</i></a>
|
||||||
|
<a class="analyse btn-floating tooltipped waves-effect waves-light" data-position="top" data-tooltip="Analyse"><i class="material-icons">search</i></a>
|
||||||
|
</td>
|
||||||
|
</tr>`,
|
||||||
|
valueNames: [{data: ['id']}, 'corpus_title', 'description', 'query', 'title']
|
||||||
|
};
|
||||||
|
|
||||||
|
export { CorpusList, JobList, QueryResultList };
|
||||||
|
@ -176,9 +176,9 @@
|
|||||||
{% block scripts %}
|
{% block scripts %}
|
||||||
{{ super() }}
|
{{ super() }}
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import {RessourceList} from '../../static/js/nopaque.lists.js';
|
import {CorpusList, JobList, QueryResultList} from '../../static/js/nopaque.lists.js';
|
||||||
let corpusList = new RessourceList("corpora", nopaque.corporaSubscribers, "Corpus");
|
let corpusList = new CorpusList("corpora");
|
||||||
let jobList = new RessourceList("jobs", nopaque.jobsSubscribers, "Job");
|
let jobList = new JobList("jobs");
|
||||||
let queryResultList = new RessourceList("query-results", nopaque.queryResultsSubscribers, "QueryResult");
|
let queryResultList = new QueryResultList("query-results");
|
||||||
</script>
|
</script>
|
||||||
{% endblock scripts %}
|
{% endblock scripts %}
|
||||||
|
Loading…
Reference in New Issue
Block a user