about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2025-01-23 11:23:05 -0600
committerFrederick Muriuki Muriithi2025-01-23 11:23:05 -0600
commit190e1c7cb924ac9598956ac0f2be37ed3915ab23 (patch)
treedc6f6b80a6b73319749501ff49b55d20ba5d91ed
parent6f92748ed9bfa1e2e522ed385809890ef2d43575 (diff)
downloadgn-uploader-190e1c7cb924ac9598956ac0f2be37ed3915ab23.tar.gz
Provide summary for review before entering data to database.
-rw-r--r--uploader/phenotypes/views.py76
-rw-r--r--uploader/templates/phenotypes/job-status.html8
-rw-r--r--uploader/templates/phenotypes/review-job-data.html101
3 files changed, 182 insertions, 3 deletions
diff --git a/uploader/phenotypes/views.py b/uploader/phenotypes/views.py
index ec4c840..53e68d1 100644
--- a/uploader/phenotypes/views.py
+++ b/uploader/phenotypes/views.py
@@ -5,7 +5,7 @@ import json
 import datetime
 from pathlib import Path
 from zipfile import ZipFile
-from functools import wraps
+from functools import wraps, reduce
 from logging import INFO, ERROR, DEBUG, FATAL, CRITICAL, WARNING
 
 from redis import Redis
@@ -502,3 +502,77 @@ def job_status(
                                metadata=jobs.job_files_metadata(
                                    rconn, jobs.jobsnamespace(), job['jobid']),
                                activelink="add-phenotypes")
+
+
+@phenotypesbp.route(
+    "<int:species_id>/populations/<int:population_id>/phenotypes/datasets"
+    "/<int:dataset_id>/review-job/<uuid:job_id>",
+    methods=["GET"])
+@require_login
+@with_dataset(
+    species_redirect_uri="species.populations.phenotypes.index",
+    population_redirect_uri="species.populations.phenotypes.select_population",
+    redirect_uri="species.populations.phenotypes.list_datasets")
+def review_job_data(
+        species: dict,
+        population: dict,
+        dataset: dict,
+        job_id: uuid.UUID,
+        **kwargs
+):# pylint: disable=[unused-argument]
+    """Review data one more time before entering it into the database."""
+    with Redis.from_url(app.config["REDIS_URL"], decode_responses=True) as rconn:
+        try:
+            job = jobs.job(rconn, jobs.jobsnamespace(), str(job_id))
+        except jobs.JobNotFound as _jnf:
+            job = None
+
+        def __metadata_by_type__(by_type, item):
+            filetype = item[1]["filetype"]
+            return {
+                **by_type,
+                filetype: (by_type.get(filetype, tuple())
+                           + ({"filename": item[0], **item[1]},))
+            }
+        metadata = reduce(__metadata_by_type__,
+                          (jobs.job_files_metadata(
+                              rconn, jobs.jobsnamespace(), job['jobid'])
+                                    if job else {}).items(),
+                          {})
+
+        def __desc__(filetype):
+            match filetype:
+                case "phenocovar":
+                    desc = "phenotypes"
+                case "pheno":
+                    desc = "phenotypes data"
+                case "phenose":
+                    desc = "phenotypes standard-errors"
+                case "phenonum":
+                    desc = "phenotypes samples"
+                case _:
+                    desc = f"unknown file type '{filetype}'."
+
+            return desc
+
+        def __summarise__(filetype, files):
+            return {
+                "filetype": filetype,
+                "number-of-files": len(files),
+                "total-data-rows": sum(
+                    int(afile["linecount"]) - 1 for afile in files),
+                "description": __desc__(filetype)
+            }
+
+        summary = {
+            filetype: __summarise__(filetype, meta)
+            for filetype,meta in metadata.items()
+        }
+        return render_template("phenotypes/review-job-data.html",
+                               species=species,
+                               population=population,
+                               dataset=dataset,
+                               job_id=job_id,
+                               job=job,
+                               summary=summary,
+                               activelink="add-phenotypes")
diff --git a/uploader/templates/phenotypes/job-status.html b/uploader/templates/phenotypes/job-status.html
index 6f43d22..12963c1 100644
--- a/uploader/templates/phenotypes/job-status.html
+++ b/uploader/templates/phenotypes/job-status.html
@@ -62,8 +62,12 @@
   {%if  job.status in ("completed:success", "success")%}
   <p>
     {%if errors | length == 0%}
