aboutsummaryrefslogtreecommitdiff
path: root/uploader
diff options
context:
space:
mode:
Diffstat (limited to 'uploader')
-rw-r--r--uploader/jobs.py34
-rw-r--r--uploader/phenotypes/views.py14
-rw-r--r--uploader/templates/cli-output.html4
-rw-r--r--uploader/templates/phenotypes/add-phenotypes.html2
-rw-r--r--uploader/templates/phenotypes/job-status.html71
5 files changed, 118 insertions, 7 deletions
diff --git a/uploader/jobs.py b/uploader/jobs.py
index 4a3fc80..e86ee05 100644
--- a/uploader/jobs.py
+++ b/uploader/jobs.py
@@ -1,6 +1,8 @@
"""Handle jobs"""
import os
import sys
+import uuid
+import json
import shlex
import subprocess
from uuid import UUID, uuid4
@@ -10,6 +12,8 @@ from typing import Union, Optional
from redis import Redis
from flask import current_app as app
+from functional_tools import take
+
JOBS_PREFIX = "jobs"
class JobNotFound(Exception):
@@ -128,3 +132,33 @@ def update_stdout_stderr(rconn: Redis,
contents = thejob.get(stream, '')
new_contents = contents + bytes_read.decode("utf-8")
rconn.hset(name=job_key(rprefix, jobid), key=stream, value=new_contents)
+
+
+def job_errors(
+ rconn: Redis,
+ prefix: str,
+ job_id: Union[str, uuid.UUID],
+ count: int = 100
+) -> list:
+ """Fetch job errors"""
+ return take(
+ (
+ json.loads(error)
+ for key in rconn.keys(f"{prefix}:{str(job_id)}:*:errors:*")
+ for error in rconn.lrange(key, 0, -1)),
+ count)
+
+
+def job_files_metadata(
+ rconn: Redis,
+ prefix: str,
+ job_id: Union[str, uuid.UUID]
+) -> dict:
+ """Get the metadata for specific job file."""
+ return {
+ key.split(":")[-1]: {
+ **rconn.hgetall(key),
+ "filetype": key.split(":")[-3]
+ }
+ for key in rconn.keys(f"{prefix}:{str(job_id)}:*:metadata*")
+ }
diff --git a/uploader/phenotypes/views.py b/uploader/phenotypes/views.py
index b8c0e93..a664ba9 100644
--- a/uploader/phenotypes/views.py
+++ b/uploader/phenotypes/views.py
@@ -395,10 +395,14 @@ def add_phenotypes(species: dict, population: dict, dataset: dict, **kwargs):# p
species_redirect_uri="species.populations.phenotypes.index",
population_redirect_uri="species.populations.phenotypes.select_population",
redirect_uri="species.populations.phenotypes.list_datasets")
-def job_status(species: dict, population: dict, dataset: dict, job_id: uuid, **kwargs):
+def job_status(
+ species: dict,
+ population: dict,
+ dataset: dict,
+ job_id: uuid.UUID,
+ **kwargs
+):# pylint: disable=[unused-argument]
"""Retrieve current status of a particular phenotype QC job."""
- from uploader.debug import __pk__
-
with Redis.from_url(app.config["REDIS_URL"], decode_responses=True) as rconn:
try:
job = jobs.job(rconn, jobs.jobsnamespace(), str(job_id))
@@ -410,4 +414,8 @@ def job_status(species: dict, population: dict, dataset: dict, job_id: uuid, **k
dataset=dataset,
job_id=job_id,
job=job,
+ errors=jobs.job_errors(
+ rconn, jobs.jobsnamespace(), job['jobid']),
+ metadata=jobs.job_files_metadata(
+ rconn, jobs.jobsnamespace(), job['jobid']),
activelink="add-phenotypes")
diff --git a/uploader/templates/cli-output.html b/uploader/templates/cli-output.html
index 33fb73b..64b1a9a 100644
--- a/uploader/templates/cli-output.html
+++ b/uploader/templates/cli-output.html
@@ -1,7 +1,7 @@
{%macro cli_output(job, stream)%}
-<h4>{{stream | upper}} Output</h4>
-<div class="cli-output">
+<h4 class="subheading">{{stream | upper}} Output</h4>
+<div class="cli-output" style="max-height: 10em; overflow: auto;">
<pre>{{job.get(stream, "")}}</pre>
</div>
diff --git a/uploader/templates/phenotypes/add-phenotypes.html b/uploader/templates/phenotypes/add-phenotypes.html
index 196bc69..9e368e1 100644
--- a/uploader/templates/phenotypes/add-phenotypes.html
+++ b/uploader/templates/phenotypes/add-phenotypes.html
@@ -40,7 +40,7 @@
<p>See the <a href="#section-file-formats">File Formats</a> section below
to get an understanding of what is expected of the bundle files you
upload.</p>
- <p><strong>This will not update any existing phenotypes!</strong></p>
+ <p><strong class="text-warning">This will not update any existing phenotypes!</strong></p>
</div>
<div class="form-group">
diff --git a/uploader/templates/phenotypes/job-status.html b/uploader/templates/phenotypes/job-status.html
index d531a71..30316b5 100644
--- a/uploader/templates/phenotypes/job-status.html
+++ b/uploader/templates/phenotypes/job-status.html
@@ -30,8 +30,32 @@
{%block contents%}
{%if job%}
+<h4 class="subheading">Progress</h4>
<div class="row">
- <p><strong>Status:</strong> {{job.status}}</p>
+ <p><strong>Process Status:</strong> {{job.status}}</p>
+ {%if metadata%}
+ <table class="table">
+ <thead>
+ <tr>
+ <th>File</th>
+ <th>Status</th>
+ <th>Lines Processed</th>
+ <th>Total Errors</th>
+ </tr>
+ </thead>
+
+ <tbody>
+ {%for file,meta in metadata.items()%}
+ <tr>
+ <td>{{file}}</td>
+ <td>{{meta.status}}</td>
+ <td>{{meta.linecount}}</td>
+ <td>{{meta["total-errors"]}}</td>
+ </tr>
+ {%endfor%}
+ </tbody>
+ </table>
+ {%endif%}
{%if job.status in ("completed:success", "success")%}
<p><a href="#"
class="not-implemented btn btn-primary"
@@ -40,6 +64,50 @@
{%endif%}
</div>
+<h4 class="subheading">Errors</h4>
+<div class="row" style="max-height: 20em; overflow: auto;">
+ {%if errors | length == 0 %}
+ <p class="text-info">
+ <span class="glyphicon glyphicon-info-sign"></span>
+ No errors found so far
+ </p>
+ {%else%}
+ <table class="table">
+ <thead>
+ <tr>
+ <th>File</th>
+ <th>Row</th>
+ <th>Column</th>
+ <th>Value</th>
+ <th>Message</th>
+ </thead>
+
+ <tbody style="font-size: 0.9em;">
+ {%for error in errors%}
+ <tr>
+ <td>{{error.filename}}</td>
+ <td>{{error.rowtitle}}</td>
+ <td>{{error.coltitle}}</td>
+ <td>{%if error.cellvalue | length > 25%}
+ {{error.cellvalue[0:24]}}&hellip;
+ {%else%}
+ {{error.cellvalue}}
+ {%endif%}
+ </td>
+ <td>
+ {%if error.message | length > 250 %}
+ {{error.message[0:249]}}&hellip;
+ {%else%}
+ {{error.message}}
+ {%endif%}
+ </td>
+ </tr>
+ {%endfor%}
+ </tbody>
+ </table>
+ {%endif%}
+</div>
+
<div class="row">
{{cli_output(job, "stdout")}}
</div>
@@ -47,6 +115,7 @@
<div class="row">
{{cli_output(job, "stderr")}}
</div>
+
{%else%}
<div class="row">
<h3 class="text-danger">No Such Job</h3>