mirror of
https://gitlab.ub.uni-bielefeld.de/sfb1288inf/nopaque.git
synced 2024-12-26 03:14:19 +00:00
Job output list implementation
This commit is contained in:
parent
82d6f6003f
commit
71c0ddf515
@ -6,6 +6,7 @@ from app import db, hashids
|
|||||||
from app.models import (
|
from app.models import (
|
||||||
Job,
|
Job,
|
||||||
JobInput,
|
JobInput,
|
||||||
|
JobResult,
|
||||||
JobStatus,
|
JobStatus,
|
||||||
TesseractOCRPipelineModel,
|
TesseractOCRPipelineModel,
|
||||||
SpaCyNLPPipelineModel
|
SpaCyNLPPipelineModel
|
||||||
@ -74,6 +75,8 @@ def tesseract_ocr_pipeline():
|
|||||||
version = request.args.get('version', service_manifest['latest_version'])
|
version = request.args.get('version', service_manifest['latest_version'])
|
||||||
if version not in service_manifest['versions']:
|
if version not in service_manifest['versions']:
|
||||||
abort(404)
|
abort(404)
|
||||||
|
job_results = JobResult.query.all()
|
||||||
|
choosable_job_ids = [job_result.job.hashid for job_result in job_results if job_result.job.service == "file-setup-pipeline" and job_result.filename.endswith('.pdf')]
|
||||||
form = CreateTesseractOCRPipelineJobForm(prefix='create-job-form', version=version)
|
form = CreateTesseractOCRPipelineJobForm(prefix='create-job-form', version=version)
|
||||||
if form.is_submitted():
|
if form.is_submitted():
|
||||||
if not form.validate():
|
if not form.validate():
|
||||||
@ -111,6 +114,7 @@ def tesseract_ocr_pipeline():
|
|||||||
return render_template(
|
return render_template(
|
||||||
'services/tesseract_ocr_pipeline.html.j2',
|
'services/tesseract_ocr_pipeline.html.j2',
|
||||||
title=service_manifest['name'],
|
title=service_manifest['name'],
|
||||||
|
choosable_job_ids=choosable_job_ids,
|
||||||
form=form,
|
form=form,
|
||||||
tesseract_ocr_pipeline_models=tesseract_ocr_pipeline_models,
|
tesseract_ocr_pipeline_models=tesseract_ocr_pipeline_models,
|
||||||
user_tesseract_ocr_pipeline_models_count=user_tesseract_ocr_pipeline_models_count
|
user_tesseract_ocr_pipeline_models_count=user_tesseract_ocr_pipeline_models_count
|
||||||
|
137
app/static/js/resource-lists/job-output-list.js
Normal file
137
app/static/js/resource-lists/job-output-list.js
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
nopaque.resource_lists.JobOutputList = class JobOutputList extends nopaque.resource_lists.ResourceList {
|
||||||
|
static htmlClass = 'job-output-list';
|
||||||
|
|
||||||
|
constructor(listContainerElement, options = {}) {
|
||||||
|
super(listContainerElement, options);
|
||||||
|
this.listjs.list.addEventListener('click', (event) => {this.onClick(event)});
|
||||||
|
this.isInitialized = false;
|
||||||
|
this.userId = listContainerElement.dataset.userId;
|
||||||
|
this.jobOutput = listContainerElement.dataset.jobOutput;
|
||||||
|
this.jobIds = listContainerElement.dataset.jobIds;
|
||||||
|
if (this.userId === undefined) {return;}
|
||||||
|
app.subscribeUser(this.userId).then((response) => {
|
||||||
|
app.socket.on('PATCH', (patch) => {
|
||||||
|
if (this.isInitialized) {this.onPatch(patch);}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.getUser(this.userId).then((user) => {
|
||||||
|
let jobIds = JSON.parse(this.jobIds.replace(/'/g, '"'));
|
||||||
|
let job_results = {};
|
||||||
|
for (let jobId of jobIds) {
|
||||||
|
for (let jobResult of Object.values(user.jobs[jobId].results)) {
|
||||||
|
if (jobResult.mimetype === 'application/pdf') {
|
||||||
|
job_results[jobResult.id] = jobResult;
|
||||||
|
job_results[jobResult.id].description = user.jobs[jobId].description;
|
||||||
|
job_results[jobResult.id].title = user.jobs[jobId].title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.add(Object.values(job_results));
|
||||||
|
this.isInitialized = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get item() {
|
||||||
|
return `
|
||||||
|
<tr class="list-item clickable hoverable">
|
||||||
|
<td><span class="title"></span></td>
|
||||||
|
<td><span class="description"></span></td>
|
||||||
|
<td><span class="filename"></span></td>
|
||||||
|
<td class="right-align">
|
||||||
|
<a class="list-action-trigger btn-flat waves-effect waves-light" data-list-action="add"><i class="material-icons">add</i></a>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
`.trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
get valueNames() {
|
||||||
|
return [
|
||||||
|
{data: ['id']},
|
||||||
|
{data: ['creation-date']},
|
||||||
|
'title',
|
||||||
|
'description',
|
||||||
|
'filename'
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
initListContainerElement() {
|
||||||
|
if (!this.listContainerElement.hasAttribute('id')) {
|
||||||
|
this.listContainerElement.id = nopaque.Utils.generateElementId('job-output-list-');
|
||||||
|
}
|
||||||
|
let listSearchElementId = nopaque.Utils.generateElementId(`${this.listContainerElement.id}-search-`);
|
||||||
|
this.listContainerElement.innerHTML = `
|
||||||
|
<div class="input-field">
|
||||||
|
<i class="material-icons prefix">search</i>
|
||||||
|
<input id="${listSearchElementId}" class="search" type="text"></input>
|
||||||
|
<label for="${listSearchElementId}">Search job output</label>
|
||||||
|
</div>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Title</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Filename</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="list"></tbody>
|
||||||
|
</table>
|
||||||
|
<ul class="pagination"></ul>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
mapResourceToValue(jobOutput) {
|
||||||
|
console.log(jobOutput);
|
||||||
|
return {
|
||||||
|
'id': jobOutput.id,
|
||||||
|
'creation-date': jobOutput.creationDate,
|
||||||
|
'title': jobOutput.title,
|
||||||
|
'description': jobOutput.description,
|
||||||
|
'filename': jobOutput.filename
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
sort() {
|
||||||
|
this.listjs.sort('title', {order: 'asc'});
|
||||||
|
}
|
||||||
|
|
||||||
|
onClick(event) {
|
||||||
|
let listItemElement = event.target.closest('.list-item[data-id]');
|
||||||
|
if (listItemElement === null) {return;}
|
||||||
|
let itemId = listItemElement.dataset.id;
|
||||||
|
let listActionElement = event.target.closest('.list-action-trigger[data-list-action]');
|
||||||
|
let listAction = listActionElement === null ? 'add' : listActionElement.dataset.listAction;
|
||||||
|
switch (listAction) {
|
||||||
|
case 'add': {
|
||||||
|
listActionElement.querySelector('i').textContent = 'done';
|
||||||
|
listActionElement.dataset.listAction = 'remove';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'remove': {
|
||||||
|
listActionElement.querySelector('i').textContent = 'add';
|
||||||
|
listActionElement.dataset.listAction = 'add';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// onPatch(patch) {
|
||||||
|
// let re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)`);
|
||||||
|
// let filteredPatch = patch.filter(operation => re.test(operation.path));
|
||||||
|
// for (let operation of filteredPatch) {
|
||||||
|
// switch(operation.op) {
|
||||||
|
// case 'add': {
|
||||||
|
// let re = new RegExp(`^/users/${this.userId}/jobs/${this.jobId}/results/([A-Za-z0-9]*)$`);
|
||||||
|
// if (re.test(operation.path)) {this.add(operation.value);}
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// default: {
|
||||||
|
// break;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
};
|
@ -52,6 +52,7 @@
|
|||||||
'js/resource-lists/job-input-list.js',
|
'js/resource-lists/job-input-list.js',
|
||||||
'js/resource-lists/job-list.js',
|
'js/resource-lists/job-list.js',
|
||||||
'js/resource-lists/job-result-list.js',
|
'js/resource-lists/job-result-list.js',
|
||||||
|
'js/resource-lists/job-output-list.js',
|
||||||
'js/resource-lists/public-corpus-list.js',
|
'js/resource-lists/public-corpus-list.js',
|
||||||
'js/resource-lists/public-user-list.js',
|
'js/resource-lists/public-user-list.js',
|
||||||
'js/resource-lists/spacy-nlp-pipeline-model-list.js',
|
'js/resource-lists/spacy-nlp-pipeline-model-list.js',
|
||||||
|
@ -37,6 +37,15 @@
|
|||||||
|
|
||||||
<div class="col s12">
|
<div class="col s12">
|
||||||
<h2>Submit a job</h2>
|
<h2>Submit a job</h2>
|
||||||
|
<div class="card">
|
||||||
|
<div class="card-content">
|
||||||
|
<p>Add an existing file from your workflow or add a new one below.</p>
|
||||||
|
<div class="job-output-list" data-user-id="{{ current_user.hashid}}" data-job-ids="{{ choosable_job_ids }}"></div>
|
||||||
|
</div>
|
||||||
|
<div class="card-action right-align">
|
||||||
|
<a class="waves-effect waves-light btn"><i class="material-icons right">send</i>Submit</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<form class="create-job-form" enctype="multipart/form-data" method="POST">
|
<form class="create-job-form" enctype="multipart/form-data" method="POST">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
@ -51,6 +60,8 @@
|
|||||||
<div class="col s12 l5">
|
<div class="col s12 l5">
|
||||||
{{ wtf.render_field(form.pdf, accept='application/pdf', placeholder='Choose a PDF file') }}
|
{{ wtf.render_field(form.pdf, accept='application/pdf', placeholder='Choose a PDF file') }}
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
<div class="col s12 l4">
|
<div class="col s12 l4">
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
<i class="material-icons prefix">language</i>
|
<i class="material-icons prefix">language</i>
|
||||||
|
Loading…
Reference in New Issue
Block a user