-    <a href="#"
-       class="not-implemented btn btn-primary"
+    <a href="{{url_for('species.populations.phenotypes.review_job_data',
+           species_id=species.SpeciesId,
+           population_id=population.Id,
+           dataset_id=dataset.Id,
+           job_id=job_id)}}"
+       class="btn btn-primary"
        title="Continue to process data">Continue</a>
     {%else%}
     <span class="text-muted"
diff --git a/uploader/templates/phenotypes/review-job-data.html b/uploader/templates/phenotypes/review-job-data.html
new file mode 100644
index 0000000..7bc8c62
--- /dev/null
+++ b/uploader/templates/phenotypes/review-job-data.html
@@ -0,0 +1,101 @@
+{%extends "phenotypes/base.html"%}
+{%from "cli-output.html" import cli_output%}
+{%from "flash_messages.html" import flash_all_messages%}
+{%from "macro-table-pagination.html" import table_pagination%}
+{%from "phenotypes/macro-display-pheno-dataset-card.html" import display_pheno_dataset_card%}
+
+{%block extrameta%}
+{%if not job%}
+<meta http-equiv="refresh"
+      content="20; url={{url_for('species.populations.phenotypes.view_dataset', species_id=species.SpeciesId,
+               population_id=population.Id,
+               dataset_id=dataset.Id)}}" />
+{%endif%}
+{%endblock%}
+
+{%block title%}Phenotypes{%endblock%}
+
+{%block pagetitle%}Phenotypes{%endblock%}
+
+{%block lvl4_breadcrumbs%}
+<li {%if activelink=="add-phenotypes"%}
+    class="breadcrumb-item active"
+    {%else%}
+    class="breadcrumb-item"
+    {%endif%}>
+  <a href="{{url_for('species.populations.phenotypes.add_phenotypes',
+           species_id=species.SpeciesId,
+           population_id=population.Id,
+           dataset_id=dataset.Id)}}">View Datasets</a>
+</li>
+{%endblock%}
+
+{%block contents%}
+
+{%if job%}
+<div class="row">
+  <h3 class="heading">Data Review</h3>
+  <p>The &#x201C;<strong>{{dataset.FullName}}</strong>&#x201D; dataset from the
+    &#x201C;<strong>{{population.FullName}}</strong>&#x201D; population of the
+    species &#x201C;<strong>{{species.SpeciesName}} ({{species.FullName}})</strong>&#x201D;
+    will be updated as follows:</p>
+
+  {%for ftype in ("phenocovar", "pheno", "phenose", "phenonum")%}
+  {%if summary.get(ftype, False)%}
+  <ul>
+    <li>A total of {{summary[ftype]["number-of-files"]}} files will be processed
+      adding {%if ftype == "phenocovar"%}(possibly){%endif%}
+      {{summary[ftype]["total-data-rows"]}} new
+      {%if ftype == "phenocovar"%}
+      phenotypes
+      {%else%}
+      {{summary[ftype]["description"]}} rows
+      {%endif%}
+      to the database.
+    </li>
+  </ul>
+  {%endif%}
+  {%endfor%}
+
+  <a href="#" class="not-implemented btn btn-primary">continue</a>
+</div>
+{%else%}
+<div class="row">
+  <h4 class="subheading">Invalid Job</h3>
+  <p class="text-danger">
+    Could not find a job with the ID: <strong>{{job_id}}.</p>
+  <p>You will be redirected in
+    <span id="countdown-element" class="text-info">20</span> second(s)</p>
+  <p class="text-muted">
+    <small>
+      If you are not redirected, please
+      <a href="{{url_for(
+               'species.populations.phenotypes.view_dataset',
+               species_id=species.SpeciesId,
+               population_id=population.Id,
+               dataset_id=dataset.Id)}}">click here</a> to continue
+    </small>
+  </p>
+</div>
+{%endif%}
+{%endblock%}
+
+{%block sidebarcontents%}
+{{display_pheno_dataset_card(species, population, dataset)}}
+{%endblock%}
+
+
+{%block javascript%}
+<script type="text/javascript">
+  $(document).ready(function() {
+      var countdown = 20;
+      var countdown_element = $("#countdown-element");
+      if(countdown_element.length === 1) {
+          intv = window.setInterval(function() {
+              countdown = countdown - 1;
+              countdown_element.html(countdown);
+          }, 1000);
+      }
+  });
+</script>
+{%endblock%}