From 5c395d1e06714cfd0a370758c04d567057770eba Mon Sep 17 00:00:00 2001 From: Inga Kirschnick Date: Thu, 14 Mar 2024 10:08:52 +0100 Subject: [PATCH] Job output list implementation --- app/services/routes.py | 4 + .../js/resource-lists/job-output-list.js | 137 ++++++++++++++++++ app/templates/_base/scripts.html.j2 | 1 + .../services/tesseract_ocr_pipeline.html.j2 | 11 ++ 4 files changed, 153 insertions(+) create mode 100644 app/static/js/resource-lists/job-output-list.js diff --git a/app/services/routes.py b/app/services/routes.py index 9f4cfdc0..2c0ab310 100644 --- a/app/services/routes.py +++ b/app/services/routes.py @@ -6,6 +6,7 @@ from app import db, hashids from app.models import ( Job, JobInput, + JobResult, JobStatus, TesseractOCRPipelineModel, SpaCyNLPPipelineModel @@ -74,6 +75,8 @@ def tesseract_ocr_pipeline(): version = request.args.get('version', service_manifest['latest_version']) if version not in service_manifest['versions']: 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) if form.is_submitted(): if not form.validate(): @@ -111,6 +114,7 @@ def tesseract_ocr_pipeline(): return render_template( 'services/tesseract_ocr_pipeline.html.j2', title=service_manifest['name'], + choosable_job_ids=choosable_job_ids, form=form, tesseract_ocr_pipeline_models=tesseract_ocr_pipeline_models, user_tesseract_ocr_pipeline_models_count=user_tesseract_ocr_pipeline_models_count diff --git a/app/static/js/resource-lists/job-output-list.js b/app/static/js/resource-lists/job-output-list.js new file mode 100644 index 00000000..91738de5 --- /dev/null +++ b/app/static/js/resource-lists/job-output-list.js @@ -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 ` + + + + + + add + + + `.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 = ` +
+ search + + +
+ + + + + + + + + + +
TitleDescriptionFilename
+ + `; + } + + 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; + // } + // } + // } + // } +}; diff --git a/app/templates/_base/scripts.html.j2 b/app/templates/_base/scripts.html.j2 index b4da4b46..3792f96d 100644 --- a/app/templates/_base/scripts.html.j2 +++ b/app/templates/_base/scripts.html.j2 @@ -52,6 +52,7 @@ 'js/resource-lists/job-input-list.js', 'js/resource-lists/job-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-user-list.js', 'js/resource-lists/spacy-nlp-pipeline-model-list.js', diff --git a/app/templates/services/tesseract_ocr_pipeline.html.j2 b/app/templates/services/tesseract_ocr_pipeline.html.j2 index 69be6889..2149e187 100644 --- a/app/templates/services/tesseract_ocr_pipeline.html.j2 +++ b/app/templates/services/tesseract_ocr_pipeline.html.j2 @@ -37,6 +37,15 @@

Submit a job

+
+
+

Add an existing file from your workflow or add a new one below.

+
+
+ +
@@ -51,6 +60,8 @@
{{ wtf.render_field(form.pdf, accept='application/pdf', placeholder='Choose a PDF file') }}
+
+
language