Unify job input tables

This commit is contained in:
Stephan Porada 2020-07-08 11:35:47 +02:00
parent 0fff7801fd
commit 43f79291aa
4 changed files with 82 additions and 63 deletions

View File

@ -1,28 +0,0 @@
from flask_table import Table, Col, LinkCol
class JobInputTable(Table):
"""
Declares the table describing colum by column.
"""
classes = ['highlight', 'responsive-table']
filename = Col('Filename', column_html_attrs={'class': 'filename'},
th_html_attrs={'class': 'sort',
'data-sort': 'filename'})
url = LinkCol('Download', 'jobs.download_job_input',
url_kwargs=dict(job_id='job.id',
job_input_id='input_id'),
anchor_attrs={'class': 'waves-effect waves-light btn-floating',
'download': ''},
text_fallback='<i class="material-icons">file_download</i>')
class JobInputItem(object):
"""
Describes one item like one row per table.
"""
def __init__(self, filename, job, input_id):
self.filename = filename
self.job = job
self.input_id = input_id

View File

@ -3,10 +3,8 @@ from flask import (abort, current_app, flash, redirect, render_template,
from flask_login import current_user, login_required from flask_login import current_user, login_required
from . import jobs from . import jobs
from . import tasks from . import tasks
from . tables import JobInputItem, JobInputTable
from ..models import Job, JobInput, JobResult from ..models import Job, JobInput, JobResult
import os import os
import html
@jobs.route('/<int:job_id>') @jobs.route('/<int:job_id>')
@ -15,15 +13,13 @@ def job(job_id):
job = Job.query.get_or_404(job_id) job = Job.query.get_or_404(job_id)
if not (job.creator == current_user or current_user.is_administrator()): if not (job.creator == current_user or current_user.is_administrator()):
abort(403) abort(403)
items = [JobInputItem(input.filename, job, input.id) job_inputs = [dict(filename=input.filename,
id=input.id,
job_id=job.id)
for input in job.inputs] for input in job.inputs]
# Convert table object to html string and unescape <>& for al little hack to use icons in buttons
job_input_table = html.unescape(JobInputTable(items).__html__())
# Add class "list" to tbody element. Needed for "List.js"
job_input_table = job_input_table.replace('tbody', 'tbody class="list"', 1)
return render_template('jobs/job.html.j2', return render_template('jobs/job.html.j2',
job=job, job=job,
job_input_table=job_input_table, job_inputs=job_inputs,
title='Job') title='Job')

View File

@ -1,6 +1,6 @@
class RessourceList extends List { class RessourceList extends List {
constructor(idOrElement, subscriberList, type, options={}) { constructor(idOrElement, subscriberList, type, options={}) {
if (!["corpus", "job", "result", "user"].includes(type)) { if (!["corpus", "job", "result", "user", "job_input"].includes(type)) {
console.error("Unknown Type!"); console.error("Unknown Type!");
return; return;
} }
@ -63,6 +63,15 @@ class RessourceList extends List {
RessourceList.dataMapper = { RessourceList.dataMapper = {
// ### Mapping Genera Info
//The Mapping 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.
// Mapping for corpus entities shown in the dashboard table.
corpus: corpus => ({creation_date: corpus.creation_date, corpus: corpus => ({creation_date: corpus.creation_date,
description: corpus.description, description: corpus.description,
id: corpus.id, id: corpus.id,
@ -70,6 +79,7 @@ RessourceList.dataMapper = {
"edit-link": `/corpora/${corpus.id}`, "edit-link": `/corpora/${corpus.id}`,
status: corpus.status, status: corpus.status,
title: corpus.title}), title: corpus.title}),
// Mapping for job entities shown in the dashboard table.
job: job => ({creation_date: job.creation_date, job: job => ({creation_date: job.creation_date,
description: job.description, description: job.description,
id: job.id, id: job.id,
@ -77,6 +87,12 @@ RessourceList.dataMapper = {
service: job.service, service: job.service,
status: job.status, status: job.status,
title: job.title}), title: job.title}),
// Mapping for job input files shown in table on every job page
job_input: job_input => ({filename: job_input.filename,
id: job_input.job_id,
"download-link": `${job_input.job_id}/inputs/${job_input.id}/download`}),
// Mapping for imported result entities from corpus analysis.
// Shown in imported results table
result: result => ({ query: result.query, result: result => ({ query: result.query,
match_count: result.match_count, match_count: result.match_count,
corpus_name: result.corpus_name, corpus_name: result.corpus_name,
@ -86,6 +102,7 @@ RessourceList.dataMapper = {
"details-link": `${result.id}/details`, "details-link": `${result.id}/details`,
"inspect-link": `${result.id}/inspect`, "inspect-link": `${result.id}/inspect`,
"delete-modal": `delete-result-${result.id}-modal`}), "delete-modal": `delete-result-${result.id}-modal`}),
// Mapping for user entities shown in admin table
user: user => ({username: user.username, user: user => ({username: user.username,
email: user.email, email: user.email,
role_id: user.role_id, role_id: user.role_id,
@ -96,7 +113,9 @@ RessourceList.dataMapper = {
RessourceList.options = { RessourceList.options = {
// 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: {page: 10, extended: {page: 10,
pagination: [ pagination: [
{ {
@ -111,6 +130,8 @@ RessourceList.options = {
outerWindow: 1 outerWindow: 1
} }
]}, ]},
// Corpus entity blueprint setting html strucuture per entity per row
// Link classes have to correspond with Links defined in the Mapping process
corpus: {item: `<tr> corpus: {item: `<tr>
<td> <td>
<a class="btn-floating disabled"> <a class="btn-floating disabled">
@ -134,11 +155,18 @@ RessourceList.options = {
</a> </a>
</td> </td>
</tr>`, </tr>`,
valueNames: ["creation_date", "description", "title", // Corpus Value Names per column. Have to correspond with the keys from the
// Mapping step above.
valueNames: ["creation_date",
"description",
"title",
{data: ["id"]}, {data: ["id"]},
{name: "analyse-link", attr: "href"}, {name: "analyse-link", attr: "href"},
{name: "edit-link", attr: "href"}, {name: "edit-link", attr: "href"},
{name: "status", attr: "data-status"}]}, {name: "status", attr: "data-status"}]
},
// Job entity blueprint setting html strucuture per entity per row
// Link classes have to correspond with Links defined in the Mapping process
job: {item: `<tr> job: {item: `<tr>
<td> <td>
<a class="btn-floating disabled"> <a class="btn-floating disabled">
@ -158,11 +186,30 @@ RessourceList.options = {
</a> </a>
</td> </td>
</tr>`, </tr>`,
valueNames: ["creation_date", "description", "title", // Job Value Names per column. Have to correspond with the keys from the
// Mapping step above.
valueNames: ["creation_date",
"description",
"title",
{data: ["id"]}, {data: ["id"]},
{name: "link", attr: "href"}, {name: "link", attr: "href"},
{name: "service", attr: "data-service"}, {name: "service", attr: "data-service"},
{name: "status", attr: "data-status"}]}, {name: "status", attr: "data-status"}]
},
job_input: {item : `<tr>
<td class="filename"></td>
<td class="actions">
<a class="btn-floating download-link waves-effect waves-light"><i class="material-icons">file_download</i>
</a>
</td>
</tr>`,
valueNames: ["filename",
"id",
{name: "download-link", attr: "href"}]
},
// Result (imported from corpus analysis) entity blueprint setting html
// strucuture per entity per row
// Link classes have to correspond with Links defined in the Mapping process
result: {item: `<tr> result: {item: `<tr>
<td class="query"></td> <td class="query"></td>
<td class="match_count"></td> <td class="match_count"></td>
@ -179,6 +226,8 @@ RessourceList.options = {
</a> </a>
</td> </td>
</tr>`, </tr>`,
// Result Value Names per column. Have to correspond with keys from the
// Mapping step above.
valueNames: ["query", valueNames: ["query",
"match_count", "match_count",
"corpus_name", "corpus_name",
@ -187,7 +236,10 @@ RessourceList.options = {
"corpus_type", "corpus_type",
{name: "details-link", attr: "href"}, {name: "details-link", attr: "href"},
{name: "inspect-link", attr: "href"}, {name: "inspect-link", attr: "href"},
{name: "delete-modal", attr: "data-target"}]}, {name: "delete-modal", attr: "data-target"}]
},
// User entity blueprint setting html strucuture per entity per row
// Link classes have to correspond with Links defined in the Mapping process
user: {item: `<tr> user: {item: `<tr>
<td class="username"></td> <td class="username"></td>
<td class="email"></td> <td class="email"></td>
@ -199,12 +251,15 @@ RessourceList.options = {
</a> </a>
</td> </td>
</tr>`, </tr>`,
// User Value Names per column. Have to correspond with keys from the
// Mapping step above.
valueNames: ["username", valueNames: ["username",
"email", "email",
"role_id", "role_id",
"confirmed", "confirmed",
"id", "id",
{name: "profile-link", attr: "href"}]} {name: "profile-link", attr: "href"}]
}
}; };

View File

@ -86,9 +86,18 @@
<p>Original input files.</p> <p>Original input files.</p>
</div> </div>
<div class="col s12 m10"> <div class="col s12 m10">
<div class="inputs row"> <div class="row">
<ul class="pagination paginationTop"></ul> <ul class="pagination paginationTop"></ul>
{{ job_input_table }} <table class="highlight responsive-table">
<thead>
<tr>
<th class="sort" data-sort="filename">Filename</th>
<th>{# Actions #}</th>
</tr>
</thead>
<tbody class="list">
</tbody>
</table>
<ul class="pagination paginationBottom"></ul> <ul class="pagination paginationBottom"></ul>
</div> </div>
</div> </div>
@ -149,23 +158,10 @@
<script> <script>
// job_input_table code // job_input_table code
var options = {page: 5, var ressources = {{ job_inputs|tojson|safe }};
pagination: [ console.log(ressources);
{ var jobInputsList = new RessourceList("inputs", null, "job_input");
name: "paginationTop", jobInputsList.addRessources(ressources);
paginationClass: "paginationTop",
innerWindow: 8,
outerWindow: 1
},
{
paginationClass: "paginationBottom",
innerWindow: 8,
outerWindow: 1
}
],
valueNames: ['filename']};
var jobInputList = new List('inputs', options);
class InformationUpdater { class InformationUpdater {
constructor(jobId, foreignJobFlag) { constructor(jobId, foreignJobFlag) {