about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.guix-channel4
-rw-r--r--README.org2
-rw-r--r--scripts/insert_samples.py16
-rw-r--r--scripts/phenotypes/__init__.py1
-rw-r--r--scripts/phenotypes/delete_phenotypes.py173
-rw-r--r--scripts/run_qtlreaper.py2
-rw-r--r--uploader/__init__.py23
-rw-r--r--uploader/background_jobs.py142
-rw-r--r--uploader/base_routes.py9
-rw-r--r--uploader/configutils.py13
-rw-r--r--uploader/default_settings.py10
-rw-r--r--uploader/errors.py3
-rw-r--r--uploader/files/chunks.py4
-rw-r--r--uploader/files/functions.py4
-rw-r--r--uploader/files/views.py4
-rw-r--r--uploader/flask_extensions.py40
-rw-r--r--uploader/phenotypes/models.py205
-rw-r--r--uploader/phenotypes/views.py175
-rw-r--r--uploader/platforms/views.py6
-rw-r--r--uploader/population/views.py5
-rw-r--r--uploader/publications/views.py14
-rw-r--r--uploader/samples/views.py148
-rw-r--r--uploader/session.py21
-rw-r--r--uploader/species/views.py4
-rw-r--r--uploader/static/css/layout-common.css18
-rw-r--r--uploader/static/css/layout-large.css6
-rw-r--r--uploader/static/css/layout-medium.css5
-rw-r--r--uploader/static/css/layout-small.css9
-rw-r--r--uploader/static/css/theme.css19
-rw-r--r--uploader/static/js/datatables.js74
-rw-r--r--uploader/static/js/utils.js3
-rw-r--r--uploader/sui.py8
-rw-r--r--uploader/templates/background-jobs/base.html10
-rw-r--r--uploader/templates/background-jobs/default-success-page.html17
-rw-r--r--uploader/templates/background-jobs/delete-job.html61
-rw-r--r--uploader/templates/background-jobs/job-status.html45
-rw-r--r--uploader/templates/background-jobs/job-summary.html75
-rw-r--r--uploader/templates/background-jobs/list-jobs.html79
-rw-r--r--uploader/templates/background-jobs/macro-display-job-details.html29
-rw-r--r--uploader/templates/background-jobs/stop-job.html61
-rw-r--r--uploader/templates/background-jobs/sui-default-success-page.html17
-rw-r--r--uploader/templates/base.html120
-rw-r--r--uploader/templates/genotypes/base.html31
-rw-r--r--uploader/templates/genotypes/list-genotypes.html17
-rw-r--r--uploader/templates/genotypes/list-markers.html20
-rw-r--r--uploader/templates/genotypes/view-dataset.html16
-rw-r--r--uploader/templates/index.html229
-rw-r--r--uploader/templates/jobs/sui-job-error.html17
-rw-r--r--uploader/templates/jobs/sui-job-not-found.html11
-rw-r--r--uploader/templates/jobs/sui-job-status.html24
-rw-r--r--uploader/templates/login.html12
-rw-r--r--uploader/templates/phenotypes/add-phenotypes-base.html21
-rw-r--r--uploader/templates/phenotypes/add-phenotypes-raw-files.html36
-rw-r--r--uploader/templates/phenotypes/add-phenotypes-with-rqtl2-bundle.html18
-rw-r--r--uploader/templates/phenotypes/base.html34
-rw-r--r--uploader/templates/phenotypes/confirm-delete-phenotypes.html196
-rw-r--r--uploader/templates/phenotypes/job-status.html25
-rw-r--r--uploader/templates/phenotypes/load-phenotypes-success.html20
-rw-r--r--uploader/templates/phenotypes/macro-display-preview-table.html24
-rw-r--r--uploader/templates/phenotypes/review-job-data.html4
-rw-r--r--uploader/templates/phenotypes/sui-add-phenotypes-base.html155
-rw-r--r--uploader/templates/phenotypes/sui-add-phenotypes-raw-files.html829
-rw-r--r--uploader/templates/phenotypes/sui-add-phenotypes-with-rqtl2-bundle.html189
-rw-r--r--uploader/templates/phenotypes/sui-base.html25
-rw-r--r--uploader/templates/phenotypes/sui-job-status.html140
-rw-r--r--uploader/templates/phenotypes/sui-load-phenotypes-success.html26
-rw-r--r--uploader/templates/phenotypes/sui-review-job-data.html121
-rw-r--r--uploader/templates/phenotypes/sui-view-dataset.html207
-rw-r--r--uploader/templates/phenotypes/view-dataset.html95
-rw-r--r--uploader/templates/phenotypes/view-phenotype.html19
-rw-r--r--uploader/templates/platforms/base.html22
-rw-r--r--uploader/templates/platforms/create-platform.html20
-rw-r--r--uploader/templates/platforms/list-platforms.html5
-rw-r--r--uploader/templates/platforms/sui-base.html17
-rw-r--r--uploader/templates/platforms/sui-create-platform.html116
-rw-r--r--uploader/templates/platforms/sui-list-platforms.html88
-rw-r--r--uploader/templates/populations/base.html28
-rw-r--r--uploader/templates/populations/create-population.html18
-rw-r--r--uploader/templates/populations/macro-display-population-card.html3
-rw-r--r--uploader/templates/populations/sui-base.html12
-rw-r--r--uploader/templates/populations/sui-view-population.html127
-rw-r--r--uploader/templates/populations/view-population.html201
-rw-r--r--uploader/templates/publications/base.html13
-rw-r--r--uploader/templates/publications/create-publication.html23
-rw-r--r--uploader/templates/publications/delete-publication.html11
-rw-r--r--uploader/templates/publications/edit-publication.html13
-rw-r--r--uploader/templates/publications/index.html57
-rw-r--r--uploader/templates/publications/sui-base.html9
-rw-r--r--uploader/templates/publications/sui-create-publication.html200
-rw-r--r--uploader/templates/publications/sui-delete-publication.html95
-rw-r--r--uploader/templates/publications/sui-edit-publication.html203
-rw-r--r--uploader/templates/publications/sui-index.html109
-rw-r--r--uploader/templates/publications/sui-view-publication.html80
-rw-r--r--uploader/templates/publications/view-publication.html2
-rw-r--r--uploader/templates/samples/base.html29
-rw-r--r--uploader/templates/samples/list-samples.html50
-rw-r--r--uploader/templates/samples/sui-base.html25
-rw-r--r--uploader/templates/samples/sui-list-samples.html98
-rw-r--r--uploader/templates/samples/sui-upload-failure.html32
-rw-r--r--uploader/templates/samples/sui-upload-progress.html26
-rw-r--r--uploader/templates/samples/sui-upload-samples.html153
-rw-r--r--uploader/templates/samples/sui-upload-success.html31
-rw-r--r--uploader/templates/samples/upload-failure.html5
-rw-r--r--uploader/templates/samples/upload-progress.html5
-rw-r--r--uploader/templates/samples/upload-samples.html81
-rw-r--r--uploader/templates/samples/upload-success.html5
-rw-r--r--uploader/templates/species/base.html19
-rw-r--r--uploader/templates/species/sui-base.html10
-rw-r--r--uploader/templates/species/sui-view-species.html127
-rw-r--r--uploader/templates/species/view-species.html171
-rw-r--r--uploader/templates/sui-base.html103
-rw-r--r--uploader/templates/sui-index.html161
l---------uploader/templates/sui-login.html1
-rw-r--r--uploader/ui.py2
114 files changed, 2105 insertions, 4746 deletions
diff --git a/.guix-channel b/.guix-channel
index 54206b2..f1a8fa6 100644
--- a/.guix-channel
+++ b/.guix-channel
@@ -35,11 +35,12 @@
   (channel
    (name guix-bioinformatics)
    (url "https://git.genenetwork.org/guix-bioinformatics")
-   (commit "903465c85c9b2ae28480b236c3364da873ca8f51"))
+   (commit "9b0955f14ec725990abb1f6af3b9f171e4943f77"))
   (channel
    (name guix-past)
    (url "https://codeberg.org/guix-science/guix-past")
    (branch "master")
+   (commit "473c942b509ab3ead35159d27dfbf2031a36cd4d")
    (introduction
     (channel-introduction
      (version 0)
@@ -50,6 +51,7 @@
    (name guix-rust-past-crates)
    (url "https://codeberg.org/guix/guix-rust-past-crates.git")
    (branch "trunk")
+   (commit "b8b7ffbd1cec9f56f93fae4da3a74163bbc9c570")
    (introduction
     (channel-introduction
      (version 0)
diff --git a/README.org b/README.org
index ca77653..efa837b 100644
--- a/README.org
+++ b/README.org
@@ -219,7 +219,7 @@ To check for correct type usage in the application, run:
 Run unit tests with:
 #+BEGIN_SRC shell
   $ export UPLOADER_CONF=</path/to/configuration/file.py>
-  $ pytest -m unit_test
+  $ pytest -m unit_test -n auto
 #+END_SRC
 
 To run ALL tests (not just unit tests):
diff --git a/scripts/insert_samples.py b/scripts/insert_samples.py
index fc029f9..96ae8e2 100644
--- a/scripts/insert_samples.py
+++ b/scripts/insert_samples.py
@@ -6,10 +6,10 @@ import argparse
 import traceback
 
 import MySQLdb as mdb
-from redis import Redis
+
 from gn_libs.mysqldb import database_connection
 
-from uploader.check_connections import check_db, check_redis
+from uploader.check_connections import check_db
 from uploader.species.models import species_by_id
 from uploader.population.models import population_by_id
 from uploader.samples.models import (
@@ -35,7 +35,6 @@ class SeparatorAction(argparse.Action):
         setattr(namespace, self.dest, (chr(9) if values == "\\t" else values))
 
 def insert_samples(conn: mdb.Connection,# pylint: disable=[too-many-arguments, too-many-positional-arguments]
-                   rconn: Redis,# pylint: disable=[unused-argument]
                    speciesid: int,
                    populationid: int,
                    samplesfile: pathlib.Path,
@@ -119,11 +118,6 @@ if __name__ == "__main__":
             help=("The character used to delimit (surround?) the value in "
                   "each column."))
 
-        # == Script-specific extras ==
-        parser.add_argument("--redisuri",
-                            help="URL to initialise connection to redis",
-                            default="redis:///")
-
         args = parser.parse_args()
         return args
 
@@ -132,17 +126,13 @@ if __name__ == "__main__":
         status_code = 1 # Exit with an Exception
         args = cli_args()
         check_db(args.databaseuri)
-        check_redis(args.redisuri)
         if not args.samplesfile.exists():
             logging.error("File not found: '%s'.", args.samplesfile)
             return 2
 
-        with (Redis.from_url(args.redisuri, decode_responses=True) as rconn,
-              database_connection(args.databaseuri) as dbconn):
-
+        with database_connection(args.databaseuri) as dbconn:
             try:
                 status_code = insert_samples(dbconn,
-                                             rconn,
                                              args.speciesid,
                                              args.populationid,
                                              args.samplesfile,
diff --git a/scripts/phenotypes/__init__.py b/scripts/phenotypes/__init__.py
new file mode 100644
index 0000000..73ad839
--- /dev/null
+++ b/scripts/phenotypes/__init__.py
@@ -0,0 +1 @@
+"Scripts for dealing with phenotypes."
diff --git a/scripts/phenotypes/delete_phenotypes.py b/scripts/phenotypes/delete_phenotypes.py
new file mode 100644
index 0000000..461f3ec
--- /dev/null
+++ b/scripts/phenotypes/delete_phenotypes.py
@@ -0,0 +1,173 @@
+"""Delete phenotypes."""
+import sys
+import logging
+from pathlib import Path
+from typing import Optional
+from urllib.parse import urljoin
+from argparse import Namespace, ArgumentParser
+
+import requests
+from MySQLdb.cursors import DictCursor, BaseCursor
+
+from gn_libs.mysqldb import database_connection
+
+from uploader.phenotypes.models import delete_phenotypes
+from scripts.cli.logging import setup_logging
+from scripts.cli.options import (add_logging,
+                                 add_mariadb_uri,
+                                 add_population_id)
+
+logger = logging.getLogger(__name__)
+
+def read_xref_ids_file(filepath: Optional[Path]) -> tuple[int, ...]:
+    """Read the phenotypes' cross-reference IDS from file."""
+    if filepath is None:
+        return tuple()
+
+    logger.debug("Using file '%s' to retrieve XREF IDs for deletion.",
+                 filepath.name)
+    _ids: tuple[int, ...] = tuple()
+    with filepath.open(mode="r") as infile:
+        for line in infile.readlines():
+            try:
+                _ids += (int(line.strip()),)
+            except TypeError:
+                pass
+
+    return _ids
+
+
+def fetch_all_xref_ids(
+        cursor: BaseCursor, population_id: int) -> tuple[int, ...]:
+    """Fetch all cross-reference IDs."""
+    cursor.execute("SELECT Id FROM PublishXRef WHERE InbredSetId=%s",
+                   (population_id,))
+    return tuple(int(row["Id"]) for row in cursor.fetchall())
+
+
+def update_auth(
+        auth_details: tuple[str, str],
+        species_id: int,
+        population_id: int,
+        dataset_id: int,
+        xref_ids: tuple[int, ...] = tuple()
+):
+    """Update the authorisation server: remove items to delete."""
+    authserver, token = auth_details
+    resp = requests.post(
+        urljoin(authserver,
+                (f"/auth/data/phenotypes/{species_id}/{population_id}"
+                 f"/{dataset_id}/delete")),
+        timeout=(9.13, 20),
+        headers={
+            "Authorization": f"Bearer {token}",
+            "Content-Type": "application/json"
+        },
+        json={"xref_ids": xref_ids})
+    resp.raise_for_status()
+
+
+def delete_the_phenotypes(
+        cursor: BaseCursor,
+        population_id: int,
+        xref_ids: tuple[int, ...] = tuple()) -> int:
+    """Process and delete the phenotypes."""
+    delete_phenotypes(cursor, population_id, xref_ids)
+
+    return 0
+
+if __name__ == "__main__":
+    def parse_args() -> Namespace:
+        """Parse CLI arguments."""
+        parser = add_logging(
+            add_population_id(
+                add_mariadb_uri(
+                    ArgumentParser(
+                        prog="delete-phenotypes",
+                        description=(
+                            "Script to delete phenotypes from the database.")))))
+        parser.add_argument(
+            "dataset_id",
+            metavar="DATASET-ID",
+            type=int,
+            help="The dataset identifier for phenotypes to delete.")
+        parser.add_argument(
+            "auth_server_uri",
+            metavar="AUTH-SERVER-URI",
+            type=str,
+            help="URI to the authorisation server.")
+        parser.add_argument(
+            "auth_token",
+            metavar="AUTH-TOKEN",
+            type=str,
+            help=("Token to use to update the authorisation system with the "
+                  "deletions done."))
+        parser.add_argument(
+            "--xref_ids_file",
+            metavar="XREF-IDS-FILE",
+            type=Path,
+            help=("Path to a file with phenotypes cross-reference IDs to "
+                  "delete."))
+        parser.add_argument(
+            "--delete-all",
+            action="store_true",
+            help=("If no 'XREF-IDS-FILE' is provided, this flag determines "
+                  "whether or not all the phenotypes for the given population "
+                  "will be deleted."))
+        return parser.parse_args()
+
+
+    def main():
+        """The `delete-phenotypes` script's entry point."""
+        args = parse_args()
+        setup_logging(logger, args.log_level.upper(), tuple())
+        with (database_connection(args.db_uri) as conn,
+              conn.cursor(cursorclass=DictCursor) as cursor):
+            xref_ids = read_xref_ids_file(args.xref_ids_file)
+            try:
+                assert not (len(xref_ids) > 0 and args.delete_all)
+                xref_ids = (fetch_all_xref_ids(cursor, args.population_id)
+                            if args.delete_all else xref_ids)
+                logger.debug("Will delete %s phenotypes and related data",
+                             len(xref_ids))
+                if len(xref_ids) == 0:
+                    print("No cross-reference IDs were provided. Aborting.")
+                    return 0
+
+                print("Updating authorisations: ", end="")
+                update_auth((args.auth_server_uri, args.auth_token),
+                            args.species_id,
+                            args.population_id,
+                            args.dataset_id,
+                            xref_ids)
+                print("OK.")
+                print("Deleting the data: ", end="")
+                delete_phenotypes(cursor, args.population_id, xref_ids=xref_ids)
+                print("OK.")
+                if args.xref_ids_file is not None:
+                    print("Deleting temporary file: ", end="")
+                    args.xref_ids_file.unlink()
+                    print("OK.")
+
+                return 0
+            except AssertionError:
+                logger.error(
+                    "'DELETE-ALL' and 'XREF-IDS' are mutually exclusive. "
+                    "If you specify the list of XREF-IDS (in a file) to delete "
+                    "and also specify to 'DELETE-ALL' phenotypes in the "
+                    "population, we have no way of knowing what it is you want.")
+                return 1
+            except requests.exceptions.HTTPError as _exc:
+                resp = _exc.response
+                resp_data = resp.json()
+                logger.debug("%s: %s",
+                             resp_data["error"],
+                             resp_data["error_description"],
+                             exc_info=True)
+                return 1
+            except Exception as _exc:# pylint: disable=[broad-exception-caught]
+                logger.debug("Failed while attempting to delete phenotypes.",
+                             exc_info=True)
+                return 1
+
+    sys.exit(main())
diff --git a/scripts/run_qtlreaper.py b/scripts/run_qtlreaper.py
index 7d58402..54e5d45 100644
--- a/scripts/run_qtlreaper.py
+++ b/scripts/run_qtlreaper.py
@@ -169,7 +169,7 @@ def dispatch(args: Namespace) -> int:
             logger.info("Successfully computed p values for %s traits.", len(_traitsdata))
             return 0
         except FileNotFoundError as fnf:
-            logger.error(", ".join(fnf.args), exc_info=False)
+            logger.error(", ".join(str(arg) for arg in fnf.args), exc_info=False)
         except AssertionError as aserr:
             logger.error(", ".join(aserr.args), exc_info=False)
         except Exception as _exc:# pylint: disable=[broad-exception-caught]
diff --git a/uploader/__init__.py b/uploader/__init__.py
index 0ba1f81..46689c5 100644
--- a/uploader/__init__.py
+++ b/uploader/__init__.py
@@ -73,6 +73,28 @@ def setup_modules_logging(app_logger, modules):
         _logger.setLevel(loglevel)
 
 
+def __setup_scratch_directory__(app: Flask) -> Flask:
+    app.config["SCRATCH_DIRECTORY"] = Path(
+        app.config["SCRATCH_DIRECTORY"]).absolute()
+    return app
+
+def __setup_upload_directory__(app: Flask) -> Flask:
+    if app.config.get("UPLOADS_DIRECTORY", "").strip() == "":
+        app.config["UPLOADS_DIRECTORY"] = app.config[
+            "SCRATCH_DIRECTORY"].joinpath("uploads")
+    else:
+        app.config["UPLOADS_DIRECTORY"] = Path(
+            app.config["UPLOADS_DIRECTORY"].strip()).absolute()
+
+    return app
+
+
+def update_unspecified_defaults(app: Flask) -> Flask:
+    """Setup the defaults for necessary configurations that do not have values
+    specified for them."""
+    return __setup_upload_directory__(__setup_scratch_directory__(app))
+
+
 def create_app(config: Optional[dict] = None):
     """The application factory.
 
@@ -100,6 +122,7 @@ def create_app(config: Optional[dict] = None):
             # Silently ignore secrets if the file does not exist.
             app.config.from_pyfile(secretsfile)
     app.config.update(config) # Override everything with passed in config
+    update_unspecified_defaults(app)
     ### END: Application configuration
 
     app.config["SESSION_CACHELIB"] = FileSystemCache(
diff --git a/uploader/background_jobs.py b/uploader/background_jobs.py
index 4e1cd13..a71dd44 100644
--- a/uploader/background_jobs.py
+++ b/uploader/background_jobs.py
@@ -1,38 +1,51 @@
 """Generic views and utilities to handle background jobs."""
 import uuid
+import datetime
 import importlib
 from typing import Callable
 from functools import partial
 
 from werkzeug.wrappers.response import Response
 from flask import (
+    flash,
+    request,
     redirect,
     Blueprint,
-    render_template,
     current_app as app)
 
 from gn_libs import jobs
 from gn_libs import sqlite3
 from gn_libs.jobs.jobs import JobNotFound
 
-
-from uploader.sui import sui_template
-
-from uploader.flask_extensions import url_for
+from uploader import session
 from uploader.authorisation import require_login
+from uploader.flask_extensions import url_for, render_template
 
 background_jobs_bp = Blueprint("background-jobs", __name__)
 HandlerType = Callable[[dict], Response]
 
 
-def __default_error_handler__(job: dict) -> Response:
-    return redirect(url_for("background-jobs.job_error", job_id=job["job_id"]))
+def make_datetime_formatter(dtformat: str = "%A, %d %B %Y at %H:%M %Z") -> Callable[[str], str]:
+    """Make a datetime formatter with the provided `dtformat`"""
+    def __formatter__(val: str) -> str:
+        dt = datetime.datetime.fromisoformat(val)
+        return dt.strftime(dtformat.strip())
+
+    return __formatter__
+
+__default_datetime_formatter__ = make_datetime_formatter()
+
+
+def __default_handler__(_job):
+    return render_template("background-jobs/job-summary.html",
+                           job=_job,
+                           display_datetime=__default_datetime_formatter__)
 
 def register_handlers(
         job_type: str,
         success_handler: HandlerType,
         # pylint: disable=[redefined-outer-name]
-        error_handler: HandlerType = __default_error_handler__
+        error_handler: HandlerType = __default_handler__
         # pylint: disable=[redefined-outer-name]
 ) -> str:
     """Register success and error handlers for each job type."""
@@ -64,7 +77,7 @@ def register_job_handlers(job: dict):
         try:
             _error_handler = __load_handler__(metadata["error_handler"])
         except Exception as _exc:# pylint: disable=[broad-exception-caught]
-            _error_handler = __default_error_handler__
+            _error_handler = __default_handler__
         register_handlers(
             metadata["job-type"], _success_handler, _error_handler)
 
@@ -80,11 +93,7 @@ def handler(job: dict, handler_type: str) -> HandlerType:
     if bool(_handler):
         return _handler(job)
 
-    def __default_success_handler__(_job):
-        return render_template(
-            sui_template("background-jobs/default-success-page.html"), job=_job)
-
-    return __default_success_handler__
+    return __default_handler__(job)
 
 
 error_handler = partial(handler, handler_type="error")
@@ -101,17 +110,17 @@ def job_status(job_id: uuid.UUID):
             status = job["metadata"]["status"]
 
             register_job_handlers(job)
-            if status == "error":
+            if status in ("error", "stopped"):
                 return error_handler(job)
 
             if status == "completed":
                 return success_handler(job)
 
-            return render_template(sui_template("jobs/job-status.html"), job=job)
+            return render_template("background-jobs/job-status.html",
+                                   job=job,
+                                   display_datetime=__default_datetime_formatter__)
         except JobNotFound as _jnf:
-            return render_template(
-                sui_template("jobs/job-not-found.html"),
-                job_id=job_id)
+            return render_template("jobs/job-not-found.html", job_id=job_id)
 
 
 @background_jobs_bp.route("/error/<uuid:job_id>")
@@ -121,7 +130,96 @@ def job_error(job_id: uuid.UUID):
     with sqlite3.connection(app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]) as conn:
         try:
             job = jobs.job(conn, job_id, fulldetails=True)
-            return render_template(sui_template("jobs/job-error.html"), job=job)
+            return render_template("jobs/job-error.html", job=job)
+        except JobNotFound as _jnf:
+            return render_template("jobs/job-not-found.html", job_id=job_id)
+
+
+@background_jobs_bp.route("/list")
+@require_login
+def list_jobs():
+    """List background jobs."""
+    with sqlite3.connection(app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]) as conn:
+        return render_template(
+            "background-jobs/list-jobs.html",
+            jobs=jobs.jobs_by_external_id(
+                conn, session.user_details()["user_id"]),
+            display_datetime=__default_datetime_formatter__)
+
+
+@background_jobs_bp.route("/summary/<uuid:job_id>")
+@require_login
+def job_summary(job_id: uuid.UUID):
+    """Provide a summary for completed jobs."""
+    with sqlite3.connection(app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]) as conn:
+        try:
+            job = jobs.job(conn, job_id, fulldetails=True)
+            status = job["metadata"]["status"]
+
+            if status in ("completed", "error", "stopped"):
+                return render_template("background-jobs/job-summary.html",
+                                       job=job,
+                                       display_datetime=__default_datetime_formatter__)
+            return redirect(url_for(
+                "background-jobs.job_status", job_id=job["job_id"]))
+        except JobNotFound as _jnf:
+            return render_template("jobs/job-not-found.html", job_id=job_id)
+
+
+@background_jobs_bp.route("/delete/<uuid:job_id>", methods=["GET", "POST"])
+@require_login
+def delete_single(job_id: uuid.UUID):
+    """Delete a single job."""
+    with sqlite3.connection(app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]) as conn:
+        try:
+            job = jobs.job(conn, job_id, fulldetails=True)
+            status = job["metadata"]["status"]
+            if status not in ("completed", "error", "stopped"):
+                flash("We cannot delete a running job.", "alert alert-danger")
+                return redirect(url_for(
+                    "background-jobs.job_summary", job_id=job_id))
+
+            if request.method == "GET":
+                return render_template("background-jobs/delete-job.html",
+                                       job=job,
+                                       display_datetime=__default_datetime_formatter__)
+
+            if request.form["btn-confirm-delete"] == "delete":
+                jobs.delete_job(conn, job_id)
+                flash("Job was deleted successfully.", "alert alert-success")
+                return redirect(url_for("background-jobs.list_jobs"))
+            flash("Delete cancelled.", "alert alert-info")
+            return redirect(url_for(
+                "background-jobs.job_summary", job_id=job_id))
+        except JobNotFound as _jnf:
+            return render_template("jobs/job-not-found.html", job_id=job_id)
+
+
+@background_jobs_bp.route("/stop/<uuid:job_id>", methods=["GET", "POST"])
+@require_login
+def stop_job(job_id: uuid.UUID):
+    """Stop a running job."""
+    with sqlite3.connection(app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]) as conn:
+        try:
+            job = jobs.job(conn, job_id, fulldetails=True)
+            status = job["metadata"]["status"]
+            if status != "running":
+                flash("Cannot stop a job that is not running.", "alert alert-danger")
+                return redirect(url_for(
+                    "background-jobs.job_summary", job_id=job_id))
+
+            if request.method == "GET":
+                return render_template("background-jobs/stop-job.html",
+                                       job=job,
+                                       display_datetime=__default_datetime_formatter__)
+
+            if request.form["btn-confirm-stop"] == "stop":
+                jobs.kill_job(conn, job_id)
+                flash("Job was stopped successfully.", "alert alert-success")
+                return redirect(url_for(
+                    "background-jobs.job_summary", job_id=job_id))
+            flash("Stop cancelled.", "alert alert-info")
+            return redirect(url_for(
+                "background-jobs.job_summary", job_id=job_id))
         except JobNotFound as _jnf:
-            return render_template(sui_template("jobs/job-not-found.html"),
-                                   job_id=job_id)
+            return render_template("jobs/job-not-found.html", job_id=job_id)
diff --git a/uploader/base_routes.py b/uploader/base_routes.py
index e9f1165..72a8402 100644
--- a/uploader/base_routes.py
+++ b/uploader/base_routes.py
@@ -11,12 +11,8 @@ from flask import (flash,
                    current_app as app,
                    send_from_directory)
 
-
-from uploader.sui import sui_template
-
 from uploader.flask_extensions import url_for
 from uploader.ui import make_template_renderer
-from uploader.oauth2.client import user_logged_in
 from uploader.species.models import all_species, species_by_id
 
 base = Blueprint("base", __name__)
@@ -40,10 +36,11 @@ def index():
         print("We found a species ID. Processing...")
         if not bool(request.args.get("species_id")):
             return render_template(
-                sui_template("index.html" if user_logged_in() else "login.html"),
+                "index.html",
                 gn2server_intro=urljoin(app.config["GN2_SERVER_URL"], "/intro"),
                 species=all_species(conn),
-                streamlined_ui=streamlined_ui)
+                view_under_construction=request.args.get(
+                    "view_under_construction", False))
 
         species = species_by_id(conn, request.args.get("species_id"))
         if not bool(species):
diff --git a/uploader/configutils.py b/uploader/configutils.py
new file mode 100644
index 0000000..c5db50b
--- /dev/null
+++ b/uploader/configutils.py
@@ -0,0 +1,13 @@
+"""Functions to fetch settings."""
+from pathlib import Path
+
+def fetch_setting(app, setting):
+    """Fetch a specified configuration `setting` from the `app` object."""
+    return app.config[setting]
+
+def uploads_dir(app) -> Path:
+    """Fetch the uploads directory"""
+    _dir = Path(fetch_setting(app, "UPLOADS_DIRECTORY")).absolute()
+    assert _dir.exists() and _dir.is_dir(), (
+        f"'{_dir}' needs to be an existing directory.")
+    return _dir
diff --git a/uploader/default_settings.py b/uploader/default_settings.py
index 52cdad5..6381a67 100644
--- a/uploader/default_settings.py
+++ b/uploader/default_settings.py
@@ -5,8 +5,14 @@ actual configuration file used for the production and staging systems.
 
 LOG_LEVEL = "WARNING"
 SECRET_KEY = b"<Please! Please! Please! Change This!>"
-UPLOAD_FOLDER = "/tmp/qc_app_files"
-TEMPORARY_DIRECTORY = "/tmp/gn-uploader-tmpdir"
+
+# Scratch directory and uploads:
+# *** The scratch directory ***
+# We avoid `/tmp` entirely for the scratch directory to avoid shared global
+# mutable state with other users/applications/processes.
+SCRATCH_DIRECTORY = "~/tmp/gn-uploader-scratchdir"
+UPLOADS_DIRECTORY = ""# If not set, will be under scratch directory.
+
 REDIS_URL = "redis://"
 JOBS_TTL_SECONDS = 1209600 # 14 days
 GNQC_REDIS_PREFIX="gn-uploader"
diff --git a/uploader/errors.py b/uploader/errors.py
index 3e7c893..2ac48b8 100644
--- a/uploader/errors.py
+++ b/uploader/errors.py
@@ -3,7 +3,8 @@ import traceback
 from werkzeug.exceptions import HTTPException
 
 import MySQLdb as mdb
-from flask import Flask, request, render_template, current_app as app
+from flask import Flask, request, current_app as app
+from uploader.flask_extensions import render_template
 
 def handle_general_exception(exc: Exception):
     """Handle generic exceptions."""
diff --git a/uploader/files/chunks.py b/uploader/files/chunks.py
index c4360b5..f63f32f 100644
--- a/uploader/files/chunks.py
+++ b/uploader/files/chunks.py
@@ -5,6 +5,8 @@ from typing import Iterator
 from flask import current_app as app
 from werkzeug.utils import secure_filename
 
+from uploader.configutils import uploads_dir
+
 
 def chunked_binary_read(filepath: Path, chunksize: int = 2048) -> Iterator:
     """Read a file in binary mode in chunks."""
@@ -29,4 +31,4 @@ def chunks_directory(uniqueidentifier: str) -> Path:
     """Compute the directory where chunks are temporarily stored."""
     if uniqueidentifier == "":
         raise ValueError("Unique identifier cannot be empty!")
-    return Path(app.config["UPLOAD_FOLDER"], f"tempdir_{uniqueidentifier}")
+    return Path(uploads_dir(app), f"tempdir_{uniqueidentifier}")
diff --git a/uploader/files/functions.py b/uploader/files/functions.py
index 7b9f06b..68f4e16 100644
--- a/uploader/files/functions.py
+++ b/uploader/files/functions.py
@@ -8,6 +8,8 @@ from flask import current_app
 from werkzeug.utils import secure_filename
 from werkzeug.datastructures import FileStorage
 
+from uploader.configutils import uploads_dir
+
 from .chunks import chunked_binary_read
 
 def save_file(fileobj: FileStorage, upload_dir: Path, hashed: bool = True) -> Path:
@@ -30,7 +32,7 @@ def save_file(fileobj: FileStorage, upload_dir: Path, hashed: bool = True) -> Pa
 
 def fullpath(filename: str):
     """Get a file's full path. This makes use of `flask.current_app`."""
-    return Path(current_app.config["UPLOAD_FOLDER"], filename).absolute()
+    return Path(uploads_dir(current_app), filename).absolute()
 
 
 def sha256_digest_over_file(filepath: Path) -> str:
diff --git a/uploader/files/views.py b/uploader/files/views.py
index 29059c7..ea0e827 100644
--- a/uploader/files/views.py
+++ b/uploader/files/views.py
@@ -6,13 +6,15 @@ from pathlib import Path
 
 from flask import request, jsonify, Blueprint, current_app as app
 
+from uploader.configutils import uploads_dir
+
 from .chunks import chunk_name, chunks_directory
 
 files = Blueprint("files", __name__)
 
 def target_file(fileid: str) -> Path:
     """Compute the full path for the target file."""
-    return Path(app.config["UPLOAD_FOLDER"], fileid)
+    return Path(uploads_dir(app), fileid)
 
 
 @files.route("/upload/resumable", methods=["GET"])
diff --git a/uploader/flask_extensions.py b/uploader/flask_extensions.py
index 30fbad7..83d25aa 100644
--- a/uploader/flask_extensions.py
+++ b/uploader/flask_extensions.py
@@ -2,19 +2,16 @@
 import logging
 from typing import Any, Optional
 
-from flask import (request, current_app as app, url_for as flask_url_for)
+from flask import (
+    request,
+    current_app as app,
+    url_for as flask_url_for,
+    render_template as flask_render_template)
 
 logger = logging.getLogger(__name__)
 
 
-def url_for(
-        endpoint: str,
-        _anchor: Optional[str] = None,
-        _method: Optional[str] = None,
-        _scheme: Optional[str] = None,
-        _external: Optional[bool] = None,
-        **values: Any) -> str:
-    """Extension to flask's `url_for` function."""
+def __fetch_flags__():
     flags = {}
     for flag in app.config["FEATURE_FLAGS_HTTP"]:
         flag_value = (request.args.get(flag) or request.form.get(flag) or "").strip()
@@ -22,12 +19,33 @@ def url_for(
             flags[flag] = flag_value
             continue
         continue
+    logger.debug("HTTP FEATURE FLAGS: %s", flags)
+    return flags
 
-    logger.debug("HTTP FEATURE FLAGS: %s, other variables: %s", flags, values)
+
+def url_for(
+        endpoint: str,
+        _anchor: Optional[str] = None,
+        _method: Optional[str] = None,
+        _scheme: Optional[str] = None,
+        _external: Optional[bool] = None,
+        **values: Any) -> str:
+    """Extension to flask's `url_for` function."""
+    logger.debug("other variables: %s", values)
     return flask_url_for(endpoint=endpoint,
                          _anchor=_anchor,
                          _method=_method,
                          _scheme=_scheme,
                          _external=_external,
                          **values,
-                         **flags)
+                         **__fetch_flags__())
+
+
+def render_template(template_name_or_list, **context: Any) -> str:
+    """Extend flask's `render_template` function"""
+    return flask_render_template(
+        template_name_or_list,
+        **{
+            **context,
+            **__fetch_flags__() # override any flag values
+        })
diff --git a/uploader/phenotypes/models.py b/uploader/phenotypes/models.py
index 7c051d7..06c417f 100644
--- a/uploader/phenotypes/models.py
+++ b/uploader/phenotypes/models.py
@@ -1,4 +1,6 @@
 """Database and utility functions for phenotypes."""
+import time
+import random
 import logging
 import tempfile
 from pathlib import Path
@@ -6,8 +8,8 @@ from functools import reduce
 from datetime import datetime
 from typing import Union, Optional, Iterable
 
-import MySQLdb as mdb
-from MySQLdb.cursors import Cursor, DictCursor
+from MySQLdb.connections import Connection
+from MySQLdb.cursors import Cursor, DictCursor, BaseCursor
 
 from gn_libs.mysqldb import debug_query
 
@@ -27,7 +29,7 @@ __PHENO_DATA_TABLES__ = {
 
 
 def datasets_by_population(
-        conn: mdb.Connection,
+        conn: Connection,
         species_id: int,
         population_id: int
 ) -> tuple[dict, ...]:
@@ -42,7 +44,7 @@ def datasets_by_population(
         return tuple(dict(row) for row in cursor.fetchall())
 
 
-def dataset_by_id(conn: mdb.Connection,
+def dataset_by_id(conn: Connection,
                   species_id: int,
                   population_id: int,
                   dataset_id: int) -> dict:
@@ -57,7 +59,7 @@ def dataset_by_id(conn: mdb.Connection,
         return dict(cursor.fetchone())
 
 
-def phenotypes_count(conn: mdb.Connection,
+def phenotypes_count(conn: Connection,
                      population_id: int,
                      dataset_id: int) -> int:
     """Count the number of phenotypes in the dataset."""
@@ -85,11 +87,14 @@ def phenotype_publication_data(conn, phenotype_id) -> Optional[dict]:
         return dict(res)
 
 
-def dataset_phenotypes(conn: mdb.Connection,
-                       population_id: int,
-                       dataset_id: int,
-                       offset: int = 0,
-                       limit: Optional[int] = None) -> tuple[dict, ...]:
+def dataset_phenotypes(
+        conn: Connection,
+        population_id: int,
+        dataset_id: int,
+        offset: int = 0,
+        limit: Optional[int] = None,
+        xref_ids: tuple[int, ...] = tuple()
+) -> tuple[dict, ...]:
     """Fetch the actual phenotypes."""
     _query = (
         "SELECT pheno.*, pxr.Id AS xref_id, pxr.InbredSetId, ist.InbredSetCode "
@@ -98,14 +103,16 @@ def dataset_phenotypes(conn: mdb.Connection,
         "INNER JOIN PublishFreeze AS pf ON pxr.InbredSetId=pf.InbredSetId "
         "INNER JOIN InbredSet AS ist ON pf.InbredSetId=ist.Id "
         "WHERE pxr.InbredSetId=%s AND pf.Id=%s") + (
+            f" AND pxr.Id IN ({', '.join(['%s'] * len(xref_ids))})"
+            if len(xref_ids) > 0 else "") + (
             f" LIMIT {limit} OFFSET {offset}" if bool(limit) else "")
     with conn.cursor(cursorclass=DictCursor) as cursor:
-        cursor.execute(_query, (population_id, dataset_id))
+        cursor.execute(_query, (population_id, dataset_id) + xref_ids)
         debug_query(cursor, logger)
         return tuple(dict(row) for row in cursor.fetchall())
 
 
-def __phenotype_se__(cursor: Cursor, xref_id, dataids_and_strainids):
+def __phenotype_se__(cursor: BaseCursor, xref_id, dataids_and_strainids):
     """Fetch standard-error values (if they exist) for a phenotype."""
     paramstr = ", ".join(["(%s, %s)"] * len(dataids_and_strainids))
     flat = tuple(item for sublist in dataids_and_strainids for item in sublist)
@@ -187,7 +194,7 @@ def __merge_pheno_data_and_se__(data, sedata) -> dict:
 
 
 def phenotype_by_id(
-        conn: mdb.Connection,
+        conn: Connection,
         species_id: int,
         population_id: int,
         dataset_id: int,
@@ -225,7 +232,7 @@ def phenotype_by_id(
     return None
 
 
-def phenotypes_data(conn: mdb.Connection,
+def phenotypes_data(conn: Connection,
                     population_id: int,
                     dataset_id: int,
                     offset: int = 0,
@@ -249,7 +256,7 @@ def phenotypes_data(conn: mdb.Connection,
 
 
 def phenotypes_vector_data(# pylint: disable=[too-many-arguments, too-many-positional-arguments]
-        conn: mdb.Connection,
+        conn: Connection,
         species_id: int,
         population_id: int,
         xref_ids: tuple[int, ...] = tuple(),
@@ -301,7 +308,7 @@ def phenotypes_vector_data(# pylint: disable=[too-many-arguments, too-many-posit
         return reduce(__organise__, cursor.fetchall(), {})
 
 
-def save_new_dataset(cursor: Cursor,
+def save_new_dataset(cursor: BaseCursor,
                      population_id: int,
                      dataset_name: str,
                      dataset_fullname: str,
@@ -328,35 +335,6 @@ def save_new_dataset(cursor: Cursor,
     return {**params, "Id": cursor.lastrowid}
 
 
-def phenotypes_data_by_ids(
-        conn: mdb.Connection,
-        inbred_pheno_xref: dict[str, int]
-) -> tuple[dict, ...]:
-    """Fetch all phenotype data, filtered by the `inbred_pheno_xref` mapping."""
-    _paramstr = ",".join(["(%s, %s, %s)"] * len(inbred_pheno_xref))
-    _query = ("SELECT "
-              "pub.PubMed_ID, pheno.*, pxr.*, pd.*, str.*, iset.InbredSetCode "
-              "FROM Publication AS pub "
-              "RIGHT JOIN PublishXRef AS pxr0 ON pub.Id=pxr0.PublicationId "
-              "INNER JOIN Phenotype AS pheno ON pxr0.PhenotypeId=pheno.id "
-              "INNER JOIN PublishXRef AS pxr ON pheno.Id=pxr.PhenotypeId "
-              "INNER JOIN PublishData AS pd ON pxr.DataId=pd.Id "
-              "INNER JOIN Strain AS str ON pd.StrainId=str.Id "
-              "INNER JOIN StrainXRef AS sxr ON str.Id=sxr.StrainId "
-              "INNER JOIN PublishFreeze AS pf ON sxr.InbredSetId=pf.InbredSetId "
-              "INNER JOIN InbredSet AS iset ON pf.InbredSetId=iset.InbredSetId "
-              f"WHERE (pxr.InbredSetId, pheno.Id, pxr.Id) IN ({_paramstr}) "
-              "ORDER BY pheno.Id")
-    with conn.cursor(cursorclass=DictCursor) as cursor:
-        cursor.execute(_query, tuple(item for row in inbred_pheno_xref
-                                     for item in (row["population_id"],
-                                                  row["phenoid"],
-                                                  row["xref_id"])))
-        debug_query(cursor, logger)
-        return tuple(
-            reduce(__organise_by_phenotype__, cursor.fetchall(), {}).values())
-
-
 def __pre_process_phenotype_data__(row):
     _desc = row.get("description", "")
     _pre_pub_desc = row.get("pre_publication_description", _desc)
@@ -375,7 +353,7 @@ def __pre_process_phenotype_data__(row):
 
 
 def create_new_phenotypes(# pylint: disable=[too-many-locals]
-        conn: mdb.Connection,
+        conn: Connection,
         population_id: int,
         publication_id: int,
         phenotypes: Iterable[dict]
@@ -503,7 +481,7 @@ def create_new_phenotypes(# pylint: disable=[too-many-locals]
 
 
 def save_phenotypes_data(
-        conn: mdb.Connection,
+        conn: Connection,
         table: str,
         data: Iterable[dict]
 ) -> int:
@@ -533,7 +511,7 @@ def save_phenotypes_data(
 
 
 def quick_save_phenotypes_data(
-        conn: mdb.Connection,
+        conn: Connection,
         table: str,
         dataitems: Iterable[dict],
         tmpdir: Path
@@ -563,3 +541,134 @@ def quick_save_phenotypes_data(
             ")")
         debug_query(cursor, logger)
         return _count
+
+
+def __sleep_random__():
+    """Sleep a random amount of time chosen from 0.05s to 1s in increments of 0.05"""
+    time.sleep(random.choice(tuple(i / 20.0 for i in range(1, 21))))
+
+
+def delete_phenotypes_data(
+        cursor: BaseCursor,
+        data_ids: tuple[int, ...]
+) -> tuple[int, int, int]:
+    """Delete numeric data for phenotypes with the given data IDs."""
+    if len(data_ids) == 0:
+        return (0, 0, 0)
+
+    # Loop to handle big deletes i.e. ≥ 10000 rows
+    _dcount, _secount, _ncount = (0, 0, 0)# Count total rows deleted
+    while True:
+        _paramstr = ", ".join(["%s"] * len(data_ids))
+        cursor.execute(
+            "DELETE FROM PublishData "
+            f"WHERE Id IN ({_paramstr}) "
+            "ORDER BY Id ASC, StrainId ASC "# Make deletions deterministic
+            "LIMIT 1000",
+            data_ids)
+        _dcount_curr = cursor.rowcount
+        _dcount += _dcount_curr
+
+        cursor.execute(
+            "DELETE FROM PublishSE "
+            f"WHERE DataId IN ({_paramstr}) "
+            "ORDER BY DataId ASC, StrainId ASC "# Make deletions deterministic
+            "LIMIT 1000",
+            data_ids)
+        _secount_curr = cursor.rowcount
+        _secount += _secount_curr
+
+        cursor.execute(
+            "DELETE FROM NStrain "
+            f"WHERE DataId IN ({_paramstr}) "
+            "ORDER BY DataId ASC, StrainId ASC "# Make deletions deterministic
+            "LIMIT 1000",
+            data_ids)
+        _ncount_curr = cursor.rowcount
+        _ncount += _ncount_curr
+        __sleep_random__()
+
+        if all((_dcount_curr == 0, _secount_curr == 0, _ncount_curr == 0)):
+            # end loop if there are no more rows to delete.
+            break
+
+    return (_dcount, _secount, _ncount)
+
+
+def __linked_ids__(
+        cursor: BaseCursor,
+        population_id: int,
+        xref_ids: tuple[int, ...]
+) -> tuple[tuple[int, int, int], ...]:
+    """Retrieve `DataId` values from `PublishXRef` table."""
+    _paramstr = ", ".join(["%s"] * len(xref_ids))
+    cursor.execute("SELECT PhenotypeId, PublicationId, DataId "
+                   "FROM PublishXRef "
+                   f"WHERE InbredSetId=%s AND Id IN ({_paramstr})",
+                   (population_id,) + xref_ids)
+    return tuple(
+        (int(row["PhenotypeId"]), int(row["PublicationId"]), int(row["DataId"]))
+        for row in cursor.fetchall())
+
+
+def delete_phenotypes(
+        conn_or_cursor: Union[Connection, Cursor],
+        population_id: int,
+        xref_ids: tuple[int, ...]
+) -> tuple[int, int, int, int]:
+    """Delete phenotypes and all their data."""
+    def __delete_phenos__(cursor: BaseCursor, pheno_ids: tuple[int, ...]) -> int:
+        """Delete data from the `Phenotype` table."""
+        _paramstr = ", ".join(["%s"] * len(pheno_ids))
+
+        _pcount = 0
+        while True:
+            cursor.execute(
+                "DELETE FROM Phenotype "
+                f"WHERE Id IN ({_paramstr}) "
+                "ORDER BY Id "
+                "LIMIT 1000",
+                pheno_ids)
+            _pcount_curr = cursor.rowcount
+            _pcount += _pcount_curr
+            __sleep_random__()
+            if _pcount_curr == 0:
+                break
+
+        return cursor.rowcount
+
+    def __delete_xrefs__(cursor: BaseCursor) -> int:
+        _paramstr = ", ".join(["%s"] * len(xref_ids))
+
+        _xcount = 0
+        while True:
+            cursor.execute(
+                "DELETE FROM PublishXRef "
+                f"WHERE InbredSetId=%s AND Id IN ({_paramstr}) "
+                "ORDER BY Id "
+                "LIMIT 10000",
+                (population_id,) + xref_ids)
+            _xcount_curr = cursor.rowcount
+            _xcount += _xcount_curr
+            __sleep_random__()
+            if _xcount_curr == 0:
+                break
+
+        return _xcount
+
+    def __with_cursor__(cursor):
+        _phenoids, _pubids, _dataids = reduce(
+            lambda acc, curr: (acc[0] + (curr[0],),
+                               acc[1] + (curr[1],),
+                               acc[2] + (curr[2],)),
+            __linked_ids__(cursor, population_id, xref_ids),
+            (tuple(), tuple(), tuple()))
+        __delete_phenos__(cursor, _phenoids)
+        return (__delete_xrefs__(cursor),) + delete_phenotypes_data(
+            cursor, _dataids)
+
+    if isinstance(conn_or_cursor, BaseCursor):
+        return __with_cursor__(conn_or_cursor)
+
+    with conn_or_cursor.cursor(cursorclass=DictCursor) as cursor:
+        return __with_cursor__(cursor)
diff --git a/uploader/phenotypes/views.py b/uploader/phenotypes/views.py
index 42f2e34..776fa52 100644
--- a/uploader/phenotypes/views.py
+++ b/uploader/phenotypes/views.py
@@ -31,12 +31,10 @@ from flask import (flash,
 from r_qtl import r_qtl2_qc as rqc
 from r_qtl import exceptions as rqe
 
-
-from uploader.sui import sui_template
-
 from uploader import jobs
 from uploader import session
 from uploader.files import save_file
+from uploader.configutils import uploads_dir
 from uploader.flask_extensions import url_for
 from uploader.ui import make_template_renderer
 from uploader.oauth2.client import oauth2_post
@@ -197,7 +195,7 @@ def view_dataset(# pylint: disable=[unused-argument]
 
         start_at = max(safe_int(request.args.get("start_at") or 0), 0)
         count = int(request.args.get("count") or 20)
-        return render_template(sui_template("phenotypes/view-dataset.html"),
+        return render_template("phenotypes/view-dataset.html",
                                species=species,
                                population=population,
                                dataset=dataset,
@@ -332,7 +330,7 @@ def process_phenotypes_rqtl2_bundle(error_uri):
     try:
         ## Handle huge files here...
         phenobundle = save_file(request.files["phenotypes-bundle"],
-                                Path(app.config["UPLOAD_FOLDER"]))
+                                uploads_dir(app))
         rqc.validate_bundle(phenobundle)
         return phenobundle
     except AssertionError as _aerr:
@@ -355,7 +353,7 @@ def process_phenotypes_individual_files(error_uri):
         "comment.char": form["file-comment-character"],
         "na.strings": form["file-na"].split(" "),
     }
-    bundlepath = Path(app.config["UPLOAD_FOLDER"],
+    bundlepath = Path(uploads_dir(app),
                       f"{str(uuid.uuid4()).replace('-', '')}.zip")
     with ZipFile(bundlepath,mode="w") as zfile:
         for rqtlkey, formkey, _type in (
@@ -373,7 +371,7 @@ def process_phenotypes_individual_files(error_uri):
                 # Chunked upload of large files was used
                 filedata = json.loads(form[formkey])
                 zfile.write(
-                    Path(app.config["UPLOAD_FOLDER"], filedata["uploaded-file"]),
+                    Path(uploads_dir(app), filedata["uploaded-file"]),
                     arcname=filedata["original-name"])
                 cdata[rqtlkey] = cdata.get(rqtlkey, []) + [filedata["original-name"]]
             else:
@@ -385,9 +383,9 @@ def process_phenotypes_individual_files(error_uri):
                     return error_uri
 
                 filepath = save_file(
-                    _sentfile, Path(app.config["UPLOAD_FOLDER"]), hashed=False)
+                    _sentfile, uploads_dir(app), hashed=False)
                 zfile.write(
-                    Path(app.config["UPLOAD_FOLDER"], filepath),
+                    Path(uploads_dir(app), filepath),
                     arcname=filepath.name)
                 cdata[rqtlkey] = cdata.get(rqtlkey, []) + [filepath.name]
 
@@ -420,9 +418,9 @@ def add_phenotypes(species: dict, population: dict, dataset: dict, **kwargs):# p
         if request.method == "GET":
             today = datetime.date.today()
             return render_template(
-                sui_template("phenotypes/add-phenotypes-with-rqtl2-bundle.html"
-                             if use_bundle
-                             else "phenotypes/add-phenotypes-raw-files.html"),
+                ("phenotypes/add-phenotypes-with-rqtl2-bundle.html"
+                 if use_bundle
+                 else "phenotypes/add-phenotypes-raw-files.html"),
                 species=species,
                 population=population,
                 dataset=dataset,
@@ -467,7 +465,7 @@ def add_phenotypes(species: dict, population: dict, dataset: dict, **kwargs):# p
                     **({"publicationid": request.form["publication-id"]}
                        if request.form.get("publication-id") else {})})}),
             _redisuri,
-            f"{app.config['UPLOAD_FOLDER']}/job_errors")
+            f"{uploads_dir(app)}/job_errors")
 
         app.logger.debug("JOB DETAILS: %s", _job)
         jobstatusuri = url_for("species.populations.phenotypes.job_status",
@@ -509,7 +507,7 @@ def job_status(
         except jobs.JobNotFound as _jnf:
             job = None
 
-        return render_template(sui_template("phenotypes/job-status.html"),
+        return render_template("phenotypes/job-status.html",
                                species=species,
                                population=population,
                                dataset=dataset,
@@ -589,7 +587,7 @@ def review_job_data(
             for filetype,meta in metadata.items()
         }
         _job_metadata = json.loads(job["job-metadata"])
-        return render_template(sui_template("phenotypes/review-job-data.html"),
+        return render_template("phenotypes/review-job-data.html",
                                species=species,
                                population=population,
                                dataset=dataset,
@@ -614,6 +612,11 @@ def load_phenotypes_success_handler(job):
         job_id=job["job_id"]))
 
 
+def proceed_to_job_status(job):
+    app.logger.debug("The new job: %s", job)
+    return redirect(url_for("background-jobs.job_status", job_id=job["job_id"]))
+
+
 @phenotypesbp.route(
     "<int:species_id>/populations/<int:population_id>/phenotypes/datasets"
     "/<int:dataset_id>/load-data-to-database",
@@ -656,11 +659,6 @@ def load_data_to_database(
         def __handle_error__(resp):
             return render_template("http-error.html", *resp.json())
 
-        def __handle_success__(load_job):
-            app.logger.debug("The phenotypes loading job: %s", load_job)
-            return redirect(url_for(
-                "background-jobs.job_status", job_id=load_job["job_id"]))
-
 
         return request_token(
             token_uri=urljoin(oauth2client.authserver_uri(), "auth/token"),
@@ -682,15 +680,16 @@ def load_data_to_database(
                     "success_handler": (
                         "uploader.phenotypes.views"
                         ".load_phenotypes_success_handler")
-                })
+                },
+                external_id=session.logged_in_user_id())
         ).then(
             lambda job: gnlibs_jobs.launch_job(
                 job,
                 _jobs_db,
-                Path(f"{app.config['UPLOAD_FOLDER']}/job_errors"),
+                Path(f"{uploads_dir(app)}/job_errors"),
                 worker_manager="gn_libs.jobs.launcher",
                 loglevel=_loglevel)
-        ).either(__handle_error__, __handle_success__)
+        ).either(__handle_error__, proceed_to_job_status)
 
 
 def update_phenotype_metadata(conn, metadata: dict):
@@ -980,7 +979,7 @@ def load_data_success(
                               (_publication["Title"] or ""))
                              if item != "")
             return render_template(
-                sui_template("phenotypes/load-phenotypes-success.html"),
+                "phenotypes/load-phenotypes-success.html",
                 species=species,
                 population=population,
                 dataset=dataset,
@@ -1062,9 +1061,10 @@ def recompute_means(# pylint: disable=[unused-argument]
                     "success_handler": (
                         "uploader.phenotypes.views."
                         "recompute_phenotype_means_success_handler")
-            }),
+                },
+                external_id=session.logged_in_user_id()),
             _jobs_db,
-            Path(f"{app.config['UPLOAD_FOLDER']}/job_errors"),
+            Path(f"{uploads_dir(app)}/job_errors"),
             worker_manager="gn_libs.jobs.launcher",
             loglevel=_loglevel)
         return redirect(url_for("background-jobs.job_status",
@@ -1106,7 +1106,7 @@ def rerun_qtlreaper(# pylint: disable=[unused-argument]
     _job_id = uuid.uuid4()
     _loglevel = logging.getLevelName(app.logger.getEffectiveLevel()).lower()
 
-    _workingdir = Path(app.config["TEMPORARY_DIRECTORY"]).joinpath("qtlreaper")
+    _workingdir = Path(app.config["SCRATCH_DIRECTORY"]).joinpath("qtlreaper")
     _workingdir.mkdir(exist_ok=True)
     command = [
         sys.executable,
@@ -1141,9 +1141,10 @@ def rerun_qtlreaper(# pylint: disable=[unused-argument]
                     "success_handler": (
                         "uploader.phenotypes.views."
                         "rerun_qtlreaper_success_handler")
-            }),
+            },
+            external_id=session.logged_in_user_id()),
             _jobs_db,
-            Path(f"{app.config['UPLOAD_FOLDER']}/job_errors"),
+            Path(f"{uploads_dir(app)}/job_errors"),
             worker_manager="gn_libs.jobs.launcher",
             loglevel=_loglevel)
         return redirect(url_for("background-jobs.job_status",
@@ -1155,3 +1156,119 @@ def rerun_qtlreaper(# pylint: disable=[unused-argument]
 def rerun_qtlreaper_success_handler(job):
     """Handle success (re)running QTLReaper script."""
     return return_to_dataset_view_handler(job, "QTLReaper ran successfully!")
+
+
+def delete_phenotypes_success_handler(job):
+    """Handle success running the 'delete-phenotypes' script."""
+    return return_to_dataset_view_handler(
+        job, "Phenotypes deleted successfully.")
+
+
+@phenotypesbp.route(
+    "<int:species_id>/populations/<int:population_id>/phenotypes/datasets"
+    "/<int:dataset_id>/delete",
+    methods=["GET", "POST"])
+@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 delete_phenotypes(# pylint: disable=[unused-argument]
+        species: dict,
+        population: dict,
+        dataset: dict,
+        **kwargs
+):
+    """Delete the specified phenotype data."""
+    _dataset_page = redirect(url_for(
+        "species.populations.phenotypes.view_dataset",
+        species_id=species["SpeciesId"],
+        population_id=population["Id"],
+        dataset_id=dataset["Id"]))
+
+    def __handle_error__(resp):
+        flash(
+            "Error retrieving authorisation token. Phenotype deletion "
+            "failed. Please try again later.",
+            "alert alert-danger")
+        return _dataset_page
+
+    _jobs_db = app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]
+    with (database_connection(app.config["SQL_URI"]) as conn,
+          sqlite3.connection(_jobs_db) as jobsconn):
+        form = request.form
+        xref_ids = tuple(int(item) for item in set(form.getlist("xref_ids")))
+
+        match form.get("action"):
+            case "cancel":
+                return redirect(url_for(
+                    "species.populations.phenotypes.view_dataset",
+                    species_id=species["SpeciesId"],
+                    population_id=population["Id"],
+                    dataset_id=dataset["Id"]))
+            case "delete":
+                _loglevel = logging.getLevelName(
+                    app.logger.getEffectiveLevel()).lower()
+                if form.get("confirm_delete_all_phenotypes", "") == "on":
+                    _cmd = ["--delete-all"]
+                else:
+                    # setup phenotypes xref_ids file
+                    _xref_ids_file = Path(
+                        app.config["SCRATCH_DIRECTORY"],
+                        f"delete-phenotypes-{uuid.uuid4()}.txt")
+                    with _xref_ids_file.open(mode="w", encoding="utf8") as ptr:
+                        ptr.write("\n".join(str(_id) for _id in xref_ids))
+
+                    _cmd = ["--xref_ids_file", str(_xref_ids_file)]
+
+                _job_id = uuid.uuid4()
+                return request_token(
+                    token_uri=urljoin(
+                        oauth2client.authserver_uri(), "auth/token"),
+                    user_id=session.user_details()["user_id"]
+                ).then(
+                    lambda token: gnlibs_jobs.initialise_job(
+                        jobsconn,
+                        _job_id,
+                        [
+                            sys.executable,
+                            "-u",
+                            "-m",
+                            "scripts.phenotypes.delete_phenotypes",
+                            "--log-level", _loglevel,
+                            app.config["SQL_URI"],
+                            str(species["SpeciesId"]),
+                            str(population["Id"]),
+                            str(dataset["Id"]),
+                            app.config["AUTH_SERVER_URL"],
+                            token["access_token"]] + _cmd,
+                        "delete-phenotypes",
+                        extra_meta={
+                            "species_id": species["SpeciesId"],
+                            "population_id": population["Id"],
+                            "dataset_id": dataset["Id"],
+                            "success_handler": (
+                                "uploader.phenotypes.views."
+                                "delete_phenotypes_success_handler")
+                        },
+                        external_id=session.logged_in_user_id())
+                ).then(
+                    lambda _job: gnlibs_jobs.launch_job(
+                        _job,
+                        _jobs_db,
+                        Path(f"{uploads_dir(app)}/job_errors"),
+                        worker_manager="gn_libs.jobs.launcher",
+                        loglevel=_loglevel)
+                ).either(__handle_error__, proceed_to_job_status)
+            case _:
+                _phenos = tuple()
+                if len(xref_ids) > 0:
+                    _phenos = dataset_phenotypes(
+                        conn, population["Id"], dataset["Id"], xref_ids=xref_ids)
+
+                return render_template(
+                    "phenotypes/confirm-delete-phenotypes.html",
+                    species=species,
+                    population=population,
+                    dataset=dataset,
+                    phenotypes=_phenos)
diff --git a/uploader/platforms/views.py b/uploader/platforms/views.py
index 0092760..ba0f0ef 100644
--- a/uploader/platforms/views.py
+++ b/uploader/platforms/views.py
@@ -8,8 +8,6 @@ from flask import (
     Blueprint,
     current_app as app)
 
-from uploader.sui import sui_template
-
 from uploader.flask_extensions import url_for
 from uploader.ui import make_template_renderer
 from uploader.authorisation import require_login
@@ -62,7 +60,7 @@ def list_platforms(species_id: int):
         start_from = max(safe_int(request.args.get("start_from") or 0), 0)
         count = safe_int(request.args.get("count") or 20)
         return render_template(
-            sui_template("platforms/list-platforms.html"),
+            "platforms/list-platforms.html",
             species=species,
             platforms=enumerate_sequence(
                 platforms_by_species(conn,
@@ -89,7 +87,7 @@ def create_platform(species_id: int):
 
         if request.method == "GET":
             return render_template(
-                sui_template("platforms/create-platform.html"),
+                "platforms/create-platform.html",
                 species=species,
                 activelink="create-platform")
 
diff --git a/uploader/population/views.py b/uploader/population/views.py
index caee55b..795ce81 100644
--- a/uploader/population/views.py
+++ b/uploader/population/views.py
@@ -11,8 +11,6 @@ from flask import (flash,
                    Blueprint,
                    current_app as app)
 
-from uploader.sui import sui_template
-
 from uploader.samples.views import samplesbp
 from uploader.flask_extensions import url_for
 from uploader.oauth2.client import oauth2_post
@@ -244,5 +242,4 @@ def view_population(species_id: int, population_id: int):
                     dataset_phenotypes(conn, population["Id"], _dataset["Id"]))
             }
 
-        return render_template(sui_template("populations/view-population.html"),
-                               **_kwargs)
+        return render_template("populations/view-population.html", **_kwargs)
diff --git a/uploader/publications/views.py b/uploader/publications/views.py
index 11732db..d9eb294 100644
--- a/uploader/publications/views.py
+++ b/uploader/publications/views.py
@@ -10,8 +10,6 @@ from flask import (
     render_template,
     current_app as app)
 
-from uploader.sui import sui_template
-
 from uploader.flask_extensions import url_for
 from uploader.authorisation import require_login
 from uploader.route_utils import redirect_to_next
@@ -32,7 +30,7 @@ pubbp = Blueprint("publications", __name__)
 @require_login
 def index():
     """Index page for publications."""
-    return render_template(sui_template("publications/index.html"))
+    return render_template("publications/index.html")
 
 
 @pubbp.route("/list", methods=["GET"])
@@ -74,7 +72,7 @@ def view_publication(publication_id: int):
             return redirect(url_for('publications.index'))
 
         return render_template(
-            sui_template("publications/view-publication.html"),
+            "publications/view-publication.html",
             publication=publication,
             linked_phenotypes=tuple(fetch_publication_phenotypes(
                 conn, publication_id)))
@@ -92,7 +90,7 @@ def create_publication():
 
     if request.method == "GET":
         return render_template(
-            sui_template("publications/create-publication.html"),
+            "publications/create-publication.html",
             get_args=_get_args)
     form = request.form
     authors = form.get("publication-authors").encode("utf8")
@@ -130,7 +128,7 @@ def edit_publication(publication_id: int):
     with database_connection(app.config["SQL_URI"]) as conn:
         if request.method == "GET":
             return render_template(
-                sui_template("publications/edit-publication.html"),
+                "publications/edit-publication.html",
                 publication=fetch_publication_by_id(conn, publication_id),
                 linked_phenotypes=tuple(fetch_publication_phenotypes(
                     conn, publication_id)),
@@ -181,12 +179,12 @@ def delete_publication(publication_id: int):
             flash("Cannot delete publication with linked phenotypes!",
                   "alert-warning")
             return redirect(url_for(
-                sui_template("publications.view_publication"),
+                "publications.view_publication",
                 publication_id=publication_id))
 
         if request.method == "GET":
             return render_template(
-                sui_template("publications/delete-publication.html"),
+                "publications/delete-publication.html",
                 publication=publication,
                 linked_phenotypes=linked_phenotypes,
                 publication_id=publication_id)
diff --git a/uploader/samples/views.py b/uploader/samples/views.py
index 93f0c29..ee002ba 100644
--- a/uploader/samples/views.py
+++ b/uploader/samples/views.py
@@ -1,19 +1,19 @@
 """Code regarding samples"""
-import os
 import sys
 import uuid
+import logging
 from pathlib import Path
 
-from redis import Redis
 from flask import (flash,
                    request,
                    redirect,
                    Blueprint,
                    current_app as app)
 
-from uploader.sui import sui_template
+from gn_libs import jobs
+from gn_libs import sqlite3
 
-from uploader import jobs
+from uploader import session
 from uploader.files import save_file
 from uploader.flask_extensions import url_for
 from uploader.ui import make_template_renderer
@@ -25,8 +25,7 @@ from uploader.datautils import safe_int, enumerate_sequence
 from uploader.species.models import all_species, species_by_id
 from uploader.request_checks import with_species, with_population
 from uploader.db_utils import (with_db_connection,
-                               database_connection,
-                               with_redis_connection)
+                               database_connection)
 
 from .models import samples_by_species_and_population
 
@@ -88,7 +87,7 @@ def list_samples(species: dict, population: dict, **kwargs):# pylint: disable=[u
         total_samples = len(all_samples)
         offset = max(safe_int(request.args.get("from") or 0), 0)
         count = int(request.args.get("count") or 20)
-        return render_template(sui_template("samples/list-samples.html"),
+        return render_template("samples/list-samples.html",
                                species=species,
                                population=population,
                                samples=all_samples[offset:offset+count],
@@ -98,22 +97,6 @@ def list_samples(species: dict, population: dict, **kwargs):# pylint: disable=[u
                                activelink="list-samples")
 
 
-def build_sample_upload_job(# pylint: disable=[too-many-arguments, too-many-positional-arguments]
-        speciesid: int,
-        populationid: int,
-        samplesfile: Path,
-        separator: str,
-        firstlineheading: bool,
-        quotechar: str):
-    """Define the async command to run the actual samples data upload."""
-    return [
-        sys.executable, "-m", "scripts.insert_samples", app.config["SQL_URI"],
-        str(speciesid), str(populationid), str(samplesfile.absolute()),
-        separator, f"--redisuri={app.config['REDIS_URL']}",
-        f"--quotechar={quotechar}"
-    ] + (["--firstlineheading"] if firstlineheading else [])
-
-
 @samplesbp.route("<int:species_id>/populations/<int:population_id>/upload-samples",
                methods=["GET", "POST"])
 @require_login
@@ -149,7 +132,7 @@ def upload_samples(species_id: int, population_id: int):#pylint: disable=[too-ma
                         code=307)
 
     if request.method == "GET" or request.files.get("samples_file") is None:
-        return render_template(sui_template("samples/upload-samples.html"),
+        return render_template("samples/upload-samples.html",
                                species=species,
                                population=population)
 
@@ -172,102 +155,29 @@ def upload_samples(species_id: int, population_id: int):#pylint: disable=[too-ma
 
     quotechar = (request.form.get("field_delimiter", '"') or '"')
 
-    redisuri = app.config["REDIS_URL"]
-    with Redis.from_url(redisuri, decode_responses=True) as rconn:
-        #T0DO: Add a QC step here — what do we check?
-        # 1. Does any sample in the uploaded file exist within the database?
-        #    If yes, what is/are its/their species and population?
-        # 2. If yes 1. above, provide error with notes on which species and
-        #    populations already own the samples.
-        the_job = jobs.launch_job(
+    _jobs_db = app.config["ASYNCHRONOUS_JOBS_SQLITE_DB"]
+    with sqlite3.connection(_jobs_db) as conn:
+        job = jobs.launch_job(
             jobs.initialise_job(
-                rconn,
-                jobs.jobsnamespace(),
+                conn,
                 str(uuid.uuid4()),
-                build_sample_upload_job(
-                    species["SpeciesId"],
-                    population["InbredSetId"],
-                    samples_file,
+                [
+                    sys.executable, "-m", "scripts.insert_samples",
+                    app.config["SQL_URI"],
+                    str(species["SpeciesId"]),
+                    str(population["InbredSetId"]),
+                    str(samples_file.absolute()),
                     separator,
-                    firstlineheading,
-                    quotechar),
+                    f"--quotechar={quotechar}"
+                ] + (["--firstlineheading"] if firstlineheading else []),
                 "samples_upload",
-                app.config["JOBS_TTL_SECONDS"],
-                {"job_name": f"Samples Upload: {samples_file.name}"}),
-            redisuri,
-            f"{app.config['UPLOAD_FOLDER']}/job_errors")
-        return redirect(url_for(
-            "species.populations.samples.upload_status",
-            species_id=species_id,
-            population_id=population_id,
-            job_id=the_job["jobid"]))
-
-
-@samplesbp.route("<int:species_id>/populations/<int:population_id>/"
-                 "upload-samples/status/<uuid:job_id>",
-                 methods=["GET"])
-@require_login
-@with_population(species_redirect_uri="species.populations.samples.index",
-                 redirect_uri="species.populations.samples.select_population")
-def upload_status(species: dict, population: dict, job_id: uuid.UUID, **kwargs):# pylint: disable=[unused-argument]
-    """Check on the status of a samples upload job."""
-    job = with_redis_connection(lambda rconn: jobs.job(
-        rconn, jobs.jobsnamespace(), job_id))
-    if job:
-        status = job["status"]
-        if status == "success":
-            return render_template(sui_template("samples/upload-success.html"),
-                                   job=job,
-                                   species=species,
-                                   population=population,)
-
-        if status == "error":
-            return redirect(url_for(
-                "species.populations.samples.upload_failure",
-                species_id=species["SpeciesId"],
-                population_id=population["Id"],
-                job_id=job_id))
-
-        error_filename = Path(jobs.error_filename(
-            job_id, f"{app.config['UPLOAD_FOLDER']}/job_errors"))
-        if error_filename.exists():
-            stat = os.stat(error_filename)
-            if stat.st_size > 0:
-                return redirect(url_for(
-                    "samples.upload_failure", job_id=job_id))
-
-        return render_template(sui_template("samples/upload-progress.html"),
-                               species=species,
-                               population=population,
-                               job=job) # maybe also handle this?
-
-    return render_template("no_such_job.html",
-                           job_id=job_id,
-                           species=species,
-                           population=population), 400
-
-
-@samplesbp.route("<int:species_id>/populations/<int:population_id>/"
-                 "upload-samples/failure/<uuid:job_id>",
-                 methods=["GET"])
-@require_login
-@with_population(species_redirect_uri="species.populations.samples.index",
-                 redirect_uri="species.populations.samples.select_population")
-def upload_failure(species: dict, population: dict, job_id: uuid.UUID, **kwargs):# pylint: disable=[unused-argument]
-    """Display the errors of the samples upload failure."""
-    job = with_redis_connection(lambda rconn: jobs.job(
-        rconn, jobs.jobsnamespace(), job_id))
-    if not bool(job):
-        return render_template("no_such_job.html", job_id=job_id), 400
-
-    error_filename = Path(jobs.error_filename(
-        job_id, f"{app.config['UPLOAD_FOLDER']}/job_errors"))
-    if error_filename.exists():
-        stat = os.stat(error_filename)
-        if stat.st_size > 0:
-            return render_template("worker_failure.html", job_id=job_id)
-
-    return render_template(sui_template("samples/upload-failure.html"),
-                           species=species,
-                           population=population,
-                           job=job)
+                extra_meta={
+                    "job_name": f"Samples Upload: {samples_file.name}"
+                },
+                external_id=session.logged_in_user_id()),
+            _jobs_db,
+            Path(f"{app.config['UPLOAD_FOLDER']}/job_errors").absolute(),
+            loglevel=logging.getLevelName(
+                app.logger.getEffectiveLevel()).lower())
+        return redirect(
+            url_for("background-jobs.job_status", job_id=job["job_id"]))
diff --git a/uploader/session.py b/uploader/session.py
index 5af5827..9872ceb 100644
--- a/uploader/session.py
+++ b/uploader/session.py
@@ -1,12 +1,15 @@
 """Deal with user sessions"""
+import logging
 from uuid import UUID, uuid4
 from datetime import datetime
 from typing import Any, Optional, TypedDict
 
+from flask import session
 from authlib.jose import KeySet
-from flask import request, session
 from pymonad.either import Left, Right, Either
 
+logger = logging.getLogger(__name__)
+
 
 class UserDetails(TypedDict):
     """Session information relating specifically to the user."""
@@ -22,8 +25,6 @@ class SessionInfo(TypedDict):
     session_id: UUID
     user: UserDetails
     anon_id: UUID
-    user_agent: str
-    ip_addr: str
     masquerade: Optional[UserDetails]
     auth_server_jwks: Optional[dict[str, Any]]
 
@@ -66,9 +67,6 @@ def session_info() -> SessionInfo:
                 "logged_in": False
             },
             "anon_id": anon_id,
-            "user_agent": request.headers.get("User-Agent"),
-            "ip_addr": request.environ.get("HTTP_X_FORWARDED_FOR",
-                                           request.remote_addr),
             "masquerading": None
         }))
 
@@ -91,6 +89,17 @@ def user_details() -> UserDetails:
     """Retrieve user details."""
     return session_info()["user"]
 
+
+def logged_in_user_id() -> Optional[UUID]:
+    """Get user id for logged in user. If user has not logged in, return None."""
+    return user_token().then(
+        lambda _tok: user_details()
+    ).then(
+        lambda _user: Either(_user["user_id"],
+                             (None, _user["email"] != "anon@ymous.user"))
+    ).either(lambda _err: None, lambda uid: uid)
+
+
 def user_token() -> Either:
     """Retrieve the user token."""
     return session_info()["user"]["token"]
diff --git a/uploader/species/views.py b/uploader/species/views.py
index 9b14d01..4bfa7ae 100644
--- a/uploader/species/views.py
+++ b/uploader/species/views.py
@@ -8,8 +8,6 @@ from flask import (flash,
                    Blueprint,
                    current_app as app)
 
-from uploader.sui import sui_template
-
 from uploader.population import popbp
 from uploader.platforms import platformsbp
 from uploader.flask_extensions import url_for
@@ -56,7 +54,7 @@ def view_species(species_id: int):
                                         species_id=species_id,
                                         population_id=population["Id"]))
             return render_template(
-                sui_template("species/view-species.html"),
+                "species/view-species.html",
                 species=species,
                 activelink="view-species",
                 populations=populations_by_species(conn, species["SpeciesId"]))
diff --git a/uploader/static/css/layout-common.css b/uploader/static/css/layout-common.css
index 36a5735..9c9d034 100644
--- a/uploader/static/css/layout-common.css
+++ b/uploader/static/css/layout-common.css
@@ -1,3 +1,21 @@
 * {
     box-sizing: border-box;
 }
+
+body {
+    display: grid;
+    grid-gap: 1em;
+}
+
+#header {
+    margin: -0.7em; /* Fill entire length of screen */
+    /* Define layout for the children elements */
+    display: grid;
+}
+
+#header #header-nav {
+    /* Place it in the parent element */
+    grid-column-start: 1;
+    grid-column-end: 2;
+    display: flex;
+}
diff --git a/uploader/static/css/layout-large.css b/uploader/static/css/layout-large.css
index 8abd2dd..2d53627 100644
--- a/uploader/static/css/layout-large.css
+++ b/uploader/static/css/layout-large.css
@@ -1,8 +1,6 @@
 @media screen and (min-width: 20.1in) {
     body {
-        display: grid;
         grid-template-columns: 7fr 3fr;
-        grid-gap: 1em;
     }
 
     #header {
@@ -12,7 +10,7 @@
 
         /* Define layout for the children elements */
         display: grid;
-        grid-template-columns: 8fr 2fr;
+        grid-template-columns: 1fr 9fr;
     }
 
     #header #header-text {
@@ -45,6 +43,8 @@
         grid-column-start: 1;
         grid-column-end: 3;
         padding: 0 3px;
+
+        margin: -0.3em -0.7em 0 -0.7em;
     }
 
     #main #main-content {
diff --git a/uploader/static/css/layout-medium.css b/uploader/static/css/layout-medium.css
index 2cca711..50ceeb4 100644
--- a/uploader/static/css/layout-medium.css
+++ b/uploader/static/css/layout-medium.css
@@ -1,8 +1,6 @@
 @media screen and (width > 8in) and (max-width: 20in) {
     body {
-        display: grid;
         grid-template-columns: 65fr 35fr;
-        grid-gap: 1em;
     }
 
     #header {
@@ -12,7 +10,7 @@
 
         /* Define layout for the children elements */
         display: grid;
-        grid-template-columns: 8fr 2fr;
+        grid-template-columns: 2fr 8fr;
     }
 
     #header #header-text {
@@ -51,7 +49,6 @@
         /* Place it in the parent element */
         grid-column-start: 1;
         grid-column-end: 2;
-        grid-gap: 5px;
 
         /* Define layout for the children elements */
         max-width: 100%;
diff --git a/uploader/static/css/layout-small.css b/uploader/static/css/layout-small.css
index 80a3759..2e47217 100644
--- a/uploader/static/css/layout-small.css
+++ b/uploader/static/css/layout-small.css
@@ -2,7 +2,7 @@
     body {
         display: grid;
         grid-template-columns: 1fr;
-        grid-template-rows: 1fr 2fr 7fr;
+        grid-template-rows: 1fr 90fr;
         grid-gap: 1em;
     }
 
@@ -31,6 +31,11 @@
         grid-column-end: 2;
     }
 
+    #header #header-nav ul {
+        display: grid;
+        grid-template-columns: 1fr;
+    }
+
     #main {
         /* Place it in the parent element */
         grid-column-start: 1;
@@ -38,7 +43,7 @@
         display: grid;
 
         /* Define layout for the children elements */
-        grid-template-rows: 1.5em 80% 20%;
+        grid-template-rows: 1fr 80fr 20fr;
         grid-template-columns: 1fr;
     }
 
diff --git a/uploader/static/css/theme.css b/uploader/static/css/theme.css
index bdac745..45e5d3d 100644
--- a/uploader/static/css/theme.css
+++ b/uploader/static/css/theme.css
@@ -8,24 +8,27 @@ body {
 #header {
     background-color: #336699;
     color: #FFFFFF;
-    border-radius: 3px;
     min-height: 30px;
+    border-bottom: solid black 1px;
 }
 
 #header #header-nav .nav li a {
     /* Content styling */
     color: #FFFFFF;
-    background: #4477AA;
-    border: solid 5px #336699;
-    border-radius: 5px;
     font-size: 0.7em;
     text-align: center;
     padding: 1px 7px;
+    text-decoration: none;
 }
 
 #main #breadcrumbs {
-    border-radius:3px;
     text-align: center;
+    background-color: #D5D5D5;
+    padding: 0 1em 0 1em;
+}
+
+#main #breadcrumbs .breadcrumb {
+    padding-top: 0.5em;
 }
 
 #main #main-content {
@@ -34,7 +37,7 @@ body {
 }
 
 #main #sidebar-content {
-    background: #EEEEEE;
+    background: #FEFEFE;
 
     border-radius: 5px;
     padding: 10px 5px;
@@ -88,3 +91,7 @@ table.dataTable tbody tr.selected td {
 .breadcrumb-item {
     text-transform: Capitalize;
 }
+
+.breadcrumb-item a {
+    text-decoration: none;
+}
diff --git a/uploader/static/js/datatables.js b/uploader/static/js/datatables.js
index 82fd696..bfcda2a 100644
--- a/uploader/static/js/datatables.js
+++ b/uploader/static/js/datatables.js
@@ -11,13 +11,36 @@ var addTableLength = (menuList, lengthToAdd, dataLength) => {
 
 var defaultLengthMenu = (data) => {
     menuList = []
-    var lengths = [10, 25, 50, 100, 1000, data.length];
+    var lengths = [10, 25, 50, 100, 1000];
+    if(data.length > 1000) {
+        lengths.push(data.length)
+    }
     lengths.forEach((len) => {
         menuList = addTableLength(menuList, len, data.length);
     });
     return menuList;
 };
 
+var setRowCheckableProperty = (node, state) => {
+    /**
+     * Set a row's (`node`) checkbox's or radio button's checked state to the
+     * boolean value `state`.
+     **/
+    if(typeof(state) == "boolean") {
+        var pseudoclass = state == false ? ":checked" : ":not(:checked)";
+        var checkable = (
+            $(node).find(`input[type="checkbox"]${pseudoclass}`)[0]
+                ||
+                $(node).find(`input[type="radio"]${pseudoclass}`)[0]);
+        $(checkable).prop("checked", state);
+    } else {
+        throw new Error("`state` *MUST* be a boolean value.")
+    }
+};
+
+var setRowChecked = (node) => {setRowCheckableProperty(node, true);};
+var setRowUnchecked = (node) => {setRowCheckableProperty(node, false);};
+
 var buildDataTable = (tableId, data = [], columns = [], userSettings = {}) => {
     var defaultSettings = {
         responsive: true,
@@ -35,35 +58,40 @@ var buildDataTable = (tableId, data = [], columns = [], userSettings = {}) => {
             lengthMenu: "",
             info: ""
         },
-        data: data,
-        columns: columns,
-        drawCallback: (settings) => {
-            $(this[0]).find("tbody tr").each((idx, row) => {
-                var arow = $(row);
-                var checkboxOrRadio = arow.find(".chk-row-select");
-                if (checkboxOrRadio) {
-                    if (arow.hasClass("selected")) {
-                        checkboxOrRadio.prop("checked", true);
-                    } else {
-                        checkboxOrRadio.prop("checked", false);
-                    }
-                }
+        drawCallback: function (settings) {
+            var api = this.api();
+            api.rows({selected: true}).nodes().each((node, index) => {
+                setRowChecked(node);
+            });
+            api.rows({selected: false}).nodes().each((node, index) => {
+                setRowUnchecked(node);
             });
         }
     }
     var theDataTable = $(tableId).DataTable({
         ...defaultSettings,
-        ...userSettings
+        ...userSettings,
+        ...(data.length == 0 ? {} : {data: data}),
+        ...(columns.length == 0 ? {} : {columns: columns})
     });
-    theDataTable.on("select", (event, datatable, type, cell, originalEvent) => {
-        datatable.rows({selected: true}).nodes().each((node, index) => {
-            $(node).find(".chk-row-select").prop("checked", true)
-        });
+    theDataTable.on("select", (event, datatable, type, indexes) => {
+        datatable
+            .rows(indexes)
+            .nodes()
+            .each((node, index) => {
+                setRowChecked(node);
+            });
     });
-    theDataTable.on("deselect", (event, datatable, type, cell, originalEvent) => {
-        datatable.rows({selected: false}).nodes().each((node, index) => {
-            $(node).find(".chk-row-select").prop("checked", false)
-        });
+    theDataTable.on("deselect", (event, datatable, type, indexes) => {
+        datatable
+            .rows(indexes)
+            .nodes()
+            .each(function(node, index) {
+                setRowUnchecked(node);
+            });
     });
+
+    theDataTable.selectAll = () => {theDataTable.rows().select()};
+    theDataTable.deselectAll = () => {theDataTable.rows().deselect()};
     return theDataTable;
 };
diff --git a/uploader/static/js/utils.js b/uploader/static/js/utils.js
index 1b31661..62d3662 100644
--- a/uploader/static/js/utils.js
+++ b/uploader/static/js/utils.js
@@ -28,7 +28,8 @@ var remove_class = (element, classvalue) => {
 
 var add_class = (element, classvalue) => {
     remove_class(element, classvalue);
-    element.attr("class", (element.attr("class") || "") + " " + classvalue);
+    element.attr("class",
+                 ((element.attr("class") || "") + " " + classvalue).trim());
 };
 
 $(".not-implemented").click((event) => {
diff --git a/uploader/sui.py b/uploader/sui.py
deleted file mode 100644
index 8eb863d..0000000
--- a/uploader/sui.py
+++ /dev/null
@@ -1,8 +0,0 @@
-"""Utilities for streamlined UI. This is a temporary module."""
-from flask import request
-
-def sui_template(template_path: str) -> str:
-    """Return the streamlined UI template for given template path."""
-    _sui="sui-" if request.args.get("streamlined_ui") else ""
-    _parts = template_path.split("/")
-    return "/".join(_parts[:-1] + [f"{_sui}{_parts[-1]}"])
diff --git a/uploader/templates/background-jobs/base.html b/uploader/templates/background-jobs/base.html
new file mode 100644
index 0000000..7201207
--- /dev/null
+++ b/uploader/templates/background-jobs/base.html
@@ -0,0 +1,10 @@
+{%extends "base.html"%}
+
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('background-jobs.list_jobs')}}">
+    background jobs
+  </a>
+</li>
+{%endblock%}
diff --git a/uploader/templates/background-jobs/default-success-page.html b/uploader/templates/background-jobs/default-success-page.html
deleted file mode 100644
index 5732456..0000000
--- a/uploader/templates/background-jobs/default-success-page.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{%extends "phenotypes/base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Background Jobs: Success{%endblock%}
-
-{%block pagetitle%}Background Jobs: Success{%endblock%}
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <p>Job <strong>{{job.job_id}}</strong>,
-    {%if job.get("metadata", {}).get("job-type")%}
-    of type '<em>{{job.metadata["job-type"]}}</em>
-    {%endif%}' completed successfully.</p>
-</div>
-{%endblock%}
diff --git a/uploader/templates/background-jobs/delete-job.html b/uploader/templates/background-jobs/delete-job.html
new file mode 100644
index 0000000..242c775
--- /dev/null
+++ b/uploader/templates/background-jobs/delete-job.html
@@ -0,0 +1,61 @@
+{%extends "background-jobs/base.html"%}
+{%from "flash_messages.html" import flash_all_messages%}
+{%from "background-jobs/macro-display-job-details.html" import display_job_details%}
+
+{%block title%}Background Jobs{%endblock%}
+
+{%block pagetitle%}Background Jobs{%endblock%}
+
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('background-jobs.job_summary', job_id=job.job_id)}}">
+    summary
+  </a>
+</li>
+{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row">
+  <h2 class="heading">background jobs: delete?</h2>
+
+  <p class="text-danger">Are you sure you want to delete the job below?</p>
+
+  {{display_job_details(job, display_datetime)}}
+</div>
+
+<div class="row">
+  <form id="frm-delete-job"
+        method="POST"
+        action="{{url_for('background-jobs.delete_single', job_id=job.job_id)}}">
+    <div class="row">
+      <div class="col">
+        <input type="submit"
+               class="btn btn-info"
+               value="cancel"
+               name="btn-confirm-delete" />
+      </div>
+      <div class="col">
+        <input type="submit"
+               class="btn btn-danger"
+               value="delete"
+               name="btn-confirm-delete" />
+      </div>
+    </div>
+  </form>
+</div>
+{%endblock%}
+
+
+{%block sidebarcontents%}
+<div class="row">
+  <h6 class="subheading">What is this?</h6>
+</div>
+<div class="row">
+  <p>Confirm whether or not you want to delete job
+    <strong>{{job.job_id}}</strong>.</p>
+</div>
+{{super()}}
+{%endblock%}
diff --git a/uploader/templates/background-jobs/job-status.html b/uploader/templates/background-jobs/job-status.html
new file mode 100644
index 0000000..2e75c6d
--- /dev/null
+++ b/uploader/templates/background-jobs/job-status.html
@@ -0,0 +1,45 @@
+{%extends "background-jobs/base.html"%}
+{%from "background-jobs/macro-display-job-details.html" import display_job_details%}
+
+{%from "flash_messages.html" import flash_all_messages%}
+
+{%block extrameta%}
+<meta http-equiv="refresh" content="5" />
+{%endblock%}
+
+{%block title%}Background Jobs{%endblock%}
+
+{%block pagetitle%}Background Jobs{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row">
+  <h2 class="heading">job status</h2>
+
+  {{display_job_details(job, display_datetime)}}
+</div>
+
+<div class="row">
+  <div class="col">
+    <a href="{{url_for('background-jobs.stop_job', job_id=job.job_id)}}"
+       title="Stop/Kill this job."
+       class="btn btn-danger">stop job</a>
+  </div>
+</div>
+
+<div class="row">
+  <h3 class="subheading">STDOUT</h3>
+  <div style="max-width: 40em; overflow: scroll">
+    <pre>{{job["stdout"]}}</pre>
+  </div>
+</div>
+
+<div class="row">
+  <h3 class="subheading">STDERR</h3>
+  <div style="max-width: 40em; overflow: scroll">
+    <pre>{{job["stderr"]}}</pre>
+  </div>
+</div>
+
+{%endblock%}
diff --git a/uploader/templates/background-jobs/job-summary.html b/uploader/templates/background-jobs/job-summary.html
new file mode 100644
index 0000000..ef9ef6c
--- /dev/null
+++ b/uploader/templates/background-jobs/job-summary.html
@@ -0,0 +1,75 @@
+{%extends "background-jobs/base.html"%}
+{%from "flash_messages.html" import flash_all_messages%}
+{%from "background-jobs/macro-display-job-details.html" import display_job_details%}
+
+{%block title%}Background Jobs{%endblock%}
+
+{%block pagetitle%}Background Jobs{%endblock%}
+
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('background-jobs.job_summary', job_id=job.job_id)}}">
+    summary
+  </a>
+</li>
+{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row">
+  <h2 class="heading">background jobs: summary</h2>
+
+  {{display_job_details(job, display_datetime)}}
+</div>
+
+<div class="row">
+  {%if view_under_construction%}
+  <div class="col">
+    <a href="#"
+       class="btn btn-info not-implemented"
+       title="Update the expiry date and time for this job.">update expiry</a>
+  </div>
+
+  {%if job.metadata.status in ("stopped",)%}
+  <div class="col">
+    <a href="#"
+       class="btn btn-warning not-implemented"
+       title="Create a new copy of this job, and run the copy.">Run Copy</a>
+  </div>
+  {%endif%}
+  {%endif%}
+
+  <div class="col">
+    <a href="{{url_for('background-jobs.delete_single', job_id=job.job_id)}}"
+       class="btn btn-danger"
+       title="Delete this job.">delete</a>
+  </div>
+</div>
+
+<div class="row">
+  <h3 class="subheading">Script Errors and Logging</h3>
+  <div style="max-width: 40em; overflow: scroll">
+    <pre>{{job["stderr"]}}</pre>
+  </div>
+</div>
+
+<div class="row">
+  <h3 class="subheading">Script Output</h3>
+  <div style="max-width: 40em; overflow: scroll">
+    <pre>{{job["stdout"]}}</pre>
+  </div>
+</div>
+{%endblock%}
+
+
+{%block sidebarcontents%}
+<div class="row">
+  <h6 class="subheading">What is this?</h6>
+</div>
+<div class="row">
+  <p>This page shows the results of running job '{{job.job_id}}'.</p>
+</div>
+{{super()}}
+{%endblock%}
diff --git a/uploader/templates/background-jobs/list-jobs.html b/uploader/templates/background-jobs/list-jobs.html
new file mode 100644
index 0000000..c16b850
--- /dev/null
+++ b/uploader/templates/background-jobs/list-jobs.html
@@ -0,0 +1,79 @@
+{%extends "background-jobs/base.html"%}
+{%from "flash_messages.html" import flash_all_messages%}
+
+{%block title%}Background Jobs{%endblock%}
+
+{%block pagetitle%}Background Jobs{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row"><h2 class="heading">Background Jobs</h2></div>
+
+<div class="row">
+  <div class="table-responsive">
+    <table class="table">
+      <thead>
+        <tr class="table-primary">
+          <th>Type</th>
+          <th>Created</th>
+          <th title="Date and time past which the job's details will be deleted from the system.">
+            Expires</th>
+          <th>Status</th>
+          <th>Actions</th>
+        </tr>
+      </thead>
+
+      <tbody>
+        {%for job in jobs%}
+        <tr>
+          <td>{{job.metadata["job-type"]}}</td>
+          <td>{{display_datetime(job.created)}}</td>
+          <td title="Date and time past which the job's details will be deleted from the system.">
+            {{display_datetime(job.expires)}}
+          </td>
+          <td {%if job.metadata.status == "completed"%}
+              class="fw-bold text-capitalize text-success"
+              {%elif job.metadata.status == "error"%}
+              class="fw-bold text-capitalize text-danger"
+              {%elif job.metadata.status == "stopped"%}
+              class="fw-bold text-capitalize text-warning"
+              {%else%}
+              class="fw-bold text-capitalize text-info"
+              {%endif%}>
+            <div>
+              {{job.metadata.status}}
+            </div>
+          </td>
+          <td>
+            <a href="{{url_for('background-jobs.job_summary', job_id=job.job_id)}}"
+               class="btn btn-info"
+               title="View more detailed information about this job.">
+              view summary</a>
+          </td>
+        </tr>
+        {%else%}
+        <tr>
+          <td colspan="5">
+            You do not have any jobs you have run in the background.</td>
+        </tr>
+        {%endfor%}
+      </tbody>
+    </table>
+  </div>
+</div>
+{%endblock%}
+
+
+{%block sidebarcontents%}
+<div class="row">
+  <h6 class="subheading">What is this?</h6>
+</div>
+<div class="row">
+  <p>The table lists the jobs that are running in the background, that you
+    started.</p>
+  <p>You can use the tools provided on this page to manage the jobs, and to view
+    each job's details.</p>
+</div>
+{{super()}}
+{%endblock%}
diff --git a/uploader/templates/background-jobs/macro-display-job-details.html b/uploader/templates/background-jobs/macro-display-job-details.html
new file mode 100644
index 0000000..82e33c0
--- /dev/null
+++ b/uploader/templates/background-jobs/macro-display-job-details.html
@@ -0,0 +1,29 @@
+{%macro display_job_details(job, display_datetime)%}
+<table class="table">
+  <thead>
+  </thead>
+
+  <tbody>
+    <tr>
+      <th class="table-primary">Job ID</th>
+      <td>{{job.job_id}}</td>
+    </tr>
+    <tr>
+      <th class="table-primary">Type</th>
+      <td>{{job.metadata["job-type"]}}</td>
+    </tr>
+    <tr>
+      <th class="table-primary">Created</th>
+      <td>{{display_datetime(job.created)}}</td>
+    </tr>
+    <tr>
+      <th class="table-primary">Expires</th>
+      <td>{{display_datetime(job.expires)}}</td>
+    </tr>
+    <tr>
+      <th class="table-primary">Status</th>
+      <td>{{job.metadata.status}}</td>
+    </tr>
+  </tbody>
+</table>
+{%endmacro%}
diff --git a/uploader/templates/background-jobs/stop-job.html b/uploader/templates/background-jobs/stop-job.html
new file mode 100644
index 0000000..fc190ac
--- /dev/null
+++ b/uploader/templates/background-jobs/stop-job.html
@@ -0,0 +1,61 @@
+{%extends "background-jobs/base.html"%}
+{%from "flash_messages.html" import flash_all_messages%}
+{%from "background-jobs/macro-display-job-details.html" import display_job_details%}
+
+{%block title%}Background Jobs{%endblock%}
+
+{%block pagetitle%}Background Jobs{%endblock%}
+
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('background-jobs.job_summary', job_id=job.job_id)}}">
+    summary
+  </a>
+</li>
+{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row">
+  <h2 class="heading">background jobs: stop?</h2>
+
+  <p class="text-danger">Are you sure you want to stop the job below?</p>
+
+  {{display_job_details(job, display_datetime)}}
+</div>
+
+<div class="row">
+  <form id="frm-stop-job"
+        method="POST"
+        action="{{url_for('background-jobs.stop_job', job_id=job.job_id)}}">
+    <div class="row">
+      <div class="col">
+        <input type="submit"
+               class="btn btn-info"
+               value="cancel"
+               name="btn-confirm-stop" />
+      </div>
+      <div class="col">
+        <input type="submit"
+               class="btn btn-danger"
+               value="stop"
+               name="btn-confirm-stop" />
+      </div>
+    </div>
+  </form>
+</div>
+{%endblock%}
+
+
+{%block sidebarcontents%}
+<div class="row">
+  <h6 class="subheading">What is this?</h6>
+</div>
+<div class="row">
+  <p>Confirm whether or not you want to stop job
+    <strong>{{job.job_id}}</strong>.</p>
+</div>
+{{super()}}
+{%endblock%}
diff --git a/uploader/templates/background-jobs/sui-default-success-page.html b/uploader/templates/background-jobs/sui-default-success-page.html
deleted file mode 100644
index 5732456..0000000
--- a/uploader/templates/background-jobs/sui-default-success-page.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{%extends "phenotypes/base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Background Jobs: Success{%endblock%}
-
-{%block pagetitle%}Background Jobs: Success{%endblock%}
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <p>Job <strong>{{job.job_id}}</strong>,
-    {%if job.get("metadata", {}).get("job-type")%}
-    of type '<em>{{job.metadata["job-type"]}}</em>
-    {%endif%}' completed successfully.</p>
-</div>
-{%endblock%}
diff --git a/uploader/templates/base.html b/uploader/templates/base.html
index d521ccb..ae4ecef 100644
--- a/uploader/templates/base.html
+++ b/uploader/templates/base.html
@@ -16,7 +16,11 @@
     <link rel="stylesheet" type="text/css"
           href="{{url_for('base.datatables',
                 filename='css/dataTables.bootstrap5.min.css')}}" />
-    <link rel="stylesheet" type="text/css" href="/static/css/styles.css" />
+    <link rel="stylesheet" type="text/css" href="/static/css/layout-common.css" />
+    <link rel="stylesheet" type="text/css" href="/static/css/layout-large.css" />
+    <link rel="stylesheet" type="text/css" href="/static/css/layout-medium.css" />
+    <link rel="stylesheet" type="text/css" href="/static/css/layout-small.css" />
+    <link rel="stylesheet" type="text/css" href="/static/css/theme.css" />
 
     {%block css%}{%endblock%}
 
@@ -26,14 +30,32 @@
     <header id="header">
       <span id="header-text">GeneNetwork</span>
       <nav id="header-nav">
-        <ul class="nav justify-content-end">
+        <ul class="nav">
+          {%if user_logged_in()%}
+          <li>
+            <a href="{{url_for('background-jobs.list_jobs')}}"
+               title="User's background jobs.">
+              <!-- https://icons.getbootstrap.com/icons/back/ -->
+              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-back" viewBox="0 0 16 16">
+                <path d="M0 2a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v2h2a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2v-2H2a2 2 0 0 1-2-2zm2-1a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1z"/>
+              </svg>
+              Background jobs
+            </a>
+          </li>
+
           <li>
-            {%if user_logged_in()%}
             <a href="{{url_for('oauth2.logout')}}"
                title="Log out of the system">
+              <!-- https://icons.getbootstrap.com/icons/file-person/ -->
+              <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-file-person" viewBox="0 0 16 16">
+                <path d="M12 1a1 1 0 0 1 1 1v10.755S12 11 8 11s-5 1.755-5 1.755V2a1 1 0 0 1 1-1zM4 0a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2V2a2 2 0 0 0-2-2z"/>
+                <path d="M8 10a3 3 0 1 0 0-6 3 3 0 0 0 0 6"/>
+              </svg>
               <span class="glyphicon glyphicon-user"></span>
-              {{user_email()}} Sign Out</a>
-            {%else%}
+              Sign Out ({{user_email()}})</a>
+          </li>
+          {%else%}
+          <li>
             <a href="{{authserver_authorise_uri()}}"
                title="Log in to the system">Sign In</a>
             {%endif%}
@@ -42,91 +64,29 @@
       </nav>
     </header>
 
-    <aside id="nav-sidebar">
-      <ul class="nav flex-column">
-        <li {%if activemenu=="home"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('base.index')}}" >Home</a></li>
-        <li {%if activemenu=="publications"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('publications.index')}}"
-             title="View and manage publications.">Publications</a></li>
-        <li {%if activemenu=="species"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('species.list_species')}}"
-             title="View and manage species information.">Species</a></li>
-        <li {%if activemenu=="platforms"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('species.platforms.index')}}"
-             title="View and manage species platforms.">Sequencing Platforms</a></li>
-        <li {%if activemenu=="populations"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('species.populations.index')}}"
-             title="View and manage species populations.">Populations</a></li>
-        <li {%if activemenu=="samples"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('species.populations.samples.index')}}"
-             title="Upload population samples.">Samples</a></li>
-        <li {%if activemenu=="genotypes"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('species.populations.genotypes.index')}}"
-             title="Upload Genotype data.">Genotype Data</a></li>
-        <!--
-            TODO: Maybe include menus here for managing studies and dataset or
-            maybe have the studies/datasets managed under their respective
-            sections, e.g. "Publish*" studies/datasets under the "Phenotypes"
-            section, "ProbeSet*" studies/datasets under the "Expression Data"
-            sections, etc.
-          -->
-        <li {%if activemenu=="phenotypes"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('species.populations.phenotypes.index')}}"
-             title="Upload phenotype data.">Phenotype Data</a></li>
-        <!--
-        <li {%if activemenu=="expression-data"%}class="activemenu"{%endif%}>
-          <a href="{{url_for('species.populations.expression-data.index')}}"
-             title="Upload expression data."
-             class="not-implemented">Expression Data</a></li>
-        <li {%if activemenu=="individuals"%}class="activemenu"{%endif%}>
-          <a href="#"
-             class="not-implemented"
-             title="Upload individual data.">Individual Data</a></li>
-        <li {%if activemenu=="rna-seq"%}class="activemenu"{%endif%}>
-          <a href="#"
-             class="not-implemented"
-             title="Upload RNA-Seq data.">RNA-Seq Data</a></li>
-        <li {%if activemenu=="async-jobs"%}class="activemenu"{%endif%}>
-          <a href="#"
-             class="not-implemented"
-             title="View and manage the backgroud jobs you have running">
-            Background Jobs</a></li>
-        -->
-      </ul>
-    </aside>
 
     <main id="main" class="main">
+      <nav id="breadcrumbs" aria-label="breadcrumb">
+        <ol class="breadcrumb">
+          {%block breadcrumbs%}
+          <li class="breadcrumb-item">
+            <a href="{{url_for('base.index')}}">Home</a></li>
+          {%endblock%}
+        </ol>
+      </nav>
 
-      <div id="pagetitle" class="pagetitle">
-        <span class="title">Data Upload and Quality Control: {%block pagetitle%}{%endblock%}</span>
-        <!--
-            <nav>
-              <ol class="breadcrumb">
-                <li {%if activelink is not defined or activelink=="home"%}
-                    class="breadcrumb-item active"
-                    {%else%}
-                    class="breadcrumb-item"
-                    {%endif%}>
-                  <a href="{{url_for('base.index')}}">Home</a>
-                </li>
-                {%block lvl1_breadcrumbs%}{%endblock%}
-              </ol>
-            </nav>
-            -->
-      </div>
-
-      <div id="all-content">
-        <div id="main-content">
+      <div id="main-content">
           {%block contents%}{%endblock%}
         </div>
-        <div id="sidebar-content">
+
+      <div id="sidebar-content">
           {%block sidebarcontents%}{%endblock%}
         </div>
-      </div>
     </main>
 
 
+
+    <script type="text/javascript" src="/static/js/debug.js"></script>
     <!--
         Core dependencies
       -->
diff --git a/uploader/templates/genotypes/base.html b/uploader/templates/genotypes/base.html
index 7d61312..8d1b951 100644
--- a/uploader/templates/genotypes/base.html
+++ b/uploader/templates/genotypes/base.html
@@ -1,23 +1,18 @@
 {%extends "populations/base.html"%}
+{%from "populations/macro-display-population-card.html" import display_sui_population_card%}
 
-{%block lvl3_breadcrumbs%}
-<li {%if activelink=="genotypes"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  {%if population is mapping%}
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
   <a href="{{url_for('species.populations.genotypes.list_genotypes',
-           species_id=species.SpeciesId,
-           population_id=population.Id)}}">
-    {%if dataset is defined and dataset is mapping%}
-    {{dataset.Name}}
-    {%else%}
-    Genotypes
-    {%endif%}</a>
-  {%else%}
-  <a href="{{url_for('species.populations.genotypes.index')}}">Genotypes</a>
-  {%endif%}
+           species_id=species['SpeciesId'],
+           population_id=population['Id'])}}">
+    genotype
+  </a>
 </li>
-{%block lvl4_breadcrumbs%}{%endblock%}
+{%endblock%}
+
+
+{%block sidebarcontents%}
+{{display_sui_population_card(species, population)}}
 {%endblock%}
diff --git a/uploader/templates/genotypes/list-genotypes.html b/uploader/templates/genotypes/list-genotypes.html
index 0f074fd..a2b98c8 100644
--- a/uploader/templates/genotypes/list-genotypes.html
+++ b/uploader/templates/genotypes/list-genotypes.html
@@ -1,23 +1,10 @@
 {%extends "genotypes/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block title%}Genotypes{%endblock%}
 
 {%block pagetitle%}Genotypes{%endblock%}
 
-{%block lvl4_breadcrumbs%}
-<li {%if activelink=="list-genotypes"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('species.populations.genotypes.list_genotypes',
-           species_id=species.SpeciesId,
-           population_id=population.Id)}}">List genotypes</a>
-</li>
-{%endblock%}
-
 {%block contents%}
 {{flash_all_messages()}}
 
@@ -143,7 +130,3 @@
     all the rest.</p>
 </div>
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
-{%endblock%}
diff --git a/uploader/templates/genotypes/list-markers.html b/uploader/templates/genotypes/list-markers.html
index a705ae3..5f3dd6f 100644
--- a/uploader/templates/genotypes/list-markers.html
+++ b/uploader/templates/genotypes/list-markers.html
@@ -1,20 +1,18 @@
 {%extends "genotypes/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
-{%from "species/macro-display-species-card.html" import display_species_card%}
 
 {%block title%}Genotypes: List Markers{%endblock%}
 
 {%block pagetitle%}Genotypes: List Markers{%endblock%}
 
-{%block lvl4_breadcrumbs%}
-<li {%if activelink=="list-markers"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
   <a href="{{url_for('species.populations.genotypes.list_markers',
-           species_id=species.SpeciesId,
-           population_id=population.Id)}}">List markers</a>
+           species_id=species['SpeciesId'],
+           population_id=population['Id'])}}">
+    markers
+  </a>
 </li>
 {%endblock%}
 
@@ -99,7 +97,3 @@
 </div>
 {%endif%}
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_species_card(species)}}
-{%endblock%}
diff --git a/uploader/templates/genotypes/view-dataset.html b/uploader/templates/genotypes/view-dataset.html
index e7ceb36..1c4eccf 100644
--- a/uploader/templates/genotypes/view-dataset.html
+++ b/uploader/templates/genotypes/view-dataset.html
@@ -1,21 +1,17 @@
 {%extends "genotypes/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block title%}Genotypes: View Dataset{%endblock%}
 
 {%block pagetitle%}Genotypes: View Dataset{%endblock%}
 
-{%block lvl4_breadcrumbs%}
-<li {%if activelink=="view-dataset"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
   <a href="{{url_for('species.populations.genotypes.view_dataset',
            species_id=species.SpeciesId,
            population_id=population.Id,
-           dataset_id=dataset.Id)}}">view dataset</a>
+           dataset_id=dataset.Id)}}">dataset</a>
 </li>
 {%endblock%}
 
@@ -55,7 +51,3 @@
 </div>
 
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
-{%endblock%}
diff --git a/uploader/templates/index.html b/uploader/templates/index.html
index aa1414e..e426732 100644
--- a/uploader/templates/index.html
+++ b/uploader/templates/index.html
@@ -1,107 +1,162 @@
 {%extends "base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
+{%from "macro-forms.html" import add_http_feature_flags%}
 
 {%block title%}Home{%endblock%}
 
 {%block pagetitle%}Home{%endblock%}
 
-{%block contents%}
-
-<div class="row">
-  {{flash_all_messages()}}
-  <div class="explainer">
-    <p>Welcome to the <strong>GeneNetwork Data Upload and Quality Control
-        System</strong>.</p>
-    <p>This tool helps you prepare and upload research data to GeneNetwork for
-      analysis.</p>
-
-    <h2 class="heading">Getting Started</h2>
-    <p>The sections below explain the features of the system. Review this guide
-      to learn how to use the system.</p>
-
-    {%block extrapageinfo%}{%endblock%}
-
-    <h3 class="subheading">Species</h3>
-
-    <p>GeneNetwork supports genetic studies across multiple species (e.g. mice
-      [Mus musculus], human [homo sapiens], rats [Rattus norvegicus], etc.) .
-      Here you can:</p>
-    <ul>
-      <li>View all species that are currently supported</li>
-      <li>Add new species not yet in the system</li>
-    </ul>
-
-    <h3 class="subheading">Populations</h3>
-
-    <p>A "population" refers to a specific subgroup within a species that you’re
-      studying (e.g., BXD mice). Here you can:</p>
-    <ul>
-      <li>View the populations that exist for a selected species</li>
-      <li>Add new populations of study for a selected species</li>
-    </ul>
-
-    <h3 class="subheading">Samples</h3>
-
-    <p>Manage individual specimens or cases used in your experiments. These
-      include:</p>
-
-    <ul>
-      <li>Experimental subjects</li>
-      <li>Data sources (e.g., tissue samples, clinical cases)</li>
-      <li>Strain means (instead of entering multiple BXD1 individuals, for
-        example, the mean would be entered for a single BXD1 strain)</li>
-    </ul>
-
-
-    <h3 class="subheading">Genotype Data</h3>
-
-    <p>Upload and review genetic markers and allele encodings for your
-      population. Key details:</p>
+{%block extra_breadcrumbs%}{%endblock%}
 
-    <ul>
-      <li>Markers are species-level (e.g., mouse SNP databases).</li>
-      <li>Allele data is population-specific (tied to your experimental
-        samples).</li>
-    </ul>
-
-    <p><strong>Requirement</strong>: Samples must already have been registered
-      in the system before uploading genotype data.</p>
-
-    <h3 class="subheading">Phenotype Data</h3>
+{%block contents%}
 
-    <p>Phenotypes are the visible traits or features of a living thing. For
-      example, phenotypes include:</p>
+{%macro add_form_buttons()%}
+<div class="row form-buttons">
+  <div class="col">
+    <input type="submit"
+           class="btn btn-primary"
+           value="use selected species" />
+  </div>
+  <div class="col">
+    <a href="{{url_for('species.create_species', return_to='base.index')}}"
+       class="btn btn-outline-primary"
+       title="Create a new species.">Create a new Species</a>
+  </div>
+</div>
+{%endmacro%}
 
-    <ul>
-      <li>Weight</li>
-      <li>Height</li>
-      <li>Color (such as the color of fur or eyes)</li>
-    </ul>
+<div class="row">{{flash_all_messages()}}</div>
 
-    <p>This part of the system will allow you to upload and manage the values
-      for different phenotypes from various samples in your studies.</p>
+{%if user_logged_in()%}
 
-    <!--
+<div class="row">
+  <ul class="nav nav-tabs" id="index-actions">
+    <li class="nav-item presentation">
+      <button class="nav-link active"
+              id="upload-data-tab"
+              data-bs-toggle="tab"
+              data-bs-target="#upload-data-content"
+              type="button"
+              role="tab"
+              aria-controls="upload-data-content"
+              aria-selected="false">Upload Data</button></li>
+    <li class="nav-item presentation">
+      <button class="nav-link"
+              id="publications-tab"
+              data-bs-toggle="tab"
+              data-bs-target="#publications-content"
+              type="button"
+              role="tab"
+              aria-controls="publications-content"
+              aria-selected="true">Publications</button></li>
+  </ul>
+</div>
 
-        <h3 class="subheading">Expression Data</h3>
+<div class="row">
+  <div class="tab-content" id="upload-data-tabs-content">
+    <div class="tab-pane fade show active"
+         id="upload-data-content"
+         role="tabpanel"
+         aria-labelledby="upload-data-content-tab">
+      <h2 class="heading">Species</h2>
+
+      <p>Select the species you want to work with.</p>
+
+      <form method="GET" action="{{url_for('base.index')}}" class="form-horizontal">
+        {{add_http_feature_flags()}}
+
+        {{add_form_buttons()}}
+
+        {%if species | length != 0%}
+        <div style="margin-top:1em;">
+          <table id="tbl-select-species" class="table compact stripe"
+                 data-species-list='{{species | tojson}}'>
+            <thead>
+              <tr>
+                <th></th>
+                <th>Species Name</th>
+              </tr>
+            </thead>
+
+            <tbody></tbody>
+          </table>
+        </div>
+
+        {%else%}
+
+        <label class="control-label" for="rdo-cant-find-species">
+          <input id="rdo-cant-find-species" type="radio" name="species_id"
+                 value="CREATE-SPECIES" />
+          There are no species to select from. Create the first one.</label>
+
+        <div class="col-sm-offset-10 col-sm-2">
+          <input type="submit"
+                 class="btn btn-primary col-sm-offset-1"
+                 value="continue" />
+        </div>
+
+        {%endif%}
+
+        {{add_form_buttons()}}
+
+      </form>
+    </div>
+
+    <div class="tab-pane fade"
+         id="publications-content"
+         role="tabpanel"
+         aria-labelledby="publications-content-tab">
+      <p>View, edit and delete existing publications, and add new
+        publications by clicking on the button below.</p>
+
+      <a href="{{url_for('publications.index')}}"
+         title="Manage publications."
+         class="btn btn-primary">manage publications</a>
+    </div>
+  </div>
+</div>
 
-    <p class="text-danger">
-      <span class="glyphicon glyphicon-exclamation-sign"></span>
-      <strong>TODO</strong>: Document this &hellip;</p>
+  {%else%}
+
+  <div class="row">
+    <p>The Genenetwork Uploader (<em>gn-uploader</em>) enables upload of new data
+      into the Genenetwork System. It provides Quality Control over data, and
+      guidance in case you data does not meet the standards for acceptance.</p>
+    <p>
+      <a href="{{authserver_authorise_uri()}}"
+         title="Sign in to the system"
+         class="btn btn-primary">Sign in</a>
+      to get started.</p>
+  </div>
+  {%endif%}
 
-    <h3 class="subheading">Individual Data</h3>
+  {%endblock%}
 
-    <p class="text-danger">
-      <span class="glyphicon glyphicon-exclamation-sign"></span>
-      <strong>TODO</strong>: Document this &hellip;</p>
 
-    <h3 class="subheading">RNA-Seq Data</h3>
 
-    <p class="text-danger">
-      <span class="glyphicon glyphicon-exclamation-sign"></span>
-      <strong>TODO</strong>: Document this &hellip;</p>
+  {%block sidebarcontents%}
+  {%if view_under_construction%}
+  <div class="row">
+    <p>The data in Genenetwork is related to one species or another. Use the form
+      provided to select from existing species, or click on the
+      "Create a New Species" button if you cannot find the species you want to
+      work with.</p>
   </div>
-  -->
-</div>
+  <div class="row">
+    <form id="frm-quick-navigation">
+      <legend>Quick Navigation</legend>
+      <div class="form-group">
+        <label for="fqn-species-id">Species</label>
+        <select name="species_id">
+          <option value="">Select species</option>
+        </select>
+      </div>
+    </form>
+  </div>
+  {%endif%}
+  {%endblock%}
+
 
-{%endblock%}
+  {%block javascript%}
+  <script type="text/javascript" src="/static/js/species.js"></script>
+  {%endblock%}
diff --git a/uploader/templates/jobs/sui-job-error.html b/uploader/templates/jobs/sui-job-error.html
deleted file mode 100644
index 1a839a6..0000000
--- a/uploader/templates/jobs/sui-job-error.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{%extends "sui-base.html"%}
-
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Background Jobs: Error{%endblock%}
-
-{%block pagetitle%}Background Jobs: Error{%endblock%}
-
-{%block contents%}
-
-<h1>Background Jobs: Error</h1>
-<p>Job <strong>{{job["job_id"]}}</strong> failed!</p>
-<p>The error details are in the "STDERR" section below.</p>
-
-<h2>STDERR</h2>
-<pre>{{job["stderr"]}}</pre>
-{%endblock%}
diff --git a/uploader/templates/jobs/sui-job-not-found.html b/uploader/templates/jobs/sui-job-not-found.html
deleted file mode 100644
index 96c8586..0000000
--- a/uploader/templates/jobs/sui-job-not-found.html
+++ /dev/null
@@ -1,11 +0,0 @@
-{%extends "sui-base.html"%}
-
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Background Jobs{%endblock%}
-
-{%block pagetitle%}Background Jobs{%endblock%}
-
-{%block contents%}
-<p>Could not find job with ID: {{job_id}}</p>
-{%endblock%}
diff --git a/uploader/templates/jobs/sui-job-status.html b/uploader/templates/jobs/sui-job-status.html
deleted file mode 100644
index fc5e532..0000000
--- a/uploader/templates/jobs/sui-job-status.html
+++ /dev/null
@@ -1,24 +0,0 @@
-{%extends "sui-base.html"%}
-
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block extrameta%}
-<meta http-equiv="refresh" content="5" />
-{%endblock%}
-
-{%block title%}Background Jobs{%endblock%}
-
-{%block pagetitle%}Background Jobs{%endblock%}
-
-{%block contents%}
-
-<p>Status: {{job["metadata"]["status"]}}</p>
-<p>Job Type: {{job["metadata"]["job-type"]}}</p>
-
-<h2>STDOUT</h2>
-<pre>{{job["stdout"]}}</pre>
-
-<h2>STDERR</h2>
-<pre>{{job["stderr"]}}</pre>
-
-{%endblock%}
diff --git a/uploader/templates/login.html b/uploader/templates/login.html
deleted file mode 100644
index e76c644..0000000
--- a/uploader/templates/login.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{%extends "index.html"%}
-
-{%block title%}Data Upload{%endblock%}
-
-{%block pagetitle%}log in{%endblock%}
-
-{%block extrapageinfo%}
-<p class="text-dark">
-  You <strong>need to
-    <a href="{{authserver_authorise_uri()}}"
-       title="Sign in to the system">sign in</a></strong> to use this system.</p>
-{%endblock%}
diff --git a/uploader/templates/phenotypes/add-phenotypes-base.html b/uploader/templates/phenotypes/add-phenotypes-base.html
index 9909c20..c74a0fa 100644
--- a/uploader/templates/phenotypes/add-phenotypes-base.html
+++ b/uploader/templates/phenotypes/add-phenotypes-base.html
@@ -1,26 +1,13 @@
 {%extends "phenotypes/base.html"%}
 {%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 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)}}">Add Phenotypes</a>
-</li>
-{%endblock%}
-
 {%block contents%}
+{{super()}}
 {{flash_all_messages()}}
 
 <div class="row">
@@ -42,8 +29,7 @@
 
     {%block frm_add_phenotypes_elements%}{%endblock%}
 
-    <fieldset id="fldset-publication-info">
-      <legend>Publication Information</legend>
+      <h4>Publication Information</h4>
       <input type="hidden" name="publication-id" id="txt-publication-id" />
       <span class="form-text text-muted">
         Select a publication for your data. <br />
@@ -66,7 +52,6 @@
 
         <tbody></tbody>
       </table>
-    </fieldset>
 
     <div class="form-group">
       <input type="submit"
@@ -83,6 +68,8 @@
 {%endblock%}
 
 
+
+
 {%block javascript%}
 <script type="text/javascript">
   $(function() {
diff --git a/uploader/templates/phenotypes/add-phenotypes-raw-files.html b/uploader/templates/phenotypes/add-phenotypes-raw-files.html
index 67b56e3..b1322b2 100644
--- a/uploader/templates/phenotypes/add-phenotypes-raw-files.html
+++ b/uploader/templates/phenotypes/add-phenotypes-raw-files.html
@@ -1,7 +1,6 @@
 {%extends "phenotypes/add-phenotypes-base.html"%}
 {%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%}
 {%from "phenotypes/macro-display-preview-table.html" import display_preview_table%}
 {%from "phenotypes/macro-display-resumable-elements.html" import display_resumable_elements%}
 
@@ -9,19 +8,6 @@
 
 {%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)}}">Add Phenotypes</a>
-</li>
-{%endblock%}
-
 {%block frm_add_phenotypes_documentation%}
 <p>This page will allow you to upload all the separate files that make up your
   phenotypes. Here, you will have to upload each separate file individually. If
@@ -35,8 +21,7 @@
 {%endblock%}
 
 {%block frm_add_phenotypes_elements%}
-<fieldset id="fldset-file-metadata">
-  <legend>File(s) Metadata</legend>
+  <h4>File(s) Metadata</h4>
   <div class="form-group">
     <label for="txt-file-separator" class="form-label">File Separator</label>
     <div class="input-group">
@@ -103,12 +88,9 @@
       <a href="#docs-file-na" title="Documentation for no-value fields">
         documentation for more information</a>.</span>
   </div>
-</fieldset>
 
-<fieldset id="fldset-files">
   <legend>Data File(s)</legend>
 
-  <fieldset id="fldset-descriptions-file">
     <div class="form-group">
       <div class="form-check">
         <input id="chk-phenotype-descriptions-transposed"
@@ -159,10 +141,8 @@
       {{display_preview_table(
       "tbl-preview-pheno-desc", "phenotype descriptions")}}
     </div>
-  </fieldset>
-
 
-  <fieldset id="fldset-data-file">
+    
     <div class="form-group">
       <div class="form-check">
         <input id="chk-phenotype-data-transposed"
@@ -210,11 +190,9 @@
         on the expected format for the file provided here.</p>')}}
       {{display_preview_table("tbl-preview-pheno-data", "phenotype data")}}
     </div>
-  </fieldset>
 
   
   {%if population.Family in families_with_se_and_n%}
-  <fieldset id="fldset-se-file">
     <div class="form-group">
       <div class="form-check">
         <input id="chk-phenotype-se-transposed"
@@ -261,10 +239,8 @@
 
       {{display_preview_table("tbl-preview-pheno-se", "standard errors")}}
     </div>
-  </fieldset>
 
 
-  <fieldset id="fldset-n-file">
     <div class="form-group">
       <div class="form-check">
         <input id="chk-phenotype-n-transposed"
@@ -311,8 +287,6 @@
 
       {{display_preview_table("tbl-preview-pheno-n", "number of samples/individuals")}}
     </div>
-  </fieldset>
-</fieldset>
 {%endif%}
 {%endblock%}
 
@@ -447,10 +421,6 @@
 
 {%endblock%}
 
-{%block sidebarcontents%}
-{{display_pheno_dataset_card(species, population, dataset)}}
-{%endblock%}
-
 
 {%block more_javascript%}
 <script src="{{url_for('base.node_modules',
@@ -495,7 +465,7 @@
               .map((field) => {
                   var value = field.trim();
                   if(navalues.includes(value)) {
-                      return "⋘NUL⋙";
+                      return "[NO-VALUE]";
                   }
                   return value;
               })
diff --git a/uploader/templates/phenotypes/add-phenotypes-with-rqtl2-bundle.html b/uploader/templates/phenotypes/add-phenotypes-with-rqtl2-bundle.html
index 898fc0c..4afd6ab 100644
--- a/uploader/templates/phenotypes/add-phenotypes-with-rqtl2-bundle.html
+++ b/uploader/templates/phenotypes/add-phenotypes-with-rqtl2-bundle.html
@@ -1,25 +1,11 @@
 {%extends "phenotypes/add-phenotypes-base.html"%}
 {%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 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)}}">Add Phenotypes</a>
-</li>
-{%endblock%}
-
 {%block frm_add_phenotypes_documentation%}
 <p>Select the zip file bundle containing information on the phenotypes you
   wish to upload, then click the "Upload Phenotypes" button below to
@@ -201,7 +187,3 @@
     <em>phenotypes × individuals</em>.</p>
 </div>
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_pheno_dataset_card(species, population, dataset)}}
-{%endblock%}
diff --git a/uploader/templates/phenotypes/base.html b/uploader/templates/phenotypes/base.html
index adbc012..fe7ccd3 100644
--- a/uploader/templates/phenotypes/base.html
+++ b/uploader/templates/phenotypes/base.html
@@ -1,19 +1,25 @@
 {%extends "populations/base.html"%}
+{%from "phenotypes/macro-display-pheno-dataset-card.html" import display_sui_pheno_dataset_card%}
 
-{%block lvl3_breadcrumbs%}
-<li {%if activelink=="phenotypes"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  {%if dataset is mapping%}
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
   <a href="{{url_for('species.populations.phenotypes.view_dataset',
-           species_id=species.SpeciesId,
-           population_id=population.Id,
-           dataset_id=dataset.Id)}}">{{dataset.Name}}</a>
-  {%else%}
-  <a href="{{url_for('species.populations.phenotypes.index')}}">Phenotypes</a>
-  {%endif%}
+           species_id=species['SpeciesId'],
+           population_id=population['Id'],
+           dataset_id=dataset['Id'])}}">
+    {{dataset["Name"]}}
+  </a>
 </li>
-{%block lvl4_breadcrumbs%}{%endblock%}
+{%endblock%}
+
+{%block contents%}
+<div class="row">
+  <h2 class="heading">{{dataset.FullName}} ({{dataset.Name}})</h2>
+</div>
+{%endblock%}
+
+
+{%block sidebarcontents%}
+{{display_sui_pheno_dataset_card(species, population, dataset)}}
 {%endblock%}
diff --git a/uploader/templates/phenotypes/confirm-delete-phenotypes.html b/uploader/templates/phenotypes/confirm-delete-phenotypes.html
new file mode 100644
index 0000000..e6d67c7
--- /dev/null
+++ b/uploader/templates/phenotypes/confirm-delete-phenotypes.html
@@ -0,0 +1,196 @@
+{%extends "phenotypes/base.html"%}
+{%from "flash_messages.html" import flash_all_messages%}
+
+{%block title%}Phenotypes{%endblock%}
+
+{%block pagetitle%}Delete Phenotypes{%endblock%}
+
+{%block lvl4_breadcrumbs%}
+<li {%if activelink=="view-dataset"%}
+    class="breadcrumb-item active"
+    {%else%}
+    class="breadcrumb-item"
+    {%endif%}>
+  <a href="{{url_for('species.populations.phenotypes.view_dataset',
+           species_id=species.SpeciesId,
+           population_id=population.Id,
+           dataset_id=dataset.Id)}}">View</a>
+</li>
+{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row"><h2>Delete Phenotypes</h2></div>
+
+{%if phenotypes | length > 0%}
+<div class="row">
+  <p>You have requested to delete the following phenotypes:</p>
+</div>
+
+<div class="row">
+  <div class="col">
+    <a id="btn-select-all-phenotypes"
+       href="#"
+       class="btn btn-info"
+       title="Select all phenotypes">select all</a>
+  </div>
+  <div class="col">
+    <a id="btn-deselect-all-phenotypes"
+       href="#"
+       class="btn btn-warning"
+       title="Deselect all phenotypes">deselect all</a>
+  </div>
+</div>
+
+<div class="row">
+  <table id="tbl-delete-phenotypes" class="table">
+    <thead>
+      <tr>
+        <th>#</th>
+        <th>Record ID</th>
+        <th>Description</th>
+      </tr>
+    </thead>
+    <tbody>
+      {%for phenotype in phenotypes%}
+      <tr>
+        <td>
+          <input id="chk-xref-id-{{phenotype.xref_id}}"
+                 name="xref_ids"
+                 type="checkbox"
+                 value="{{phenotype.xref_id}}"
+                 class="chk-row-select" />
+        </td>
+        <td>{{phenotype.xref_id}}</td>
+        <td>{{phenotype.Post_publication_description or
+          phenotype.Pre_publication_description or
+          phenotype.original_description}}</td>
+      </tr>
+      {%endfor%}
+    </tbody>
+  </table>
+</div>
+
+<div class="row">
+  <form id="frm-delete-phenotypes-selected"
+        method="POST"
+        action="{{url_for('species.populations.phenotypes.delete_phenotypes',
+                species_id=species.SpeciesId,
+                population_id=population.Id,
+                dataset_id=dataset.Id)}}">
+    <div class="row">
+      <div class="col">
+        <input class="btn btn-info"
+               type="submit"
+               title="Cancel delete and return to dataset page."
+               name="action"
+               value="cancel" /></div>
+      <div class="col">
+        <input id="btn-delete-phenotypes-selected"
+               class="btn btn-danger"
+               type="submit"
+               title="Delete the selected phenotypes from this dataset."
+               name="action"
+               value="delete" />
+      </div>
+    </div>
+  </form>
+</div>
+{%else%}
+<div class="row">
+  <p>You did not select any phenotypes to delete. Delete everything?</p>
+</div>
+
+<div class="row">
+  <form id="frm-delete-phenotypes-all"
+        method="POST"
+        action="{{url_for('species.populations.phenotypes.delete_phenotypes',
+                species_id=species.SpeciesId,
+                population_id=population.Id,
+                dataset_id=dataset.Id)}}">
+    <div class="form-check">
+      <input class="form-check-input"
+             type="checkbox"
+             name="confirm_delete_all_phenotypes"
+             id="chk-confirm-delete-all-phenotypes" />
+      <label class="form-check-label"
+             for="chk-confirm-delete-all-phenotypes">
+        delete all phenotypes?</label>
+    </div>
+
+    <div class="row">
+      <div class="col">
+        <input class="btn btn-info"
+               type="submit"
+               title="Cancel delete and return to dataset page."
+               name="action"
+               value="cancel" /></div>
+      <div class="col">
+        <input class="btn btn-danger"
+               type="submit"
+               title="Delete all phenotypes in this dataset."
+               name="action"
+               value="delete" />
+      </div>
+    </div>
+  </form>
+</div>
+{%endif%}
+
+{%endblock%}
+
+{%block javascript%}
+<script type="text/javascript">
+  $(function() {
+      var dt = buildDataTable(
+          "#tbl-delete-phenotypes",
+          data=[],
+          columns=[],
+          userSettings={
+              responsive: true,
+              select: {
+                  style: "os",
+                  info: false
+              },
+              initComplete: function(setting, json) {
+                  var api = this.api();
+                  api.rows().select();
+                  api.rows({selected: true}).nodes().each((node, index) => {
+                      setRowChecked(node);
+                  });
+              }
+          });
+
+      $("#btn-select-all-phenotypes").on("click", function(event) {
+          dt.selectAll();
+      });
+
+      $("#btn-deselect-all-phenotypes").on("click", function(event) {
+          dt.deselectAll();
+      });
+
+      $("#btn-delete-phenotypes-selected").on("click", function(event) {
+          event.preventDefault();
+          form = $("#frm-delete-phenotypes-selected");
+          form.find(".dynamically-added-element").remove();
+          dt.rows({selected: true}).nodes().each(function(node, index) {
+              var xref_id = $(node)
+                  .find('input[type="checkbox"]:checked')
+                  .val();
+              var chk = $('<input type="checkbox">');
+              chk.attr("class", "dynamically-added-element");
+              chk.attr("value", xref_id);
+              chk.attr("name", "xref_ids");
+              chk.attr("style", "display: none");
+              chk.prop("checked", true);
+              form.append(chk);
+          });
+          form.append(
+              $('<input type="hidden" name="action" value="delete" />'));
+          form.submit();
+      })
+  });
+</script>
+{%endblock%}
+
diff --git a/uploader/templates/phenotypes/job-status.html b/uploader/templates/phenotypes/job-status.html
index 257f726..0bbe8e0 100644
--- a/uploader/templates/phenotypes/job-status.html
+++ b/uploader/templates/phenotypes/job-status.html
@@ -2,7 +2,6 @@
 {%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 job and job.status not in ("success", "completed:success", "error", "completed:error")%}
@@ -14,23 +13,13 @@
 
 {%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%}
-<h4 class="subheading">Progress</h4>
+<div class="row">
+  <h2 class="heading">{{dataset.FullName}} ({{dataset.Name}})</h2>
+  <h3 class="subheading">upload progress</h3>
+</div>
 <div class="row" style="overflow:scroll;">
   <p><strong>Process Status:</strong> {{job.status}}</p>
   {%if metadata%}
@@ -80,7 +69,7 @@
   {%endif%}
 </div>
 
-<h4 class="subheading">Errors</h4>
+<h3 class="subheading">upload errors</h3>
 <div class="row" style="max-height: 20em; overflow: scroll;">
   {%if errors | length == 0 %}
   <p class="text-info">
@@ -149,7 +138,3 @@
 </div>
 {%endif%}
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_pheno_dataset_card(species, population, dataset)}}
-{%endblock%}
diff --git a/uploader/templates/phenotypes/load-phenotypes-success.html b/uploader/templates/phenotypes/load-phenotypes-success.html
index 645be16..1fb0e61 100644
--- a/uploader/templates/phenotypes/load-phenotypes-success.html
+++ b/uploader/templates/phenotypes/load-phenotypes-success.html
@@ -1,26 +1,14 @@
 {%extends "phenotypes/base.html"%}
 {%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 title%}Phenotypes{%endblock%}
 
 {%block pagetitle%}Phenotypes{%endblock%}
 
-{%block lvl4_breadcrumbs%}
-<li {%if activelink=="load-phenotypes-success"%}
-    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)}}">Add Phenotypes</a>
-</li>
-{%endblock%}
-
 {%block contents%}
+{{super()}}
+
 <div class="row">
   <p>You have successfully loaded
     <!-- maybe indicate the number of phenotypes here? -->your
@@ -34,9 +22,5 @@
 </div>
 {%endblock%}
 
-{%block sidebarcontents%}
-{{display_pheno_dataset_card(species, population, dataset)}}
-{%endblock%}
-
 
 {%block more_javascript%}{%endblock%}
diff --git a/uploader/templates/phenotypes/macro-display-preview-table.html b/uploader/templates/phenotypes/macro-display-preview-table.html
index 5a4c422..6dffe9f 100644
--- a/uploader/templates/phenotypes/macro-display-preview-table.html
+++ b/uploader/templates/phenotypes/macro-display-preview-table.html
@@ -1,19 +1,11 @@
 {%macro display_preview_table(tableid, filetype)%}
-<div class="card">
-  <div class="card-body">
-    <h5 class="card-title">{{filetype | title}}: File Preview</h5>
-    <div class="card-text" style="overflow: scroll;">
-      <table id="{{tableid}}" class="table table-condensed table-responsive">
-        <thead>
-          <tr>
-          </tr>
-        <tbody>
-          <tr>
-            <td class="data-row-template text-info"></td>
-          </tr>
-        </tbody>
-      </table>
-    </div>
-  </div>
+<div class="table-responsive"
+     style="max-width:39.2em;border-radius:5px;border: solid 1px;overflow-x: scroll;">
+  <h5>{{filetype | title}}: File Preview</h5>
+  <table id="{{tableid}}" class="table">
+    <thead><tr></tr></thead>
+
+    <tbody></tbody>
+  </table>
 </div>
 {%endmacro%}
diff --git a/uploader/templates/phenotypes/review-job-data.html b/uploader/templates/phenotypes/review-job-data.html
index 859df74..c8355b2 100644
--- a/uploader/templates/phenotypes/review-job-data.html
+++ b/uploader/templates/phenotypes/review-job-data.html
@@ -104,10 +104,6 @@
 {%endif%}
 {%endblock%}
 
-{%block sidebarcontents%}
-{{display_pheno_dataset_card(species, population, dataset)}}
-{%endblock%}
-
 
 {%block javascript%}
 <script type="text/javascript">
diff --git a/uploader/templates/phenotypes/sui-add-phenotypes-base.html b/uploader/templates/phenotypes/sui-add-phenotypes-base.html
deleted file mode 100644
index 1e71267..0000000
--- a/uploader/templates/phenotypes/sui-add-phenotypes-base.html
+++ /dev/null
@@ -1,155 +0,0 @@
-{%extends "phenotypes/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "macro-table-pagination.html" import table_pagination%}
-
-{%block title%}Phenotypes{%endblock%}
-
-{%block pagetitle%}Phenotypes{%endblock%}
-
-{%block contents%}
-{{super()}}
-{{flash_all_messages()}}
-
-<div class="row">
-  <form id="frm-add-phenotypes"
-        method="POST"
-        enctype="multipart/form-data"
-        action="{{url_for('species.populations.phenotypes.add_phenotypes',
-                species_id=species.SpeciesId,
-                population_id=population.Id,
-                dataset_id=dataset.Id,
-                use_bundle=use_bundle)}}"
-        data-resumable-target="{{url_for('files.resumable_upload_post')}}">
-    <legend>Add New Phenotypes</legend>
-
-    <div class="form-text help-block">
-      {%block frm_add_phenotypes_documentation%}{%endblock%}
-      <p><strong class="text-warning">This will not update any existing phenotypes!</strong></p>
-    </div>
-
-    {%block frm_add_phenotypes_elements%}{%endblock%}
-
-    <fieldset id="fldset-publication-info">
-      <legend>Publication Information</legend>
-      <input type="hidden" name="publication-id" id="txt-publication-id" />
-      <span class="form-text text-muted">
-        Select a publication for your data. <br />
-        Can't find a publication you can use? Go ahead and
-        <a href="{{url_for(
-                 'publications.create_publication',
-                 return_to='species.populations.phenotypes.add_phenotypes',
-                 species_id=species.SpeciesId,
-                 population_id=population.Id,
-                 dataset_id=dataset.Id)}}">create a new publication</a>.</span>
-      <table id="tbl-select-publication" class="table compact stripe">
-        <thead>
-          <tr>
-            <th>#</th>
-            <th>PubMed ID</th>
-            <th>Title</th>
-            <th>Authors</th>
-          </tr>
-        </thead>
-
-        <tbody></tbody>
-      </table>
-    </fieldset>
-
-    <div class="form-group">
-      <input type="submit"
-             value="upload phenotypes"
-             class="btn btn-primary" />
-    </div>
-  </form>
-</div>
-
-<div class="row">
-  {%block page_documentation%}{%endblock%}
-</div>
-
-{%endblock%}
-
-
-
-
-{%block javascript%}
-<script type="text/javascript">
-  $(function() {
-      var publicationsDataTable = buildDataTable(
-          "#tbl-select-publication",
-          [],
-          [
-              {data: "index"},
-              {
-                  searchable: true,
-                  data: (pub) => {
-                      if(pub.PubMed_ID) {
-                          return `<a href="https://pubmed.ncbi.nlm.nih.gov/` +
-                              `${pub.PubMed_ID}/" target="_blank" ` +
-                              `title="Link to publication on NCBI.">` +
-                              `${pub.PubMed_ID}</a>`;
-                      }
-                      return "";
-                  }
-              },
-              {
-                  searchable: true,
-                  data: (pub) => {
-                      var title = "⸻";
-                      if(pub.Title) {
-                          title = pub.Title
-                      }
-                      return `<a href="/publications/view/${pub.Id}" ` +
-                          `target="_blank" ` +
-                          `title="Link to view publication details">` +
-                          `${title}</a>`;
-                  }
-              },
-              {
-                  searchable: true,
-                  data: (pub) => {
-                      authors = pub.Authors.split(",").map(
-                          (item) => {return item.trim();});
-                      if(authors.length > 1) {
-                          return authors[0] + ", et. al.";
-                      }
-                      return authors[0];
-                  }
-              }
-          ],
-          {
-              serverSide: true,
-              ajax: {
-                  url: "/publications/list",
-                  dataSrc: "publications"
-              },
-              select: "single",
-              paging: true,
-              scrollY: 700,
-              deferRender: true,
-              scroller: true,
-              scrollCollapse: true,
-              layout: {
-                  topStart: "info",
-                  topEnd: "search"
-              }
-          });
-      publicationsDataTable.on("select", (event, datatable, type, indexes) => {
-          indexes.forEach((element, index, thearray) => {
-              let row = datatable.row(element).node();
-              console.debug(datatable.row(element).data());
-              $("#frm-add-phenotypes #txt-publication-id").val(
-                  datatable.row(element).data().Id);
-          });
-      });
-      publicationsDataTable.on("deselect", (event, datatable, type, indexes) => {
-          indexes.forEach((element, index, thearray) => {
-              let row = datatable.row(element).node();
-              $("#frm-add-phenotypes #txt-publication-id").val(null);
-          });
-      });
-  });
-</script>
-
-{%block more_javascript%}{%endblock%}
-{%endblock%}
diff --git a/uploader/templates/phenotypes/sui-add-phenotypes-raw-files.html b/uploader/templates/phenotypes/sui-add-phenotypes-raw-files.html
deleted file mode 100644
index 6038617..0000000
--- a/uploader/templates/phenotypes/sui-add-phenotypes-raw-files.html
+++ /dev/null
@@ -1,829 +0,0 @@
-{%extends "phenotypes/sui-add-phenotypes-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "macro-table-pagination.html" import table_pagination%}
-{%from "phenotypes/macro-display-preview-table.html" import display_preview_table%}
-{%from "phenotypes/macro-display-resumable-elements.html" import display_resumable_elements%}
-
-{%block title%}Phenotypes{%endblock%}
-
-{%block pagetitle%}Phenotypes{%endblock%}
-
-{%block frm_add_phenotypes_documentation%}
-<p>This page will allow you to upload all the separate files that make up your
-  phenotypes. Here, you will have to upload each separate file individually. If
-  you want instead to upload all your files as a single ZIP file,
-  <a href="{{url_for('species.populations.phenotypes.add_phenotypes',
-           species_id=species.SpeciesId,
-           population_id=population.Id,
-           dataset_id=dataset.Id,
-           use_bundle=true)}}"
-     title="">click here</a>.</p>
-{%endblock%}
-
-{%block frm_add_phenotypes_elements%}
-<fieldset id="fldset-file-metadata">
-  <legend>File(s) Metadata</legend>
-  <div class="form-group">
-    <label for="txt-file-separator" class="form-label">File Separator</label>
-    <div class="input-group">
-      <input id="txt-file-separator"
-             name="file-separator"
-             type="text"
-             value="&#9;"
-             class="form-control"
-             maxlength="1" />
-      <span class="input-group-btn">
-        <button id="btn-reset-file-separator" class="btn btn-info">Reset Default</button>
-      </span>
-    </div>
-    <span class="form-text text-muted">
-      Provide the character that separates the fields in your file(s). It should
-      be the same character for all files (if more than one is provided).<br />
-      A tab character will be assumed if you leave this field blank. See
-      <a href="#docs-file-separator"
-         title="Documentation for file-separator characters">
-        documentation for more information</a>.
-    </span>
-  </div>
-
-  <div class="form-group">
-    <label for="txt-file-comment-character" class="form-label">File Comment-Character</label>
-    <div class="input-group">
-      <input id="txt-file-comment-character"
-             name="file-comment-character"
-             type="text"
-             value="#"
-             class="form-control"
-             maxlength="1" />
-      <span class="input-group-btn">
-        <button id="btn-reset-file-comment-character" class="btn btn-info">
-          Reset Default</button>
-      </span>
-    </div>
-    <span class="form-text text-muted">
-      This specifies that lines that begin with the character provided will be
-      considered comment lines and ignored in their entirety. See
-      <a href="#docs-file-comment-character"
-         title="Documentation for comment characters">
-        documentation for more information</a>.
-    </span>
-  </div>
-
-  <div class="form-group">
-    <label for="txt-file-na" class="form-label">File "No-Value" Indicators</label>
-    <div class="input-group">
-      <input id="txt-file-na"
-             name="file-na"
-             type="text"
-             value="- NA N/A"
-             class="form-control" />
-      <span class="input-group-btn">
-        <button id="btn-reset-file-na" class="btn btn-info">Reset Default</button>
-      </span>
-    </div>
-    <span class="form-text text-muted">
-      This specifies strings in your file indicate that there is no value for a
-      particular cell (a cell is where a column and row intersect). Provide a
-      space-separated list of strings if you have more than one way of
-      indicating no values. See
-      <a href="#docs-file-na" title="Documentation for no-value fields">
-        documentation for more information</a>.</span>
-  </div>
-</fieldset>
-
-<fieldset id="fldset-files">
-  <legend>Data File(s)</legend>
-
-  <fieldset id="fldset-descriptions-file">
-    <div class="form-group">
-      <div class="form-check">
-        <input id="chk-phenotype-descriptions-transposed"
-               name="phenotype-descriptions-transposed"
-               type="checkbox"
-               class="form-check-input"
-               style="border: solid #8EABF0" />
-        <label for="chk-phenotype-descriptions-transposed"
-               class="form-check-label">
-          Description file transposed?</label>
-      </div>
-
-      <div class="non-resumable-elements">
-        <label for="finput-phenotype-descriptions" class="form-label">
-          Phenotype Descriptions</label>
-        <input id="finput-phenotype-descriptions"
-               name="phenotype-descriptions"
-               class="form-control"
-               type="file"
-               data-preview-table="tbl-preview-pheno-desc"
-               required="required"  />
-        <span class="form-text text-muted">
-          Provide a file that contains only the phenotype descriptions,
-          <a href="#docs-file-phenotype-description"
-             title="Documentation of the phenotype data file format.">
-            the documentation for the expected format of the file</a>.</span>
-      </div>
-      {{display_resumable_elements(
-      "resumable-phenotype-descriptions",
-      "phenotype descriptions",
-      '<p>Drag and drop the CSV file that contains the descriptions of your
-        phenotypes here.</p>
-
-      <p>The CSV file should be a matrix of
-        <strong>phenotypes × descriptions</strong> i.e. The first column
-        contains the phenotype names/identifiers whereas the first row is a list
-        of metadata fields like, "description", "units", etc.</p>
-
-      <p>If the format is transposed (i.e.
-        <strong>descriptions × phenotypes</strong>) select the checkbox above.
-      </p>
-
-      <p>Please see the
-        <a href="#docs-file-phenotype-description"
-           title="Documentation of the phenotype data file format.">
-          "Phenotypes Descriptions" documentation</a> section below for more
-        information on the expected format of the file provided here.</p>')}}
-      {{display_preview_table(
-      "tbl-preview-pheno-desc", "phenotype descriptions")}}
-    </div>
-  </fieldset>
-
-
-  <fieldset id="fldset-data-file">
-    <div class="form-group">
-      <div class="form-check">
-        <input id="chk-phenotype-data-transposed"
-               name="phenotype-data-transposed"
-               type="checkbox"
-               class="form-check-input"
-               style="border: solid #8EABF0" />
-        <label for="chk-phenotype-data-transposed" class="form-check-label">
-          Data file transposed?</label>
-      </div>
-
-      <div class="non-resumable-elements">
-        <label for="finput-phenotype-data" class="form-label">Phenotype Data</label>
-        <input id="finput-phenotype-data"
-               name="phenotype-data"
-               class="form-control"
-               type="file"
-               data-preview-table="tbl-preview-pheno-data"
-               required="required"  />
-        <span class="form-text text-muted">
-          Provide a file that contains only the phenotype data. See
-          <a href="#docs-file-phenotype-data"
-             title="Documentation of the phenotype data file format.">
-            the documentation for the expected format of the file</a>.</span>
-      </div>
-
-      {{display_resumable_elements(
-      "resumable-phenotype-data",
-      "phenotype data",
-      '<p>Drag and drop a CSV file that contains the phenotypes numerical data
-        here. You can click the "Browse" button (below and to the right) to
-        select the file from your computer.</p>
-
-      <p>The CSV should be a matrix of <strong>samples × phenotypes</strong>,
-        i.e. The first column contains the samples identifiers while the first
-        row is the list of phenotypes identifiers occurring in the phenotypes
-        descriptions file.</p>
-
-      <p>If the format is transposed (i.e <strong>phenotypes × samples</strong>)
-        select the checkbox above.</p>
-      <p>Please see the
-        <a href="#docs-file-phenotype-data"
-           title="Documentation of the phenotype data file format.">
-          "Phenotypes Data" documentation</a> section below for more information
-        on the expected format for the file provided here.</p>')}}
-      {{display_preview_table("tbl-preview-pheno-data", "phenotype data")}}
-    </div>
-  </fieldset>
-
-  
-  {%if population.Family in families_with_se_and_n%}
-  <fieldset id="fldset-se-file">
-    <div class="form-group">
-      <div class="form-check">
-        <input id="chk-phenotype-se-transposed"
-               name="phenotype-se-transposed"
-               type="checkbox"
-               class="form-check-input"
-               style="border: solid #8EABF0" />
-        <label for="chk-phenotype-se-transposed" class="form-check-label">
-          Standard-Errors file transposed?</label>
-      </div>
-      <div class="group non-resumable-elements">
-        <label for="finput-phenotype-se" class="form-label">Phenotype: Standard Errors</label>
-        <input id="finput-phenotype-se"
-               name="phenotype-se"
-               class="form-control"
-               type="file"
-               data-preview-table="tbl-preview-pheno-se"
-               required="required"  />
-        <span class="form-text text-muted">
-          Provide a file that contains only the standard errors for the phenotypes,
-          computed from the data above.</span>
-      </div>
-
-      {{display_resumable_elements(
-      "resumable-phenotype-se",
-      "standard errors",
-      '<p>Drag and drop a CSV file that contains the phenotypes standard-errors
-        data here. You can click the "Browse" button (below and to the right) to
-        select the file from your computer.</p>
-
-      <p>The CSV should be a matrix of <strong>samples × phenotypes</strong>,
-        i.e. The first column contains the samples identifiers while the first
-        row is the list of phenotypes identifiers occurring in the phenotypes
-        descriptions file.</p>
-
-      <p>If the format is transposed (i.e <strong>phenotypes × samples</strong>)
-        select the checkbox above.</p>
-
-      <p>Please see the
-        <a href="#docs-file-phenotype-se"
-           title="Documentation of the phenotype data file format.">
-          "Phenotypes Data" documentation</a> section below for more information
-        on the expected format of the file provided here.</p>')}}
-
-      {{display_preview_table("tbl-preview-pheno-se", "standard errors")}}
-    </div>
-  </fieldset>
-
-
-  <fieldset id="fldset-n-file">
-    <div class="form-group">
-      <div class="form-check">
-        <input id="chk-phenotype-n-transposed"
-               name="phenotype-n-transposed"
-               type="checkbox"
-               class="form-check-input"
-               style="border: solid #8EABF0" />
-        <label for="chk-phenotype-n-transposed" class="form-check-label">
-          Counts file transposed?</label>
-      </div>
-      <div class="non-resumable-elements">
-        <label for="finput-phenotype-n" class="form-label">Phenotype: Number of Samples/Individuals</label>
-        <input id="finput-phenotype-n"
-               name="phenotype-n"
-               class="form-control"
-               type="file"
-               data-preview-table="tbl-preview-pheno-n"
-               required="required"  />
-        <span class="form-text text-muted">
-          Provide a file that contains only the number of samples/individuals used in
-          the computation of the standard errors above.</span>
-      </div>
-
-      {{display_resumable_elements(
-      "resumable-phenotype-n",
-      "number of samples/individuals",
-      '<p>Drag and drop a CSV file that contains the samples\' phenotypes counts
-        data here. You can click the "Browse" button (below and to the right) to
-        select the file from your computer.</p>
-
-      <p>The CSV should be a matrix of <strong>samples × phenotypes</strong>,
-        i.e. The first column contains the samples identifiers while the first
-        row is the list of phenotypes identifiers occurring in the phenotypes
-        descriptions file.</p>
-
-      <p>If the format is transposed (i.e <strong>phenotypes × samples</strong>)
-        select the checkbox above.</p>
-
-      <p>Please see the
-        <a href="#docs-file-phenotype-se"
-           title="Documentation of the phenotype data file format.">
-          "Phenotypes Data" documentation</a> section below for more information
-        on the expected format of the file provided here.</p>')}}
-
-      {{display_preview_table("tbl-preview-pheno-n", "number of samples/individuals")}}
-    </div>
-  </fieldset>
-</fieldset>
-{%endif%}
-{%endblock%}
-
-
-{%block page_documentation%}
-<div class="row">
-  <h2 class="heading" id="docs-help">Help</h2>
-  <h3 class="subheading">Common Features</h3>
-  <p>The following are the common expectations for <strong>ALL</strong> the
-    files provided in the form above:
-    <ul>
-      <li>The file <strong>MUST</strong> be character-separated values (CSV)
-        text file</li>
-      <li>The first row in the file <strong>MUST</strong> be a heading row, and
-        will be composed of the list identifiers for all of
-        samples/individuals/cases involved in your study.</li>
-      <li>The first column of data in the file <strong>MUST</strong> be the
-        identifiers for all of the phenotypes you wish to upload.</li>
-    </ul>
-  </p>
-
-  <p>If you do not specify the separator character, then we will assume a
-    <strong>TAB</strong> character was used as your separator.</p>
-
-  <p>We also assume you might include comments lines in your files. In that
-    case, if you do not specify what character denotes that a line in your files
-    is a comment line, we will assume the <strong>#</strong> character.<br />
-    A comment <strong>MUST ALWAYS</strong> begin at the start of the line marked
-    with the comment character specified.</p>
-
-  <h3 class="subheading" id="docs-file-metadata">File Metadata</h3>
-  <p>We request some details about your files to help us parse and process the
-    files correctly. The details we collect are:</p>
-  <dl>
-    <dt id="docs-file-separator">File separator</dt>
-    <dd>The files you provide should be character-separated value (CSV) files.
-      We need to know what character you used to separate the values in your
-      file. Some common ones are the Tab character, the comma, etc.<br />
-      Providing that information makes it possible for the system to parse and
-      process your files correctly.<br>
-      <strong>NOTE:</strong> All the files you upload MUST use the same
-      separator.</dd>
-
-    <dt id="docs-file-comment-character">Comment character</dt>
-    <dd>We support use of comment lines in your files. We only support one type
-      of comment style, the <em>line comment</em>.<br />
-      This mean the comment begins at the start of the line, and the end of that
-      line indicates the end of that comment. If you have a really long comment,
-      then you need to break it across multiple lines, marking each line a
-      comment line.<br />
-      The "comment character" is the character at the start of the line that
-      indicates that the line is a line comment.</dd>
-
-    <dt id="docs-file-na">No-Value indicator(s)</dt>
-    <dd>Data in the real world is messy, and in some cases, entirely absent. You
-      need to indicate, in your files, that a particular field did not have a
-      value, and once you do that, you then need to let the system know how you
-      mark such fields. Common ways of indicating "empty values" are, leaving
-      the field blank, using a character such as '-', or using strings like
-      "NA", "N/A", "NULL", etc.<br />
-      Providing this information will help with parsing and processing such
-      no-value fields the correct way.</dd>
-  </dl>
-
-  <h3 class="subheading" id="docs-file-phenotype-description">
-    file: Phenotypes Descriptions</h3>
-  <p>The data in this file is a matrix of <em>phenotypes × metadata-fields</em>.
-    Please note we use the term "metadata-fields" above loosely, due to lack of
-    a good word for this.</p>
-  <p>The file <strong>MUST</strong> have columns in this order:
-    <dl>
-      <dt>Phenotype Identifiers</dt>
-      <dd>These are the names/identifiers for your phenotypes. These
-        names/identifiers are the same ones you will have in all the other files you are
-        uploading.</dd>
-
-      <dt>Descriptions</dt>
-      <dd>Each phenotype will need a description. Good description are necessary
-        to inform other people of what the data is about. Good description are
-        hard to construct, so we provide
-        <a href="https://info.genenetwork.org/faq.php#q-22"
-           title="How to write phenotype descriptions">
-          advice on describing your phenotypes.</a></dd>
-
-      <dt>Units</dt>
-      <dd>Each phenotype will need units for the measurements taken. If there are
-        none, then indicate the field is a no-value field.</dd>
-  </dl></p>
-  <p>You can add more columns after those three if you want to, but these 3
-    <strong>MUST</strong> be present.</p>
-  <p>The file would, for example, look like the following:</p>
-  <code>id,description,units,…<br />
-    pheno10001|Central nervous system, behavior, cognition; …|mg|…<br />
-    pheno10002|Aging, metabolism, central nervous system: …|mg|…<br />
-    â‹®<br /></code>
-
-  <p><strong>Note 01</strong>: The first usable row is the heading row.</p>
-  <p><strong>Note 02: </strong>This example demonstrates a subtle issue that
-    could make your CSV file invalid &mdash; the choice of your field separator
-    character.<br >
-    In the example above, we use the pipe character (<code>|</code>) as our
-    field separator. This is because, if we follow the advice on how to write
-    good descriptions, then we cannot use the comma as our separator &ndash; if
-    we did, then our CSV file would be invalid because the system would have no
-    way to tell the difference between the comma as a field separator, and the
-    comma as a way to separate the "general category and ontology terms".</p>
-
-  <h3 class="subheading">file: Phenotype Data, Standard Errors and/or Sample Counts</h3>
-  <span id="docs-file-phenotype-data"></span>
-  <span id="docs-file-phenotype-se"></span>
-  <span id="docs-file-phenotype-n"></span>
-  <p>The data is a matrix of <em>samples(or individuals) × phenotypes</em>, e.g.</p>
-  <code>
-    # num-cases: 2549
-    # num-phenos: 13
-    id,pheno10001,pheno10002,pheno10003,pheno10004,53.099998,…<br />
-    IND001,61.400002,49,62.5,55.099998,…<br />
-    IND002,54.099998,50.099998,53.299999,55.099998,…<br />
-    IND003,483,403,501,403,…<br />
-    IND004,49.799999,45.5,62.900002,NA,…<br />
-    â‹®<br /></code>
-
-  <p>where <code>IND001,IND002,IND003,IND004,…</code> are the
-    samples/individuals/cases in your study, and
-    <code>pheno10001,pheno10002,pheno10004,pheno10004,…</code> are the
-    identifiers for your phenotypes.</p>
-  <p>The lines beginning with the "<em>#</em>" symbol (i.e.
-    <code># num-cases: 2549</code> and <code># num-phenos: 13</code> are comment
-    lines and will be ignored</p>
-  <p>In this example, the comma (,) is used as the file separator.</p>
-</div>
-
-{%endblock%}
-
-
-{%block more_javascript%}
-<script src="{{url_for('base.node_modules',
-             filename='resumablejs/resumable.js')}}"></script>
-<script type="text/javascript" src="/static/js/files.js"></script>
-
-<script type="text/javascript">
-  $("#btn-reset-file-separator").on("click", (event) => {
-      event.preventDefault();
-      $("#txt-file-separator").val("\t");
-      $("#txt-file-separator").trigger("change");
-  });
-  $("#btn-reset-file-comment-character").on("click", (event) => {
-      event.preventDefault();
-      $("#txt-file-comment-character").val("#");
-      $("#txt-file-comment-character").trigger("change");
-  });
-  $("#btn-reset-file-na").on("click", (event) => {
-      event.preventDefault();
-      $("#txt-file-na").val("- NA N/A");
-      $("#txt-file-na").trigger("change");
-  });
-
-  var update_preview = (table, filedata, formdata, numrows) => {
-      table.find("thead tr").remove()
-      table.find(".data-row").remove();
-      var linenum = 0;
-      var tableheader = table.find("thead");
-      var tablebody = table.find("tbody");
-      var numheadings = 0;
-      var navalues = formdata
-          .na_strings
-          .split(" ")
-          .map((v) => {return v.trim();})
-          .filter((v) => {return Boolean(v);});
-      filedata.forEach((line) => {
-          if(line.startsWith(formdata.comment_char) || linenum >= numrows) {
-              return false;
-          }
-          var row = $("<tr></tr>");
-          line.split(formdata.separator)
-              .map((field) => {
-                  var value = field.trim();
-                  if(navalues.includes(value)) {
-                      return "⋘NUL⋙";
-                  }
-                  return value;
-              })
-              .filter((field) => {
-                  return (field !== "" && field != undefined && field != null);
-              })
-              .forEach((field) => {
-                  if(linenum == 0) {
-                      numheadings += 1;
-                      var tablefield = $("<th></th>");
-                      tablefield.text(field);
-                      row.append(tablefield);
-                  } else {
-                      add_class(row, "data-row");
-                      var tablefield = $("<td></td>");
-                      tablefield.text(field);
-                      row.append(tablefield);
-                  }
-              });
-
-          if(linenum == 0) {
-              tableheader.append(row);
-          } else {
-              tablebody.append(row);
-          }
-          linenum += 1;
-      });
-
-      if(table.find("tbody tr.data-row").length > 0) {
-          add_class(table.find(".data-row-template"), "visually-hidden");
-      } else {
-          remove_class(table.find(".data-row-template"), "visually-hidden");
-      }
-  };
-
-  var makePreviewUpdater = (preview_table) => {
-      return (data) => {
-          update_preview(
-              preview_table,
-              data,
-              filesMetadata(),
-              PREVIEW_ROWS);
-      };
-  };
-
-  var preview_tables_to_elements_map = {
-      "#tbl-preview-pheno-desc": "#finput-phenotype-descriptions",
-      "#tbl-preview-pheno-data": "#finput-phenotype-data",
-      "#tbl-preview-pheno-se": "#finput-phenotype-se",
-      "#tbl-preview-pheno-n": "#finput-phenotype-n"
-  };
-
-  var filesMetadata = () => {
-      return {
-          "separator": $("#txt-file-separator").val(),
-          "comment_char": $(
-              "#txt-file-comment-character").val(),
-          "na_strings": $("#txt-file-na").val()
-      }
-  };
-
-  var PREVIEW_ROWS = 5;
-
-  var handler_update_previews = (event) => {
-      Object.entries(preview_tables_to_elements_map).forEach((mapentry) => {
-          var preview_table = $(mapentry[0]);
-          var file_input = $(mapentry[1]);
-          if(file_input[0].files.length > 0) {
-              readFirstNLines(
-                  file_input[0].files[0],
-                  10,
-                  [makePreviewUpdater(preview_table)]);
-          }
-      });
-
-      if(typeof(resumables) !== "undefined") {
-          resumables.forEach((resumable) => {
-              if(resumable.files.length > 0) {
-                  readFirstNLines(
-                      resumable.files[0].file,
-                      10,
-                      [makePreviewUpdater(resumable.preview_table)]);
-              }
-          });
-      }
-  };
-
-  [
-      "#txt-file-separator",
-      "#txt-file-comment-character",
-      "#txt-file-na"
-  ].forEach((elementid) => {
-      $(elementid).on("change", handler_update_previews);
-  });
-
-  [
-      "#finput-phenotype-descriptions",
-      "#finput-phenotype-data",
-      "#finput-phenotype-se",
-      "#finput-phenotype-n"
-  ].forEach((elementid) => {
-      $(elementid).on("change", (event) => {
-          readFirstNLines(
-              event.target.files[0],
-              10,
-              [makePreviewUpdater(
-                  $("#" + event.target.getAttribute("data-preview-table")))]);
-      });
-  });
-
-
-  var resumableDisplayFiles = (display_area, files) => {
-      files.forEach((file) => {
-          display_area.find(".file-display").remove();
-          var display_element = display_area
-              .find(".file-display-template")
-              .clone();
-          remove_class(display_element, "visually-hidden");
-          remove_class(display_element, "file-display-template");
-          add_class(display_element, "file-display");
-          display_element.find(".filename").text(file.name
-                                                || file.fileName
-                                                || file.relativePath
-                                                || file.webkitRelativePath);
-          display_element.find(".filesize").text(
-              (file.size / (1024*1024)).toFixed(2) + "MB");
-          display_element.find(".fileuniqueid").text(file.uniqueIdentifier);
-          display_element.find(".filemimetype").text(file.file.type);
-          display_area.append(display_element);
-      });
-  };
-
-
-  var indicateProgress = (resumable, progress_bar) => {
-      return () => {/*Has no event!*/
-          var progress = (resumable.progress() * 100).toFixed(2);
-          var pbar = progress_bar.find(".progress-bar");
-          remove_class(progress_bar, "visually-hidden");
-          pbar.css("width", progress+"%");
-          pbar.attr("aria-valuenow", progress);
-          pbar.text("Uploading: " + progress + "%");
-      };
-  };
-
-  var retryUpload = (retry_button, cancel_button) => {
-      retry_button.on("click", (event) => {
-          resumable.files.forEach((file) => {file.retry();});
-          add_class(retry_button, "visually-hidden");
-          remove_class(cancel_button, "visually-hidden");
-          add_class(browse_button, "visually-hidden");
-      });
-  };
-
-  var cancelUpload = (cancel_button, retry_button) => {
-      cancel_button.on("click", (event) => {
-          resumable.files.forEach((file) => {
-              if(file.isUploading()) {
-                  file.abort();
-              }
-          });
-          add_class(cancel_button, "visually-hidden");
-          remove_class(retry_button, "visually-hidden");
-          remove_class(browse_button, "visually-hidden");
-      });
-  };
-
-
-  var startUpload = (browse_button, retry_button, cancel_button) => {
-      return (event) => {
-          remove_class(cancel_button, "visually-hidden");
-          add_class(retry_button, "visually-hidden");
-          add_class(browse_button, "visually-hidden");
-      };
-  };
-
-  var processForm = (form) => {
-      var formdata = new FormData(form);
-      uploaded_files.forEach((msg) => {
-          formdata.delete(msg["file-input-name"]);
-          formdata.append(msg["file-input-name"], JSON.stringify({
-              "uploaded-file": msg["uploaded-file"],
-              "original-name": msg["original-name"]
-          }));
-      });
-      formdata.append("resumable-upload", "true");
-      formdata.append("publication-id", $("#txt-publication-id").val());
-      return formdata;
-  }
-
-  var uploaded_files = new Set();
-  var submitForm = (new_file) => {
-      uploaded_files.add(new_file);
-      if(uploaded_files.size === resumables.length) {
-          var form = $("#frm-add-phenotypes");
-          if(form.length !== 1) {
-              // TODO: Handle error somehow?
-              alert("Could not find form!!!");
-              return false;
-          }
-
-          $.ajax({
-              "url": form.attr("action"),
-              "type": "POST",
-              "data": processForm(form[0]),
-              "processData": false,
-              "contentType": false,
-              "success": (data, textstatus, jqxhr) => {
-                  // TODO: Redirect to endpoint that should come as part of the
-                  //       success/error message.
-                  console.log("SUCCESS DATA: ", data);
-                  console.log("SUCCESS STATUS: ", textstatus);
-                  console.log("SUCCESS jqXHR: ", jqxhr);
-                  window.location.assign(window.location.origin + data["redirect-to"]);
-              },
-          });
-          return false;
-      }
-      return false;
-  };
-
-  var uploadSuccess = (file_input_name) => {
-      return (file, message) => {
-          submitForm({...JSON.parse(message), "file-input-name": file_input_name});
-      };
-  };
-
-
-  var uploadError = () => {
-      return (message, file) => {
-          $("#frm-add-phenotypes input[type=submit]").removeAttr("disabled");
-          console.log("THE FILE:", file);
-          console.log("THE ERROR MESSAGE:", message);
-      };
-  };
-
-
-
-  var makeResumableObject = (form_id, file_input_id, resumable_element_id, preview_table_id) => {
-      var the_form = $("#" + form_id);
-      var file_input = $("#" + file_input_id);
-      var submit_button = the_form.find("input[type=submit]");
-      if(file_input.length != 1) {
-          return false;
-      }
-      var r = errorHandler(
-          fileSuccessHandler(
-              uploadStartHandler(
-                  filesAddedHandler(
-                      markResumableDragAndDropElement(
-                          makeResumableElement(
-                              the_form.attr("data-resumable-target"),
-                              file_input.parent(),
-                              $("#" + resumable_element_id),
-                              submit_button,
-                              ["csv", "tsv", "txt"]),
-                          file_input.parent(),
-                          $("#" + resumable_element_id),
-                          $("#" + resumable_element_id + "-browse-button")),
-                      (files) => {
-                          // TODO: Also trigger preview!
-                          resumableDisplayFiles(
-                              $("#" + resumable_element_id + "-selected-files"), files);
-                          files.forEach((file) => {
-                              readFirstNLines(
-                                  file.file,
-                                  10,
-                                  [makePreviewUpdater(
-                                      $("#" + preview_table_id))])
-                          });
-                      }),
-                  startUpload($("#" + resumable_element_id + "-browse-button"),
-                              $("#" + resumable_element_id + "-retry-button"),
-                              $("#" + resumable_element_id + "-cancel-button"))),
-              uploadSuccess(file_input.attr("name"))),
-          uploadError());
-
-      /** Setup progress indicator **/
-      progressHandler(
-          r,
-          indicateProgress(r, $("#" + resumable_element_id + "-progress-bar")));
-
-      return r;
-  };
-
-  var resumables = [
-      ["frm-add-phenotypes", "finput-phenotype-descriptions", "resumable-phenotype-descriptions", "tbl-preview-pheno-desc"],
-      ["frm-add-phenotypes", "finput-phenotype-data", "resumable-phenotype-data", "tbl-preview-pheno-data"],
-      ["frm-add-phenotypes", "finput-phenotype-se", "resumable-phenotype-se", "tbl-preview-pheno-se"],
-      ["frm-add-phenotypes", "finput-phenotype-n", "resumable-phenotype-n", "tbl-preview-pheno-n"],
-  ].map((row) => {
-      r = makeResumableObject(row[0], row[1], row[2], row[3]);
-      r.preview_table = $("#" + row[3]);
-      return r;
-  }).filter((val) => {
-      return Boolean(val);
-  });
-
-  $("#frm-add-phenotypes input[type=submit]").on("click", (event) => {
-      event.preventDefault();
-      console.debug();
-      if ($("#txt-publication-id").val() == "") {
-          alert("You MUST provide a publication for the phenotypes.");
-          return false;
-      }
-      // TODO: Check all the relevant files exist
-      // TODO: Verify that files are not duplicated
-      var filenames = [];
-      var nondupfiles = [];
-      resumables.forEach((r) => {
-          var fname = r.files[0].file.name;
-          filenames.push(fname);
-          if(!nondupfiles.includes(fname)) {
-              nondupfiles.push(fname);
-          }
-      });
-
-      // Check that all files were provided
-      if(resumables.length !== filenames.length) {
-          window.alert("You MUST provide all the files requested.");
-          event.target.removeAttribute("disabled");
-          return false;
-      }
-
-      // Check that there are no duplicate files
-      var duplicates = Object.entries(filenames.reduce(
-          (acc, curr, idx, arr) => {
-              acc[curr] = (acc[curr] || 0) + 1;
-              return acc;
-          },
-          {})).filter((entry) => {return entry[1] !== 1;});
-      if(duplicates.length > 0) {
-          var msg = "The file(s):\r\n";
-          msg = msg + duplicates.reduce(
-              (msgstr, afile) => {
-                  return msgstr + "  • " + afile[0] + "\r\n";
-              },
-              "");
-          msg = msg + "is(are) duplicated. Please fix and try again.";
-          window.alert(msg);
-          event.target.removeAttribute("disabled");
-          return false;
-      }
-      // TODO: Check all fields
-      // Start the uploads.
-      event.target.setAttribute("disabled", "disabled");
-      resumables.forEach((r) => {r.upload();});
-  });
-</script>
-{%endblock%}
diff --git a/uploader/templates/phenotypes/sui-add-phenotypes-with-rqtl2-bundle.html b/uploader/templates/phenotypes/sui-add-phenotypes-with-rqtl2-bundle.html
deleted file mode 100644
index 29a8dea..0000000
--- a/uploader/templates/phenotypes/sui-add-phenotypes-with-rqtl2-bundle.html
+++ /dev/null
@@ -1,189 +0,0 @@
-{%extends "phenotypes/sui-add-phenotypes-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "macro-table-pagination.html" import table_pagination%}
-
-{%block title%}Phenotypes{%endblock%}
-
-{%block pagetitle%}Phenotypes{%endblock%}
-
-{%block frm_add_phenotypes_documentation%}
-<p>Select the zip file bundle containing information on the phenotypes you
-  wish to upload, then click the "Upload Phenotypes" button below to
-  upload the data.</p>
-<p>If you wish to upload the files individually instead,
-  <a href="{{url_for('species.populations.phenotypes.add_phenotypes',
-           species_id=species.SpeciesId,
-           population_id=population.Id,
-           dataset_id=dataset.Id)}}"
-     title="">click here</a>.</p>
-<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>
-{%endblock%}
-
-{%block frm_add_phenotypes_elements%}
-<div class="form-group">
-  <label for="finput-phenotypes-bundle" class="form-label">
-    Phenotypes Bundle</label>
-  <input type="file"
-         id="finput-phenotypes-bundle"
-         name="phenotypes-bundle"
-         accept="application/zip, .zip"
-	 required="required"
-         class="form-control" />
-</div>
-{%endblock%}
-
-{%block page_documentation%}
-<div class="row">
-  <h2 class="heading" id="section-file-formats">File Formats</h2>
-  <p>We accept an extended form of the
-    <a href="https://kbroman.org/qtl2/assets/vignettes/input_files.html#format-of-the-data-files"
-       title="R/qtl2 software input file format documentation">
-      input files' format used with the R/qtl2 software</a> as a single ZIP
-    file</p>
-  <p>The files that are used for this feature are:
-    <ul>
-      <li>the <em>control</em> file</li>
-      <li><em>pheno</em> file(s)</li>
-      <li><em>phenocovar</em> file(s)</li>
-      <li><em>phenose</em> files(s)</li>
-    </ul>
-  </p>
-  <p>Other files within the bundle will be ignored, for this feature.</p>
-  <p>The following section will detail the expectations for each of the
-    different file types within the uploaded ZIP file bundle for phenotypes:</p>
-
-  <h3 class="subheading">Control File</h3>
-  <p>There <strong>MUST be <em>one, and only one</em></strong> file that acts
-    as the control file. This file can be:
-    <ul>
-      <li>a <em>JSON</em> file, or</li>
-      <li>a <em>YAML</em> file.</li>
-    </ul>
-  </p>
-
-  <p>The control file is useful for defining things about the bundle such as:</p>
-  <ul>
-    <li>The field separator value (default: <code>sep: ','</code>). There can
-      only ever be one field separator and it <strong>MUST</strong> be the same
-      one for <strong>ALL</strong> files in the bundle.</li>
-    <li>The comment character (default: <code>comment.char: '#'</code>). Any
-      line that starts with this character will be considered a comment line and
-      be ignored in its entirety.</li>
-    <li>Code for missing values (default: <code>na.strings: 'NA'</code>). You
-      can specify more than one code to indicate missing values, e.g.
-      <code>{…, "na.strings": ["NA", "N/A", "-"], …}</code></li>
-  </ul>
-
-  <h3 class="subheading"><em>pheno</em> File(s)</h3>
-  <p>These files are the main data files. You must have at least one of these
-    files in your bundle for it to be valid for this step.</p>
-  <p>The data is a matrix of <em>individuals × phenotypes</em> by default, as
-    below:<br />
-    <code>
-      id,10001,10002,10003,10004,…<br />
-      BXD1,61.400002,54.099998,483,49.799999,…<br />
-      BXD2,49,50.099998,403,45.5,…<br />
-      BXD5,62.5,53.299999,501,62.900002,…<br />
-      BXD6,53.099998,55.099998,403,NA,…<br />
-      â‹®<br /></code>
-  </p>
-  <p>If the <code>pheno_transposed</code> value is set to <code>True</code>,
-    then the data will be a <em>phenotypes × individuals</em> matrix as in the
-    example below:<br />
-    <code>
-      id,BXD1,BXD2,BXD5,BXD6,…<br />
-      10001,61.400002,49,62.5,53.099998,…<br />
-      10002,54.099998,50.099998,53.299999,55.099998,…<br />
-      10003,483,403,501,403,…<br />
-      10004,49.799999,45.5,62.900002,NA,…<br />
-      â‹®
-    </code>
-  </p>
-
-
-  <h3 class="subheading"><em>phenocovar</em> File(s)</h3>
-  <p>At least one phenotypes metadata file with the metadata values such as
-    descriptions, PubMed Identifier, publication titles (if present), etc.</p>
-  <p>The data in this/these file(s) is a matrix of
-    <em>phenotypes × phenotypes-covariates</em>. The first column is always the
-    phenotype names/identifiers — same as in the R/qtl2 format.</p>
-  <p><em>phenocovar</em> files <strong>should never be transposed</strong>!</p>
-  <p>This file <strong>MUST</strong> be present in the bundle, and have data for
-    the bundle to be considered valid by our system for this step.<br />
-    In addition to that, the following are the fields that <strong>must be
-      present</strong>, and
-    have values, in the file before the file is considered valid:
-    <ul>
-      <li><em>description</em>: A description for each phenotype. Useful
-        for users to know what the phenotype is about.</li>
-      <li><em>units</em>: The units of measurement for the phenotype,
-        e.g. milligrams for brain weight, centimetres/millimetres for
-        tail-length, etc.</li>
-  </ul></p>
-
-  <p>The following <em>optional</em> fields can also be provided:
-    <ul>
-      <li><em>pubmedid</em>: A PubMed Identifier for the publication where
-        the phenotype is published. If this field is not provided, the system will
-        assume your phenotype is not published.</li>
-    </ul>
-  </p>
-  <p>These files will be marked up in the control file with the
-    <code>phenocovar</code> key, as in the examples below:
-    <ol>
-      <li>JSON: single file<br />
-        <code>{<br />
-          &nbsp;&nbsp;â‹®,<br />
-          &nbsp;&nbsp;"phenocovar": "your_covariates_file.csv",<br />
-          &nbsp;&nbsp;â‹®<br />
-          }
-        </code>
-      </li>
-      <li>JSON: multiple files<br />
-        <code>{<br />
-          &nbsp;&nbsp;â‹®,<br />
-          &nbsp;&nbsp;"phenocovar": [<br />
-          &nbsp;&nbsp;&nbsp;&nbsp;"covariates_file_01.csv",<br />
-          &nbsp;&nbsp;&nbsp;&nbsp;"covariates_file_01.csv",<br />
-          &nbsp;&nbsp;&nbsp;&nbsp;â‹®<br />
-          &nbsp;&nbsp;],<br />
-          &nbsp;&nbsp;â‹®<br />
-          }
-        </code>
-      </li>
-      <li>YAML: single file or<br />
-        <code>
-          â‹®<br />
-          phenocovar: your_covariates_file.csv<br />
-          â‹®
-        </code>
-      </li>
-      <li>YAML: multiple files<br />
-        <code>
-          â‹®<br />
-          phenocovar:<br />
-          - covariates_file_01.csv<br />
-          - covariates_file_02.csv<br />
-          - covariates_file_03.csv<br />
-          …<br />
-          â‹®
-        </code>
-      </li>
-    </ol>
-  </p>
-
-  <h3 class="subheading"><em>phenose</em> and <em>phenonum</em> File(s)</h3>
-  <p>These are extensions to the R/qtl2 standard, i.e. these types ofs file are
-    not supported by the original R/qtl2 file format</p>
-  <p>We use these files to upload the standard errors (<em>phenose</em>) when
-    the data file (<em>pheno</em>) is average data. In that case, the
-    <em>phenonum</em> file(s) contains the number of individuals that were
-    involved when computing the averages.</p>
-  <p>Both types of files are matrices of <em>individuals × phenotypes</em> by
-    default. Like the related <em>pheno</em> files, if
-    <code>pheno_transposed: True</code>, then the file will be a matrix of
-    <em>phenotypes × individuals</em>.</p>
-</div>
-{%endblock%}
diff --git a/uploader/templates/phenotypes/sui-base.html b/uploader/templates/phenotypes/sui-base.html
deleted file mode 100644
index d7d980f..0000000
--- a/uploader/templates/phenotypes/sui-base.html
+++ /dev/null
@@ -1,25 +0,0 @@
-{%extends "populations/sui-base.html"%}
-{%from "phenotypes/macro-display-pheno-dataset-card.html" import display_sui_pheno_dataset_card%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('species.populations.phenotypes.view_dataset',
-           species_id=species['SpeciesId'],
-           population_id=population['Id'],
-           dataset_id=dataset['Id'])}}">
-    {{dataset["Name"]}}
-  </a>
-</li>
-{%endblock%}
-
-{%block contents%}
-<div class="row">
-  <h2 class="heading">{{dataset.FullName}} ({{dataset.Name}})</h2>
-</div>
-{%endblock%}
-
-
-{%block sidebarcontents%}
-{{display_sui_pheno_dataset_card(species, population, dataset)}}
-{%endblock%}
diff --git a/uploader/templates/phenotypes/sui-job-status.html b/uploader/templates/phenotypes/sui-job-status.html
deleted file mode 100644
index bca87d5..0000000
--- a/uploader/templates/phenotypes/sui-job-status.html
+++ /dev/null
@@ -1,140 +0,0 @@
-{%extends "phenotypes/sui-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%}
-
-{%block extrameta%}
-{%if job and job.status not in ("success", "completed:success", "error", "completed:error")%}
-<meta http-equiv="refresh" content="5" />
-{%endif%}
-{%endblock%}
-
-{%block title%}Phenotypes{%endblock%}
-
-{%block pagetitle%}Phenotypes{%endblock%}
-
-{%block contents%}
-
-{%if job%}
-<div class="row">
-  <h2 class="heading">{{dataset.FullName}} ({{dataset.Name}})</h2>
-  <h3 class="subheading">upload progress</h3>
-</div>
-<div class="row" style="overflow:scroll;">
-  <p><strong>Process Status:</strong> {{job.status}}</p>
-  {%if metadata%}
-  <table class="table table-responsive">
-    <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%}
-</div>
-
-<div class="row">
-  {%if  job.status in ("completed:success", "success")%}
-  <p>
-    {%if errors | length == 0%}
-    <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"
-          disabled="disabled"
-          style="border: solid 2px;border-radius: 5px;padding: 0.3em;">
-      Cannot continue due to errors. Please fix the errors first.
-    </span>
-    {%endif%}
-  </p>
-  {%endif%}
-</div>
-
-<h3 class="subheading">upload errors</h3>
-<div class="row" style="max-height: 20em; overflow: scroll;">
-  {%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 table-responsive">
-    <thead style="position: sticky; top: 0; background: white;">
-      <tr>
-        <th>File</th>
-        <th>Row</th>
-        <th>Column</th>
-        <th>Value</th>
-        <th>Message</th>
-      </tr>
-    </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 is not none and 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>
-
-<div class="row">
-  {{cli_output(job, "stderr")}}
-</div>
-
-{%else%}
-<div class="row">
-  <h3 class="text-danger">No Such Job</h3>
-  <p>Could not find a job with the ID: {{job_id}}</p>
-  <p>
-    Please go back to
-    <a href="{{url_for('species.populations.phenotypes.view_dataset',
-             species_id=species.SpeciesId,
-             population_id=population.Id,
-             dataset_id=dataset.Id)}}"
-       title="'{{dataset.Name}}' dataset page">
-      the '{{dataset.Name}}' dataset page</a>
-    to upload new phenotypes or edit existing ones.</p>
-</div>
-{%endif%}
-{%endblock%}
diff --git a/uploader/templates/phenotypes/sui-load-phenotypes-success.html b/uploader/templates/phenotypes/sui-load-phenotypes-success.html
deleted file mode 100644
index dff0682..0000000
--- a/uploader/templates/phenotypes/sui-load-phenotypes-success.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{%extends "phenotypes/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "macro-table-pagination.html" import table_pagination%}
-
-{%block title%}Phenotypes{%endblock%}
-
-{%block pagetitle%}Phenotypes{%endblock%}
-
-{%block contents%}
-{{super()}}
-
-<div class="row">
-  <p>You have successfully loaded
-    <!-- maybe indicate the number of phenotypes here? -->your
-    new phenotypes into the database.</p>
-  <!-- TODO: Maybe notify user that they have sole access. -->
-  <!-- TODO: Maybe provide a link to go to GeneNetwork to view the data. -->
-  <p>View your data
-    <a href="{{search_page_uri}}"
-       target="_blank">on GeneNetwork2</a>.
-    You might need to login to GeneNetwork2 to view specific traits.</p>
-</div>
-{%endblock%}
-
-
-{%block more_javascript%}{%endblock%}
diff --git a/uploader/templates/phenotypes/sui-review-job-data.html b/uploader/templates/phenotypes/sui-review-job-data.html
deleted file mode 100644
index ea4183d..0000000
--- a/uploader/templates/phenotypes/sui-review-job-data.html
+++ /dev/null
@@ -1,121 +0,0 @@
-{%extends "phenotypes/sui-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 class="text-info"><strong>
-      The data has <em>NOT</em> been added/saved yet. Review the details below
-      and click "Continue" to save the data.</strong></p>
-  <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>
-
-  <ul>
-    {%if publication%}
-    <li>All {{summary.get("pheno", {}).get("total-data-rows", "0")}} phenotypes
-      are linked to the following publication:
-      <ul>
-        <li><strong>Publication Title:</strong>
-          {{publication.Title or "—"}}</li>
-        <li><strong>Author(s):</strong>
-          {{publication.Authors or "—"}}</li>
-      </ul>
-    </li>
-    {%endif%}
-  {%for ftype in ("phenocovar", "pheno", "phenose", "phenonum")%}
-  {%if summary.get(ftype, False)%}
-    <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>
-  {%endif%}
-  {%endfor%}
-  </ul>
-
-  <form id="frm-review-phenotype-data"
-        method="POST"
-        action="{{url_for('species.populations.phenotypes.load_data_to_database',
-                species_id=species.SpeciesId,
-                population_id=population.Id,
-                dataset_id=dataset.Id)}}">
-    <input type="hidden" name="data-qc-job-id" value="{{job.jobid}}" />
-    <input type="submit"
-           value="continue"
-           class="btn btn-primary" />
-  </form>
-</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 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%}
diff --git a/uploader/templates/phenotypes/sui-view-dataset.html b/uploader/templates/phenotypes/sui-view-dataset.html
deleted file mode 100644
index f858c4e..0000000
--- a/uploader/templates/phenotypes/sui-view-dataset.html
+++ /dev/null
@@ -1,207 +0,0 @@
-{%extends "phenotypes/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "macro-table-pagination.html" import table_pagination%}
-
-{%block title%}Phenotypes{%endblock%}
-
-{%block pagetitle%}Phenotypes{%endblock%}
-
-{%block lvl4_breadcrumbs%}
-<li {%if activelink=="view-dataset"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('species.populations.phenotypes.view_dataset',
-           species_id=species.SpeciesId,
-           population_id=population.Id,
-           dataset_id=dataset.Id)}}">View</a>
-</li>
-{%endblock%}
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <p>The basic dataset details are:</p>
-
-  <table class="table">
-    <thead>
-      <tr>
-        <th>Name</th>
-        <th>Full Name</th>
-        <th>Short Name</th>
-      </tr>
-    </thead>
-
-    <tbody>
-      <tr>
-        <td>{{dataset.Name}}</td>
-        <td>{{dataset.FullName}}</td>
-        <td>{{dataset.ShortName}}</td>
-      </tr>
-    </tbody>
-  </table>
-</div>
-
-<div class="row">
-  <div class="col">
-    <a href="{{url_for('species.populations.phenotypes.add_phenotypes',
-             species_id=species.SpeciesId,
-             population_id=population.Id,
-             dataset_id=dataset.Id)}}"
-       title="Add a bunch of phenotypes"
-       class="btn btn-primary">Add phenotypes</a>
-  </div>
-
-  <div class="col">
-    <form id="frm-recompute-phenotype-means"
-          method="POST"
-          action="{{url_for(
-                  'species.populations.phenotypes.recompute_means',
-                  species_id=species['SpeciesId'],
-                  population_id=population['Id'],
-                  dataset_id=dataset['Id'])}}"
-          class="d-flex flex-row align-items-center flex-wrap"
-          style="display: inline;">
-      <input type="submit"
-             title="Compute/Recompute the means for all phenotypes."
-             class="btn btn-info"
-             value="(rec/c)ompute means"
-             id="submit-frm-recompute-phenotype-means" />
-    </form>
-  </div>
-
-  <div class="col">
-    <form id="frm-run-qtlreaper"
-          method="POST"
-          action="{{url_for(
-                  'species.populations.phenotypes.rerun_qtlreaper',
-                  species_id=species['SpeciesId'],
-                  population_id=population['Id'],
-                  dataset_id=dataset['Id'])}}"
-          class="d-flex flex-row align-items-center flex-wrap"
-          style="display: inline;">
-      <input type="submit"
-             title="Run/Rerun QTLReaper."
-             class="btn btn-info"
-             value="(re)run QTLReaper"
-             id="submit-frm-rerun-qtlreaper" />
-    </form>
-  </div>
-</div>
-
-<div class="row">
-  <h2>Phenotype Data</h2>
-
-  <p>Click on any of the phenotypes in the table below to view and edit that
-    phenotype's data.</p>
-  <p>Use the search to filter through all the phenotypes and find specific
-    phenotypes of interest.</p>
-</div>
-
-
-<div class="row">
-
-  <table id="tbl-phenotypes-list" class="table compact stripe cell-border">
-    <thead>
-      <tr>
-        <th></th>
-        <th>Index</th>
-        <th>Record</th>
-        <th>Description</th>
-      </tr>
-    </thead>
-
-    <tbody></tbody>
-  </table>
-</div>
-{%endblock%}
-
-
-{%block javascript%}
-<script type="text/javascript" src="/static/js/urls.js"></script>
-
-<script type="text/javascript">
-  $(function() {
-      var species_id = {{species.SpeciesId}};
-      var population_id = {{population.Id}};
-      var dataset_id = {{dataset.Id}};
-      var dataset_name = "{{dataset.Name}}";
-      var data = {{phenotypes | tojson}};
-
-      var dtPhenotypesList = buildDataTable(
-          "#tbl-phenotypes-list",
-          data,
-          [
-              {
-                  data: function(pheno) {
-                      return `<input type="checkbox" name="selected-phenotypes" `
-                          + `id="chk-selected-phenotypes-${pheno.InbredSetCode}_${pheno.xref_id}" `
-                          + `value="${pheno.InbredSetCode}_${pheno.xref_id}" `
-                          + `class="chk-row-select" />`
-                  }
-              },
-              {data: "sequence_number"},
-              {
-                  data: function(pheno, type, set, meta) {
-                      var spcs_id = {{species.SpeciesId}};
-                      var pop_id = {{population.Id}};
-                      var dtst_id = {{dataset.Id}};
-                      var url = buildURLFromCurrentURL(
-                          (`/species/${spcs_id}` +
-                          `/populations/${pop_id}` +
-                          `/phenotypes/datasets/${dtst_id}` +
-                           `/phenotype/${pheno.xref_id}`));
-                      return `<a href="${url.toString()}" target="_blank">` +
-                          `${pheno.InbredSetCode}_${pheno.xref_id}` +
-                          `</a>`;
-                  }
-              },
-              {
-                  data: function(pheno) {
-                      return (pheno.Post_publication_description ||
-                              pheno.Original_description ||
-                              pheno.Pre_publication_description);
-                  }
-              }
-          ],
-          {
-              select: "multi+shift",
-              layout: {
-                  top1Start: {
-                      pageLength: {
-                          text: "Show _MENU_ of _TOTAL_"
-                      }
-                  },
-                  topStart: "info",
-                  top1End: null
-              },
-              rowId: function(pheno) {
-                  return `${pheno.InbredSetCode}_${pheno.xref_id}`;
-              }
-          });
-
-
-      $("#submit-frm-rerun-qtlreaper").on(
-          "click",
-          function(event) {
-              // (Re)run the QTLReaper script for selected phenotypes.
-              event.preventDefault();
-              var form = $("#frm-run-qtlreaper");
-              form.find(".dynamically-added-element").remove();
-              dtPhenotypesList.rows({selected: true}).nodes().each((node, index) => {
-                  _cloned = $(node).find(".chk-row-select").clone();
-                  _cloned.removeAttr("id");
-                  _cloned.removeAttr("class");
-                  _cloned.attr("style", "display: none;");
-                  _cloned.attr("data-type", "dynamically-added-element");
-                  _cloned.attr("class", "dynamically-added-element checkbox");
-                  _cloned.prop("checked", true);
-                  form.append(_cloned);
-              });
-              form.submit();
-          });
-  });
-</script>
-{%endblock%}
diff --git a/uploader/templates/phenotypes/view-dataset.html b/uploader/templates/phenotypes/view-dataset.html
index c634a48..3bb2586 100644
--- a/uploader/templates/phenotypes/view-dataset.html
+++ b/uploader/templates/phenotypes/view-dataset.html
@@ -1,7 +1,6 @@
 {%extends "phenotypes/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
 {%from "macro-table-pagination.html" import table_pagination%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block title%}Phenotypes{%endblock%}
 
@@ -24,25 +23,12 @@
 {{flash_all_messages()}}
 
 <div class="row">
-  <p>The basic dataset details are:</p>
-
-  <table class="table">
-    <thead>
-      <tr>
-        <th>Name</th>
-        <th>Full Name</th>
-        <th>Short Name</th>
-      </tr>
-    </thead>
+  <h2>Phenotype Data</h2>
 
-    <tbody>
-      <tr>
-        <td>{{dataset.Name}}</td>
-        <td>{{dataset.FullName}}</td>
-        <td>{{dataset.ShortName}}</td>
-      </tr>
-    </tbody>
-  </table>
+  <p>Click on any of the phenotypes in the table below to view and edit that
+    phenotype's data.</p>
+  <p>Use the search to filter through all the phenotypes and find specific
+    phenotypes of interest.</p>
 </div>
 
 <div class="row">
@@ -68,7 +54,7 @@
       <input type="submit"
              title="Compute/Recompute the means for all phenotypes."
              class="btn btn-info"
-             value="(rec/c)ompute means"
+             value="compute means"
              id="submit-frm-recompute-phenotype-means" />
     </form>
   </div>
@@ -86,24 +72,29 @@
       <input type="submit"
              title="Run/Rerun QTLReaper."
              class="btn btn-info"
-             value="(re)run QTLReaper"
+             value="run QTLReaper"
              id="submit-frm-rerun-qtlreaper" />
     </form>
   </div>
-</div>
-
-<div class="row">
-  <h2>Phenotype Data</h2>
 
-  <p>Click on any of the phenotypes in the table below to view and edit that
-    phenotype's data.</p>
-  <p>Use the search to filter through all the phenotypes and find specific
-    phenotypes of interest.</p>
+  <div class="col">
+    <form id="frm-delete-phenotypes"
+          method="POST"
+          action="{{url_for(
+                  'species.populations.phenotypes.delete_phenotypes',
+                  species_id=species['SpeciesId'],
+                  population_id=population['Id'],
+                  dataset_id=dataset['Id'])}}">
+      <input type="submit"
+             class="btn btn-danger"
+             id="btn-delete-phenotypes"
+             title="Delete phenotypes from this dataset. If no phenotypes are selected in the table, this will delete ALL the phenotypes."
+             value="delete phenotypes" />
+    </form>
+  </div>
 </div>
 
-
-<div class="row">
-
+<div class="row" style="margin-top: 0.5em;">
   <table id="tbl-phenotypes-list" class="table compact stripe cell-border">
     <thead>
       <tr>
@@ -119,12 +110,10 @@
 </div>
 {%endblock%}
 
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
-{%endblock%}
-
 
 {%block javascript%}
+<script type="text/javascript" src="/static/js/urls.js"></script>
+
 <script type="text/javascript">
   $(function() {
       var species_id = {{species.SpeciesId}};
@@ -151,11 +140,12 @@
                       var spcs_id = {{species.SpeciesId}};
                       var pop_id = {{population.Id}};
                       var dtst_id = {{dataset.Id}};
-                      return `<a href="/species/${spcs_id}` +
+                      var url = buildURLFromCurrentURL(
+                          (`/species/${spcs_id}` +
                           `/populations/${pop_id}` +
                           `/phenotypes/datasets/${dtst_id}` +
-                          `/phenotype/${pheno.xref_id}` +
-                          `" target="_blank">` +
+                           `/phenotype/${pheno.xref_id}`));
+                      return `<a href="${url.toString()}" target="_blank">` +
                           `${pheno.InbredSetCode}_${pheno.xref_id}` +
                           `</a>`;
                   }
@@ -204,6 +194,33 @@
               });
               form.submit();
           });
+
+      $("#btn-delete-phenotypes").on(
+          "click",
+          function(event) {
+              // Collect selected phenotypes for deletion, if any.
+              event.preventDefault();
+              form = $("#frm-delete-phenotypes");
+              form.find(".dynamically-added-element").remove();
+              $("#tbl-phenotypes-list")
+                  .DataTable()
+                  .rows({selected: true}).
+                  nodes().each(function(node, index) {
+                      var parts = $(node)
+                          .find(".chk-row-select")
+                          .val()
+                          .split("_");
+                      var xref_id = parts[parts.length - 1].trim();
+                      var chk = $('<input type="checkbox">');
+                      chk.attr("class", "dynamically-added-element");
+                      chk.attr("value", xref_id);
+                      chk.attr("name", "xref_ids");
+                      chk.attr("style", "display: none");
+                      chk.prop("checked", true);
+                      form.append(chk);
+                  });
+              form.submit();
+          });
   });
 </script>
 {%endblock%}
diff --git a/uploader/templates/phenotypes/view-phenotype.html b/uploader/templates/phenotypes/view-phenotype.html
index 75e3c1e..a69b024 100644
--- a/uploader/templates/phenotypes/view-phenotype.html
+++ b/uploader/templates/phenotypes/view-phenotype.html
@@ -1,25 +1,10 @@
 {%extends "phenotypes/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block title%}Phenotypes{%endblock%}
 
 {%block pagetitle%}Phenotypes{%endblock%}
 
-{%block lvl4_breadcrumbs%}
-<li {%if activelink=="view-phenotype"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('species.populations.phenotypes.view_phenotype',
-           species_id=species.SpeciesId,
-           population_id=population.Id,
-           dataset_id=dataset.Id,
-           xref_id=xref_id)}}">View Phenotype</a>
-</li>
-{%endblock%}
-
 {%block contents%}
 {{flash_all_messages()}}
 
@@ -153,7 +138,3 @@ or "group:resource:delete-resource" in privileges%}
 </div>
 
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
-{%endblock%}
diff --git a/uploader/templates/platforms/base.html b/uploader/templates/platforms/base.html
index dac965f..d4f3686 100644
--- a/uploader/templates/platforms/base.html
+++ b/uploader/templates/platforms/base.html
@@ -1,13 +1,17 @@
 {%extends "species/base.html"%}
+{%from "species/macro-display-species-card.html" import display_sui_species_card%}
 
-{%block lvl3_breadcrumbs%}
-<li {%if activelink=="platforms"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('species.populations.platforms.index')}}">
-    Sequencing Platforms</a>
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('species.platforms.list_platforms',
+           species_id=species['SpeciesId'])}}">
+    Platforms
+  </a>
 </li>
-{%block lvl4_breadcrumbs%}{%endblock%}
+{%endblock%}
+
+
+{%block sidebarcontents%}
+{{display_sui_species_card(species)}}
 {%endblock%}
diff --git a/uploader/templates/platforms/create-platform.html b/uploader/templates/platforms/create-platform.html
index 0866d5e..3a62472 100644
--- a/uploader/templates/platforms/create-platform.html
+++ b/uploader/templates/platforms/create-platform.html
@@ -1,19 +1,15 @@
 {%extends "platforms/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
-{%from "species/macro-display-species-card.html" import display_species_card%}
 
 {%block title%}Platforms &mdash; Create Platforms{%endblock%}
 
-{%block pagetitle%}Platforms &mdash; Create Platforms{%endblock%}
-
-{%block lvl3_breadcrumbs%}
-<li {%if activelink=="create-platform"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
   <a href="{{url_for('species.platforms.create_platform',
-           species_id=species.SpeciesId)}}">create platform</a>
+           species_id=species['SpeciesId'])}}">
+    Create
+  </a>
 </li>
 {%endblock%}
 
@@ -118,7 +114,3 @@
   </form>
 </div>
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_species_card(species)}}
-{%endblock%}
diff --git a/uploader/templates/platforms/list-platforms.html b/uploader/templates/platforms/list-platforms.html
index a6bcfdc..db14745 100644
--- a/uploader/templates/platforms/list-platforms.html
+++ b/uploader/templates/platforms/list-platforms.html
@@ -1,6 +1,5 @@
 {%extends "platforms/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
-{%from "species/macro-display-species-card.html" import display_species_card%}
 
 {%block title%}Platforms &mdash; List Platforms{%endblock%}
 
@@ -87,7 +86,3 @@
   {%endif%}
 </div>
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_species_card(species)}}
-{%endblock%}
diff --git a/uploader/templates/platforms/sui-base.html b/uploader/templates/platforms/sui-base.html
deleted file mode 100644
index 136b956..0000000
--- a/uploader/templates/platforms/sui-base.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{%extends "species/sui-base.html"%}
-{%from "species/macro-display-species-card.html" import display_sui_species_card%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('species.platforms.list_platforms',
-           species_id=species['SpeciesId'])}}">
-    Platforms
-  </a>
-</li>
-{%endblock%}
-
-
-{%block sidebarcontents%}
-{{display_sui_species_card(species)}}
-{%endblock%}
diff --git a/uploader/templates/platforms/sui-create-platform.html b/uploader/templates/platforms/sui-create-platform.html
deleted file mode 100644
index 25977a7..0000000
--- a/uploader/templates/platforms/sui-create-platform.html
+++ /dev/null
@@ -1,116 +0,0 @@
-{%extends "platforms/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Platforms &mdash; Create Platforms{%endblock%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('species.platforms.create_platform',
-           species_id=species['SpeciesId'])}}">
-    Create
-  </a>
-</li>
-{%endblock%}
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <h2>Create New Platform</h2>
-
-  <p>You can create a new genetic sequencing platform below.</p>
-</div>
-
-<div class="row">
-  <form id="frm-create-platform"
-        method="POST"
-        action="{{url_for('species.platforms.create_platform',
-                species_id=species.SpeciesId)}}">
-
-    <div class="form-group">
-      <label for="txt-geo-platform" class="form-label">GEO Platform</label>
-      <input type="text"
-             id="txt-geo-platform"
-             name="geo-platform"
-             required="required"
-             class="form-control"  />
-      <small class="form-text text-muted">
-        <p>This is the platform's
-          <a href="https://www.ncbi.nlm.nih.gov/geo/browse/?view=platforms&tax={{species.TaxonomyId}}"
-             title="Platforms for '{{species.FullName}}' on NCBI">
-            accession value on NCBI</a>. If you do not know the value, click the
-          link and search on NCBI for species '{{species.FullName}}'.</p></small>
-    </div>
-
-    <div class="form-group">
-      <label for="txt-platform-name" class="form-label">Platform Name</label>
-      <input type="text"
-             id="txt-platform-name"
-             name="platform-name"
-             required="required"
-             class="form-control" />
-      <small class="form-text text-muted">
-        <p>This is name of the genetic sequencing platform.</p></small>
-    </div>
-
-    <div class="form-group">
-      <label for="txt-platform-shortname" class="form-label">
-        Platform Short Name</label>
-      <input type="text"
-             id="txt-platform-shortname"
-             name="platform-shortname"
-             required="required"
-             class="form-control" />
-      <small class="form-text text-muted">
-        <p>Use the following conventions for this field:
-          <ol>
-            <li>Start with a 4-letter vendor code, e.g. "Affy" for "Affymetrix", "Illu" for "Illumina", etc.</li>
-            <li>Append an underscore to the 4-letter vendor code</li>
-            <li>Use the name of the array given by the vendor, e.g.  U74AV2, MOE430A, etc.</li>
-          </ol>
-        </p>
-      </small>
-    </div>
-
-    <div class="form-group">
-      <label for="txt-platform-title" class="form-label">Platform Title</label>
-      <input type="text"
-             id="txt-platform-title"
-             name="platform-title"
-             required="required"
-             class="form-control"  />
-      <small class="form-text text-muted">
-        <p>The full platform title. Sometimes, this is the same as the Platform
-          Name above.</p></small>
-    </div>
-
-    <div class="form-group">
-      <label for="txt-go-tree-value" class="form-label">GO Tree Value</label>
-      <input type="text"
-             id="txt-go-tree-value"
-             name="go-tree-value"
-             class="form-control"  />
-      <small class="form-text text-muted">
-        <p>This is a Chip identification value useful for analysis with the
-          <strong>
-            <a href="https://www.geneweaver.org/"
-               title="Go to the GeneWeaver site."
-               target="_blank">GeneWeaver</a></strong>
-          and
-          <strong>
-            <a href="https://www.webgestalt.org/"
-               title="Go to the WEB-based GEne SeT AnaLysis Toolkit site."
-               target="_blank">WebGestalt</a></strong>
-          tools.<br />
-        This can be left blank for custom platforms.</p></small>
-    </div>
-
-    <div class="form-group">
-      <input type="submit"
-             value="create new platform"
-             class="btn btn-primary"  />
-    </div>
-  </form>
-</div>
-{%endblock%}
diff --git a/uploader/templates/platforms/sui-list-platforms.html b/uploader/templates/platforms/sui-list-platforms.html
deleted file mode 100644
index f4c17e8..0000000
--- a/uploader/templates/platforms/sui-list-platforms.html
+++ /dev/null
@@ -1,88 +0,0 @@
-{%extends "platforms/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Platforms &mdash; List Platforms{%endblock%}
-
-{%block pagetitle%}Platforms &mdash; List Platforms{%endblock%}
-
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <p>View the list of the genetic sequencing platforms that are currently
-    supported by GeneNetwork.</p>
-  <p>If you cannot find the platform you wish to use, you can add it by clicking
-    the "New Platform" button below.</p>
-  <p><a href="{{url_for('species.platforms.create_platform',
-              species_id=species.SpeciesId)}}"
-        title="Create a new genetic sequencing platform for species {{species.FullName}}"
-        class="btn btn-primary">Create Platform</a></p>
-</div>
-
-<div class="row">
-  <h2>Supported Platforms</h2>
-  {%if platforms is defined and platforms | length > 0%}
-  <p>There are {{total_platforms}} platforms supported by GeneNetwork</p>
-
-  <div class="row">
-    <div class="col-md-2" style="text-align: start;">
-      {%if start_from > 0%}
-      <a href="{{url_for('species.platforms.list_platforms',
-               species_id=species.SpeciesId,
-               start_from=start_from-count,
-               count=count)}}">
-        <span class="glyphicon glyphicon-backward"></span>
-        Previous
-      </a>
-      {%endif%}
-    </div>
-    <div class="col-md-8" style="text-align: center;">
-      Displaying platforms {{start_from+1}} to {{start_from+count if start_from+count < total_platforms else total_platforms}} of
-      {{total_platforms}}
-    </div>
-    <div class="col-md-2" style="text-align: end;">
-      {%if start_from + count < total_platforms%}
-      <a href="{{url_for('species.platforms.list_platforms',
-               species_id=species.SpeciesId,
-               start_from=start_from+count,
-               count=count)}}">
-        Next
-        <span class="glyphicon glyphicon-forward"></span>
-      </a>
-      {%endif%}
-    </div>
-  </div>
-
-  <table class="table">
-    <thead>
-      <tr>
-        <th></th>
-        <th>Platform Name</th>
-        <th><a href="https://www.ncbi.nlm.nih.gov/geo/browse/?view=platforms&tax={{species.TaxonomyId}}"
-               title="Gene Expression Omnibus: Platforms section"
-               target="_blank">GEO Platform</a></th>
-        <th>Title</th>
-      </tr>
-    </thead>
-
-    <tbody>
-      {%for platform in platforms%}
-      <tr>
-        <td>{{platform.sequence_number}}</td>
-        <td>{{platform.GeneChipName}}</td>
-        <td><a href="https://www.ncbi.nlm.nih.gov/geo/query/acc.cgi?acc={{platform.GeoPlatform}}"
-               title="View platform on the Gene Expression Omnibus"
-               target="_blank">{{platform.GeoPlatform}}</a></td>
-        <td>{{platform.Title}}</td>
-      </tr>
-      {%endfor%}
-    </tbody>
-  </table>
-  {%else%}
-  <p class="text-warning">
-    <span class="glyphicon glyphicon-exclamation-sign"></span>
-    There are no platforms supported at this time!</p>
-  {%endif%}
-</div>
-{%endblock%}
diff --git a/uploader/templates/populations/base.html b/uploader/templates/populations/base.html
index 9db8083..24cacc2 100644
--- a/uploader/templates/populations/base.html
+++ b/uploader/templates/populations/base.html
@@ -1,18 +1,20 @@
 {%extends "species/base.html"%}
+{%from "populations/macro-display-population-card.html" import display_sui_population_card%}
 
-{%block lvl2_breadcrumbs%}
-<li {%if activelink=="populations"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  {%if population is mapping%}
+{%block breadcrumbs%}
+{{super()}}
+{%if population%}
+<li class="breadcrumb-item">
   <a href="{{url_for('species.populations.view_population',
-           species_id=species.SpeciesId,
-           population_id=population.Id)}}">{{population.Name}}</a>
-  {%else%}
-  <a href="{{url_for('species.populations.index')}}">Populations</a>
-  {%endif%}
+           species_id=species['SpeciesId'],
+           population_id=population['Id'])}}">
+    {{population["Name"]}}
+  </a>
 </li>
-{%block lvl3_breadcrumbs%}{%endblock%}
+{%endif%}
+{%endblock%}
+
+
+{%block sidebarcontents%}
+{{display_sui_population_card(species, population)}}
 {%endblock%}
diff --git a/uploader/templates/populations/create-population.html b/uploader/templates/populations/create-population.html
index 007b6bf..d5359f5 100644
--- a/uploader/templates/populations/create-population.html
+++ b/uploader/templates/populations/create-population.html
@@ -1,20 +1,16 @@
 {%extends "populations/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
-{%from "species/macro-select-species.html" import select_species_form%}
-{%from "species/macro-display-species-card.html" import display_species_card%}
 
 {%block title%}Create Population{%endblock%}
 
 {%block pagetitle%}Create Population{%endblock%}
 
-{%block lvl3_breadcrumbs%}
-<li {%if activelink=="create-population"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
   <a href="{{url_for('species.populations.create_population',
-           species_id=species.SpeciesId)}}">create population</a>
+           species_id=species['SpeciesId'])}}">
+    create population</a>
 </li>
 {%endblock%}
 
@@ -263,7 +259,3 @@
   </form>
 </div>
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_species_card(species)}}
-{%endblock%}
diff --git a/uploader/templates/populations/macro-display-population-card.html b/uploader/templates/populations/macro-display-population-card.html
index 6b5f1e0..f3040ea 100644
--- a/uploader/templates/populations/macro-display-population-card.html
+++ b/uploader/templates/populations/macro-display-population-card.html
@@ -43,7 +43,7 @@
 
 {%macro display_sui_population_card(species, population)%}
 {{display_sui_species_card(species)}}
-
+{%if population%}
 <div class="row">
   <table class="table">
     <caption>Current population</caption>
@@ -75,4 +75,5 @@
     </tbody>
   </table>
 </div>
+{%endif%}
 {%endmacro%}
diff --git a/uploader/templates/populations/sui-base.html b/uploader/templates/populations/sui-base.html
deleted file mode 100644
index 0ca5c59..0000000
--- a/uploader/templates/populations/sui-base.html
+++ /dev/null
@@ -1,12 +0,0 @@
-{%extends "species/sui-base.html"%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('species.populations.view_population',
-           species_id=species['SpeciesId'],
-           population_id=population['Id'])}}">
-    {{population["Name"]}}
-  </a>
-</li>
-{%endblock%}
diff --git a/uploader/templates/populations/sui-view-population.html b/uploader/templates/populations/sui-view-population.html
deleted file mode 100644
index a35eac6..0000000
--- a/uploader/templates/populations/sui-view-population.html
+++ /dev/null
@@ -1,127 +0,0 @@
-{%extends "populations/sui-base.html"%}
-{%from "macro-step-indicator.html" import step_indicator%}
-{%from "populations/macro-display-population-card.html" import display_sui_population_card%}
-
-{%block contents%}
-<div class="row">
-  <h2 class="heading">{{population.FullName}} ({{population.Name}})</h2>
-</div>
-
-<div class="row">
-  <ul class="nav nav-tabs" id="population-actions">
-    <li class="nav-item presentation">
-      <button class="nav-link"
-              id="samples-tab"
-              data-bs-toggle="tab"
-              data-bs-target="#samples-content"
-              type="button"
-              role="tab"
-              aria-controls="samples-content"
-              aria-selected="true">Samples</button></li>
-    <li class="nav-item presentation">
-      <button class="nav-link active"
-              id="phenotypes-tab"
-              data-bs-toggle="tab"
-              data-bs-target="#phenotypes-content"
-              type="button"
-              role="tab"
-              aria-controls="phenotypes-content"
-              aria-selected="false">Phenotypes</button></li>
-    {%if view_under_construction%}
-    <li class="nav-item presentation">
-      <button class="nav-link"
-              id="genotypes-tab"
-              data-bs-toggle="tab"
-              data-bs-target="#genotypes-content"
-              type="button"
-              role="tab"
-              aria-controls="genotypes-content"
-              aria-selected="false">Genotypes</button></li>
-    <li class="nav-item presentation">
-      <button class="nav-link"
-              id="expression-data-tab"
-              data-bs-toggle="tab"
-              data-bs-target="#expression-data-content"
-              type="button"
-              role="tab"
-              aria-controls="expression-data-content"
-              aria-selected="false">Expression-Data</button></li>
-    {%endif%}
-  </ul>
-</div>
-
-<div class="row">
-  <div class="tab-content" id="populations-tabs-content">
-    <div class="tab-pane fade"
-         id="samples-content"
-         role="tabpanel"
-         aria-labelledby="samples-content-tab">
-      <p>Think of a <strong>"sample"</strong> as say a single case or individual
-        in the experiment. It could even be a single strain (where applicable).
-      </p>
-      <p>This is a convenience feature for when you want to upload phenotypes to
-        the system, but do not have the genotypes data ready yet.</p>
-      <a href="{{url_for('species.populations.samples.list_samples',
-               species_id=species.SpeciesId,
-               population_id=population.Id)}}"
-         title="View and upload samples for population '{{population['Name']}}'"
-         class="btn btn-primary">Manage Samples</a>
-    </div>
-
-    <div class="tab-pane fade show active"
-         id="phenotypes-content"
-         role="tabpanel"
-         aria-labelledby="phenotypes-content-tab">
-
-      <div class="row" style="margin-top: 1em;">
-        <h3> Phenotypes in  Population "{{population.FullName}} ({{population.Name}})"</h3>
-
-        <p>To view existing phenotype traits, or upload new ones, click the button below:</p>
-
-        <div class="row">
-          <div class="col">
-            <a href="{{url_for(
-                     'species.populations.phenotypes.list_datasets',
-                     species_id=species.SpeciesId,
-                     population_id=population.Id)}}"
-               title="View and upload phenotype traits"
-               class="btn btn-primary">Phenotypes</a>
-          </div>
-        </div>
-      </div>
-    </div>
-
-    <div class="tab-pane fade"
-         id="genotypes-content"
-         role="tabpanel"
-         aria-labelledby="genotypes-content-tab">
-      <p>This allows you to upload the data that concerns your genotypes.</p>
-      <p>Any samples/individuals/cases/strains that do not already exist in the
-        system will be added. This does not delete any existing data.</p>
-      <a href="{{url_for('species.populations.genotypes.list_genotypes',
-               species_id=species.SpeciesId,
-               population_id=population.Id)}}"
-         title="Upload genotype information for the '{{population.FullName}}' population of the '{{species.FullName}}' species."
-         class="btn btn-primary">upload genotypes</a>
-    </div>
-    <div class="tab-pane fade" id="expression-data-content" role="tabpanel" aria-labelledby="expression-data-content-tab">
-      <p>Upload expression data (mRNA data) for this population.</p>
-      <a href="#" title="" class="btn btn-primary">upload genotypes</a>
-    </div>
-  </div>
-</div>
-{%endblock%}
-
-{%block sidebarcontents%}
-<div class="row">
-  <p>Each tab presents a feature that's available at the population level.
-    Select the tab that allows you to continue with your task.</p>
-</div>
-{{display_sui_population_card(species, population)}}
-{%endblock%}
-
-
-
-
-{%block javascript%}
-{%endblock%}
diff --git a/uploader/templates/populations/view-population.html b/uploader/templates/populations/view-population.html
index 3b9661b..ac89bc7 100644
--- a/uploader/templates/populations/view-population.html
+++ b/uploader/templates/populations/view-population.html
@@ -1,104 +1,127 @@
 {%extends "populations/base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "species/macro-select-species.html" import select_species_form%}
-{%from "species/macro-display-species-card.html" import display_species_card%}
-
-{%block title%}Populations{%endblock%}
-
-{%block pagetitle%}Populations{%endblock%}
-
-{%block lvl3_breadcrumbs%}
-<li {%if activelink=="view-population"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('species.populations.view_population',
-           species_id=species.SpeciesId,
-           population_id=population.InbredSetId)}}">view</a>
-</li>
-{%endblock%}
-
+{%from "macro-step-indicator.html" import step_indicator%}
+{%from "populations/macro-display-population-card.html" import display_sui_population_card%}
 
 {%block contents%}
 <div class="row">
-  <h2>Population Details</h2>
-
-  {{flash_all_messages()}}
-
-  <dl>
-    <dt>Name</dt>
-    <dd>{{population.Name}}</dd>
-
-    <dt>FullName</dt>
-    <dd>{{population.FullName}}</dd>
-
-    <dt>Code</dt>
-    <dd>{{population.InbredSetCode}}</dd>
-
-    <dt>Genetic Type</dt>
-    <dd>{{population.GeneticType}}</dd>
-
-    <dt>Family</dt>
-    <dd>{{population.Family}}</dd>
-
-    <dt>Information</dt>
-    <dd><a href="https://info.genenetwork.org/species/source.php?SpeciesName={{species.Name}}&InbredSetName={{population.Name}}"
-           title="Link to detailed information on this population."
-           target="_blank">Population Information</a></dd>
-  </dl>
+  <h2 class="heading">{{population.FullName}} ({{population.Name}})</h2>
 </div>
 
 <div class="row">
-  … maybe provide a way to organise populations in the same family here …
+  <ul class="nav nav-tabs" id="population-actions">
+    <li class="nav-item presentation">
+      <button class="nav-link"
+              id="samples-tab"
+              data-bs-toggle="tab"
+              data-bs-target="#samples-content"
+              type="button"
+              role="tab"
+              aria-controls="samples-content"
+              aria-selected="true">Samples</button></li>
+    <li class="nav-item presentation">
+      <button class="nav-link active"
+              id="phenotypes-tab"
+              data-bs-toggle="tab"
+              data-bs-target="#phenotypes-content"
+              type="button"
+              role="tab"
+              aria-controls="phenotypes-content"
+              aria-selected="false">Phenotypes</button></li>
+    {%if view_under_construction%}
+    <li class="nav-item presentation">
+      <button class="nav-link"
+              id="genotypes-tab"
+              data-bs-toggle="tab"
+              data-bs-target="#genotypes-content"
+              type="button"
+              role="tab"
+              aria-controls="genotypes-content"
+              aria-selected="false">Genotypes</button></li>
+    <li class="nav-item presentation">
+      <button class="nav-link"
+              id="expression-data-tab"
+              data-bs-toggle="tab"
+              data-bs-target="#expression-data-content"
+              type="button"
+              role="tab"
+              aria-controls="expression-data-content"
+              aria-selected="false">Expression-Data</button></li>
+    {%endif%}
+  </ul>
 </div>
 
 <div class="row">
-  <h3>Actions</h3>
-
-  <p>
-    Click any of the following links to use this population in performing the
-    subsequent operations.
-  </p>
-
-  <nav class="nav">
-    <ul>
-      <li>
-        <a href="{{url_for('species.populations.samples.list_samples',
-                 species_id=species.SpeciesId,
-                 population_id=population.Id)}}"
-           title="Manage samples: Add new or delete existing.">
-          manage samples</a>
-      </li>
-      <li>
-        <a href="{{url_for('species.populations.genotypes.list_genotypes',
-                 species_id=species.SpeciesId,
-                 population_id=population.Id)}}"
-           title="Manage genotypes for {{species.FullName}}">Manage Genotypes</a>
-      </li>
-      <li>
-        <a href="{{url_for('species.populations.phenotypes.list_datasets',
-                 species_id=species.SpeciesId,
-                 population_id=population.Id)}}"
-           title="Manage phenotype data.">manage phenotype data</a>
-      </li>
-      <li>
-        <a href="#" title="Manage expression data"
-           class="not-implemented">manage expression data</a>
-      </li>
-      <li>
-        <a href="#" title="Manage individual data"
-           class="not-implemented">manage individual data</a>
-      </li>
-      <li>
-        <a href="#" title="Manage RNA-Seq data"
-           class="not-implemented">manage RNA-Seq data</a>
-      </li>
-    </ul>
-  </nav>
+  <div class="tab-content" id="populations-tabs-content">
+    <div class="tab-pane fade"
+         id="samples-content"
+         role="tabpanel"
+         aria-labelledby="samples-content-tab">
+      <p>Think of a <strong>"sample"</strong> as say a single case or individual
+        in the experiment. It could even be a single strain (where applicable).
+      </p>
+      <p>This is a convenience feature for when you want to upload phenotypes to
+        the system, but do not have the genotypes data ready yet.</p>
+      <a href="{{url_for('species.populations.samples.list_samples',
+               species_id=species.SpeciesId,
+               population_id=population.Id)}}"
+         title="View and upload samples for population '{{population['Name']}}'"
+         class="btn btn-primary">Manage Samples</a>
+    </div>
+
+    <div class="tab-pane fade show active"
+         id="phenotypes-content"
+         role="tabpanel"
+         aria-labelledby="phenotypes-content-tab">
+
+      <div class="row" style="margin-top: 1em;">
+        <h3> Phenotypes in  Population "{{population.FullName}} ({{population.Name}})"</h3>
+
+        <p>To view existing phenotype traits, or upload new ones, click the button below:</p>
+
+        <div class="row">
+          <div class="col">
+            <a href="{{url_for(
+                     'species.populations.phenotypes.list_datasets',
+                     species_id=species.SpeciesId,
+                     population_id=population.Id)}}"
+               title="View and upload phenotype traits"
+               class="btn btn-primary">Phenotypes</a>
+          </div>
+        </div>
+      </div>
+    </div>
+
+    <div class="tab-pane fade"
+         id="genotypes-content"
+         role="tabpanel"
+         aria-labelledby="genotypes-content-tab">
+      <p>This allows you to upload the data that concerns your genotypes.</p>
+      <p>Any samples/individuals/cases/strains that do not already exist in the
+        system will be added. This does not delete any existing data.</p>
+      <a href="{{url_for('species.populations.genotypes.list_genotypes',
+               species_id=species.SpeciesId,
+               population_id=population.Id)}}"
+         title="Upload genotype information for the '{{population.FullName}}' population of the '{{species.FullName}}' species."
+         class="btn btn-primary">upload genotypes</a>
+    </div>
+    <div class="tab-pane fade" id="expression-data-content" role="tabpanel" aria-labelledby="expression-data-content-tab">
+      <p>Upload expression data (mRNA data) for this population.</p>
+      <a href="#" title="" class="btn btn-primary">upload genotypes</a>
+    </div>
+  </div>
 </div>
 {%endblock%}
 
 {%block sidebarcontents%}
-{{display_species_card(species)}}
+<div class="row">
+  <p>Each tab presents a feature that's available at the population level.
+    Select the tab that allows you to continue with your task.</p>
+</div>
+{{super()}}
+{%endblock%}
+
+
+
+
+{%block javascript%}
 {%endblock%}
diff --git a/uploader/templates/publications/base.html b/uploader/templates/publications/base.html
index db80bfa..de0a350 100644
--- a/uploader/templates/publications/base.html
+++ b/uploader/templates/publications/base.html
@@ -1,12 +1,9 @@
 {%extends "base.html"%}
 
-{%block lvl1_breadcrumbs%}
-<li {%if activelink=="publications"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('publications.index')}}">Publications</a>
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('publications.index')}}"
+     title="Manage publications">Publications</a>
 </li>
-{%block lvl2_breadcrumbs%}{%endblock%}
 {%endblock%}
diff --git a/uploader/templates/publications/create-publication.html b/uploader/templates/publications/create-publication.html
index 3f828a9..fb0127d 100644
--- a/uploader/templates/publications/create-publication.html
+++ b/uploader/templates/publications/create-publication.html
@@ -3,7 +3,13 @@
 
 {%block title%}View Publication{%endblock%}
 
-{%block pagetitle%}View Publication{%endblock%}
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('publications.create_publication', **get_args)}}"
+     title="Manage publications">create publication</a>
+</li>
+{%endblock%}
 
 
 {%block contents%}
@@ -12,7 +18,7 @@
 <div class="row">
   <form id="frm-create-publication"
         method="POST"
-        action="{{url_for('publications.create_publication', **request.args)}}"
+        action="{{url_for('publications.create_publication', **get_args)}}"
         class="form-horizontal">
 
     <div class="row mb-3">
@@ -152,11 +158,14 @@
       </div>
     </div>
 
-    <div class="row mb-3">
-      <div class="col-sm-2"></div>
-      <div class="col-sm-8">
-        <input type="submit" class="btn btn-primary" value="Add" />
-        <input type="reset" class="btn btn-danger" />
+    <div class="row">
+      <div class="col">
+        <input type="submit"
+               class="btn btn-primary"
+               value="create publication" />
+      </div>
+      <div class="col">
+        <input type="reset" class="btn btn-danger" value="reset form" />
       </div>
     </div>
 
diff --git a/uploader/templates/publications/delete-publication.html b/uploader/templates/publications/delete-publication.html
index 0ac93ec..a9c8c7c 100644
--- a/uploader/templates/publications/delete-publication.html
+++ b/uploader/templates/publications/delete-publication.html
@@ -1,9 +1,16 @@
 {%extends "publications/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
 
-{%block title%}View Publication{%endblock%}
+{%block title%}Delete Publication{%endblock%}
 
-{%block pagetitle%}View Publication{%endblock%}
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('publications.delete_publication',
+           publication_id=publication.Id)}}"
+     title="Manage publications">delete publication</a>
+</li>
+{%endblock%}
 
 
 {%block contents%}
diff --git a/uploader/templates/publications/edit-publication.html b/uploader/templates/publications/edit-publication.html
index 97fa134..314a78c 100644
--- a/uploader/templates/publications/edit-publication.html
+++ b/uploader/templates/publications/edit-publication.html
@@ -1,9 +1,16 @@
 {%extends "publications/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
 
-{%block title%}View Publication{%endblock%}
-
-{%block pagetitle%}View Publication{%endblock%}
+{%block title%}Edit Publication{%endblock%}
+
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('publications.edit_publication',
+           publication_id=publication.Id)}}"
+     title="Edit the publication's details">edit publication</a>
+</li>
+{%endblock%}
 
 
 {%block contents%}
diff --git a/uploader/templates/publications/index.html b/uploader/templates/publications/index.html
index 369812b..54d3fc0 100644
--- a/uploader/templates/publications/index.html
+++ b/uploader/templates/publications/index.html
@@ -3,16 +3,22 @@
 
 {%block title%}Publications{%endblock%}
 
-{%block pagetitle%}Publications{%endblock%}
-
 
 {%block contents%}
 {{flash_all_messages()}}
 
 <div class="row" style="padding-bottom: 1em;">
-  <a href="{{url_for('publications.create_publication')}}"
-     class="btn btn-primary">
-    add new publication</a>
+  <div class="col">
+    <a href="{{url_for('publications.create_publication')}}"
+       class="btn btn-primary"
+       title="Create a new publication.">
+      add new publication</a>
+  </div>
+</div>
+
+<div class="row">
+  <p>Click on title to view more details and to edit details for that
+    publication.</p>
 </div>
 
 <div class="row">
@@ -33,6 +39,8 @@
 
 
 {%block javascript%}
+<script type="text/javascript" src="/static/js/urls.js"></script>
+
 <script type="text/javascript">
   $(function() {
       var publicationsDataTable = buildDataTable(
@@ -43,24 +51,25 @@
               {
                   searchable: true,
                   data: (pub) => {
-                  if(pub.PubMed_ID) {
-                      return `<a href="https://pubmed.ncbi.nlm.nih.gov/` +
-                          `${pub.PubMed_ID}/" target="_blank" ` +
-                          `title="Link to publication on NCBI.">` +
-                          `${pub.PubMed_ID}</a>`;
-                  }
-                  return "";
+                      if(pub.PubMed_ID) {
+                          return `<a href="https://pubmed.ncbi.nlm.nih.gov/` +
+                              `${pub.PubMed_ID}/" target="_blank" ` +
+                              `title="Link to publication on NCBI.">` +
+                              `${pub.PubMed_ID}</a>`;
+                      }
+                      return "";
                   }
               },
               {
                   searchable: true,
                   data: (pub) => {
-                  var title = "⸻";
-                  if(pub.Title) {
-                      title = pub.Title
-                  }
-                  return `<a href="/publications/view/${pub.Id}" ` +
-                          `target="_blank" ` +
+                      var title = "⸻";
+                      if(pub.Title) {
+                          title = pub.Title
+                      }
+                      url=buildURLFromCurrentURL(
+                          `/publications/view/${pub.Id}`);
+                      return `<a href="${url}" target="_blank" ` +
                           `title="Link to view publication details">` +
                           `${title}</a>`;
                   }
@@ -68,12 +77,12 @@
               {
                   searchable: true,
                   data: (pub) => {
-                  authors = pub.Authors.split(",").map(
-                      (item) => {return item.trim();});
-                  if(authors.length > 1) {
-                      return authors[0] + ", et. al.";
-                  }
-                  return authors[0];
+                      authors = pub.Authors.split(",").map(
+                          (item) => {return item.trim();});
+                      if(authors.length > 1) {
+                          return authors[0] + ", et. al.";
+                      }
+                      return authors[0];
                   }
               }
           ],
diff --git a/uploader/templates/publications/sui-base.html b/uploader/templates/publications/sui-base.html
deleted file mode 100644
index 64e41ef..0000000
--- a/uploader/templates/publications/sui-base.html
+++ /dev/null
@@ -1,9 +0,0 @@
-{%extends "sui-base.html"%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('publications.index')}}"
-     title="Manage publications">Publications</a>
-</li>
-{%endblock%}
diff --git a/uploader/templates/publications/sui-create-publication.html b/uploader/templates/publications/sui-create-publication.html
deleted file mode 100644
index 81edca6..0000000
--- a/uploader/templates/publications/sui-create-publication.html
+++ /dev/null
@@ -1,200 +0,0 @@
-{%extends "publications/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}View Publication{%endblock%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('publications.create_publication', **get_args)}}"
-     title="Manage publications">create publication</a>
-</li>
-{%endblock%}
-
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <form id="frm-create-publication"
-        method="POST"
-        action="{{url_for('publications.create_publication', **get_args)}}"
-        class="form-horizontal">
-
-    <div class="row mb-3">
-      <label for="txt-pubmed-id" class="col-sm-2 col-form-label">
-        PubMed ID</label>
-      <div class="col-sm-10">
-        <div class="input-group">
-          <input type="text"
-                 id="txt-pubmed-id"
-                 name="pubmed-id"
-                 class="form-control"/>
-          <div class="input-group-text">
-            <button class="btn btn-outline-primary"
-                    id="btn-search-pubmed-id">search</button>
-          </div>
-        </div>
-        <span id="search-pubmed-id-error"
-              class="form-text text-muted text-danger visually-hidden">
-        </span>
-        <span class="form-text text-muted">This is the publication's ID on
-          <a href="https://pubmed.ncbi.nlm.nih.gov/"
-             title="Link to NCBI's PubMed service">NCBI's Pubmed Service</a>
-        </span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-publication-title" class="col-sm-2 col-form-label">
-        Title</label>
-      <div class="col-sm-10">
-        <input type="text"
-               id="txt-publication-title"
-               name="publication-title"
-               class="form-control" />
-        <span class="form-text text-muted">Provide the publication's title here.</span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-publication-authors" class="col-sm-2 col-form-label">
-        Authors</label>
-      <div class="col-sm-10">
-        <input type="text"
-               id="txt-publication-authors"
-               name="publication-authors"
-               required="required"
-               class="form-control" />
-        <span class="form-text text-muted">
-          A publication <strong>MUST</strong> have an author. You <em>must</em>
-          provide a value for the authors field.
-        </span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-publication-journal" class="col-sm-2 col-form-label">
-        Journal</label>
-      <div class="col-sm-10">
-        <input type="text"
-               id="txt-publication-journal"
-               name="publication-journal"
-               class="form-control" />
-        <span class="form-text text-muted">Provide the name journal where the
-          publication was done, here.</span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="select-publication-month"
-             class="col-sm-2 col-form-label">
-        Month</label>
-      <div class="col-sm-4">
-        <select class="form-control"
-                id="select-publication-month"
-                name="publication-month">
-          <option value="">Select a month</option>
-          <option value="january">January</option>
-          <option value="february">February</option>
-          <option value="march">March</option>
-          <option value="april">April</option>
-          <option value="may">May</option>
-          <option value="june">June</option>
-          <option value="july">July</option>
-          <option value="august">August</option>
-          <option value="september">September</option>
-          <option value="october">October</option>
-          <option value="november">November</option>
-          <option value="december">December</option>
-        </select>
-        <span class="form-text text-muted">Month of publication</span>
-      </div>
-
-      <label for="txt-publication-year"
-             class="col-sm-2 col-form-label">
-        Year</label>
-      <div class="col-sm-4">
-        <input type="number"
-               id="txt-publication-year"
-               name="publication-year"
-               class="form-control"
-               min="1960" />
-        <span class="form-text text-muted">Year of publication</span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-publication-volume"
-             class="col-sm-2 col-form-label">
-        Volume</label>
-      <div class="col-sm-4">
-        <input type="text"
-               id="txt-publication-volume"
-               name="publication-volume"
-               class="form-control">
-        <span class="form-text text-muted">Journal volume</span>
-      </div>
-
-      <label for="txt-publication-pages"
-             class="col-sm-2 col-form-label">
-        Pages</label>
-      <div class="col-sm-4">
-        <input type="text"
-               id="txt-publication-pages"
-               name="publication-pages"
-               class="form-control" />
-        <span class="form-text text-muted">Journal pages for the publication</span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-abstract" class="col-sm-2 col-form-label">Abstract</label>
-      <div class="col-sm-10">
-        <textarea id="txt-publication-abstract"
-                  name="publication-abstract"
-                  class="form-control"
-                  rows="7"></textarea>
-      </div>
-    </div>
-
-    <div class="row">
-      <div class="col">
-        <input type="submit"
-               class="btn btn-primary"
-               value="create publication" />
-      </div>
-      <div class="col">
-        <input type="reset" class="btn btn-danger" value="reset form" />
-      </div>
-    </div>
-
-</form>
-</div>
-
-{%endblock%}
-
-
-{%block javascript%}
-<script type="text/javascript" src="/static/js/pubmed.js"></script>
-<script type="text/javascript">
-  $(function() {
-      $("#btn-search-pubmed-id").on("click", (event) => {
-          event.preventDefault();
-          var search_button = event.target;
-          var pubmed_id = $("#txt-pubmed-id").val().trim();
-          remove_class($("#txt-pubmed-id").parent(), "has-error");
-          if(pubmed_id == "") {
-              add_class($("#txt-pubmed-id").parent(), "has-error");
-              return false;
-          }
-
-          search_button.disabled = true;
-          // Fetch publication details
-          fetch_publication_details(pubmed_id,
-                                    [() => {search_button.disabled = false;}]);
-          return false;
-      });
-  });
-</script>
-{%endblock%}
diff --git a/uploader/templates/publications/sui-delete-publication.html b/uploader/templates/publications/sui-delete-publication.html
deleted file mode 100644
index 436f2c1..0000000
--- a/uploader/templates/publications/sui-delete-publication.html
+++ /dev/null
@@ -1,95 +0,0 @@
-{%extends "publications/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Delete Publication{%endblock%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('publications.delete_publication',
-           publication_id=publication.Id)}}"
-     title="Manage publications">delete publication</a>
-</li>
-{%endblock%}
-
-
-{%block contents%}
-{{flash_all_messages()}}
-<div class="row">
-  <p>You are about to delete the publication with the following details:</p>
-</div>
-
-<div class="row">
-  <table class="table">
-    <tr>
-      <th>Linked Phenotypes</th>
-      <td>{{linked_phenotypes | count}}</td>
-    </tr>
-    <tr>
-      <th>PubMed</th>
-      <td>
-        {%if publication.PubMed_ID%}
-        <a href="https://pubmed.ncbi.nlm.nih.gov/{{publication.PubMed_ID}}/"
-           target="_blank">{{publication.PubMed_ID}}</a>
-        {%else%}
-        —
-        {%endif%}
-      </td>
-    </tr>
-    <tr>
-      <th>Title</th>
-      <td>{{publication.Title or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Authors</th>
-      <td>{{publication.Authors or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Journal</th>
-      <td>{{publication.Journal or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Published</th>
-      <td>{{publication.Month or ""}} {{publication.Year or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Volume</th>
-      <td>{{publication.Volume or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Pages</th>
-      <td>{{publication.Pages or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Abstract</th>
-      <td>
-        {%for line in (publication.Abstract or "—").replace("\r\n", "<br />").replace("\n", "<br />").split("<br />")%}
-        <p>{{line}}</p>
-        {%endfor%}
-      </td>
-    </tr>
-  </table>
-</div>
-
-<div class="row">
-  <p>If you are sure that is what you want, click the button below to delete the
-    publication</p>
-  <p class="form-text text-small">
-    <small>You will not be able to recover the data if you click
-      delete below.</small></p>
-
-  <form action="{{url_for('publications.delete_publication', publication_id=publication_id)}}"
-        method="POST">
-    <div class="form-group">
-      <input type="submit" value="delete" class="btn btn-danger" />
-    </div>
-  </form>
-</div>
-{%endblock%}
-
-
-{%block javascript%}
-<script type="text/javascript">
-  $(function() {});
-</script>
-{%endblock%}
diff --git a/uploader/templates/publications/sui-edit-publication.html b/uploader/templates/publications/sui-edit-publication.html
deleted file mode 100644
index 847b020..0000000
--- a/uploader/templates/publications/sui-edit-publication.html
+++ /dev/null
@@ -1,203 +0,0 @@
-{%extends "publications/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Edit Publication{%endblock%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('publications.edit_publication',
-           publication_id=publication.Id)}}"
-     title="Edit the publication's details">edit publication</a>
-</li>
-{%endblock%}
-
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <form id="frm-create-publication"
-        method="POST"
-        action="{{url_for('publications.edit_publication',
-                publication_id=publication_id,
-                next=request.args.get('next', ''))}}"
-        class="form-horizontal">
-
-    <div class="row mb-3">
-      <label for="txt-pubmed-id" class="col-sm-2 col-form-label">
-        PubMed ID</label>
-      <div class="col-sm-10">
-        <div class="input-group">
-          <input type="text"
-                 id="txt-pubmed-id"
-                 name="pubmed-id"
-                 value="{{publication.PubMed_ID or ''}}"
-                 class="form-control" />
-          <div class="input-group-text">
-            <button class="btn btn-outline-primary"
-                    id="btn-search-pubmed-id">search</button>
-          </div>
-        </div>
-        <span id="search-pubmed-id-error"
-              class="form-text text-muted text-danger visually-hidden">
-        </span>
-        <span class="form-text text-muted">This is the publication's ID on
-          <a href="https://pubmed.ncbi.nlm.nih.gov/"
-             title="Link to NCBI's PubMed service">NCBI's Pubmed Service</a>
-        </span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-publication-title" class="col-sm-2 col-form-label">
-        Title</label>
-      <div class="col-sm-10">
-        <input type="text"
-               id="txt-publication-title"
-               name="publication-title"
-               value="{{publication.Title}}"
-               class="form-control" />
-        <span class="form-text text-muted">Provide the publication's title here.</span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-publication-authors" class="col-sm-2 col-form-label">
-        Authors</label>
-      <div class="col-sm-10">
-        <input type="text"
-               id="txt-publication-authors"
-               name="publication-authors"
-               value="{{publication.Authors}}"
-               required="required"
-               class="form-control" />
-        <span class="form-text text-muted">
-          A publication <strong>MUST</strong> have an author. You <em>must</em>
-          provide a value for the authors field.
-        </span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-publication-journal" class="col-sm-2 col-form-label">
-        Journal</label>
-      <div class="col-sm-10">
-        <input type="text"
-               id="txt-publication-journal"
-               name="publication-journal"
-               value="{{publication.Journal}}"
-               class="form-control" />
-        <span class="form-text text-muted">Provide the name journal where the
-          publication was done, here.</span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="select-publication-month"
-             class="col-sm-2 col-form-label">
-        Month</label>
-      <div class="col-sm-4">
-        <select class="form-control"
-                id="select-publication-month"
-                name="publication-month">
-          <option value="">Select a month</option>
-          {%for month in ("january", "february", "march", "april", "may", "june", "july", "august", "september", "october", "november", "december"):%}
-          <option value="{{month}}"
-                  {%if publication.Month | lower == month %}
-                  selected="selected"
-                  {%endif%}>
-            {{month | title}}
-          </option>
-          {%endfor%}
-        </select>
-        <span class="form-text text-muted">Month of publication</span>
-      </div>
-
-      <label for="txt-publication-year"
-             class="col-sm-2 col-form-label">
-        Year</label>
-      <div class="col-sm-4">
-        <input type="number"
-               id="txt-publication-year"
-               name="publication-year"
-               value="{{publication.Year}}"
-               class="form-control"
-               min="1960" />
-        <span class="form-text text-muted">Year of publication</span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-publication-volume"
-             class="col-sm-2 col-form-label">
-        Volume</label>
-      <div class="col-sm-4">
-        <input type="text"
-               id="txt-publication-volume"
-               name="publication-volume"
-               value="{{publication.Volume}}"
-               class="form-control">
-        <span class="form-text text-muted">Journal volume</span>
-      </div>
-
-      <label for="txt-publication-pages"
-             class="col-sm-2 col-form-label">
-        Pages</label>
-      <div class="col-sm-4">
-        <input type="text"
-               id="txt-publication-pages"
-               name="publication-pages"
-               value="{{publication.Pages}}"
-               class="form-control" />
-        <span class="form-text text-muted">Journal pages for the publication</span>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <label for="txt-abstract" class="col-sm-2 col-form-label">Abstract</label>
-      <div class="col-sm-10">
-        <textarea id="txt-publication-abstract"
-                  name="publication-abstract"
-                  class="form-control"
-                  rows="7">{{publication.Abstract or ""}}</textarea>
-      </div>
-    </div>
-
-    <div class="row mb-3">
-      <div class="col-sm-2"></div>
-      <div class="col-sm-8">
-        <input type="submit" class="btn btn-primary" value="Save" />
-        <input type="reset" class="btn btn-danger" />
-      </div>
-    </div>
-
-</form>
-</div>
-
-{%endblock%}
-
-
-{%block javascript%}
-<script type="text/javascript" src="/static/js/pubmed.js"></script>
-<script type="text/javascript">
-  $(function() {
-      $("#btn-search-pubmed-id").on("click", (event) => {
-          event.preventDefault();
-          var search_button = event.target;
-          var pubmed_id = $("#txt-pubmed-id").val().trim();
-          remove_class($("#txt-pubmed-id").parent(), "has-error");
-          if(pubmed_id == "") {
-              add_class($("#txt-pubmed-id").parent(), "has-error");
-              return false;
-          }
-
-          search_button.disabled = true;
-          // Fetch publication details
-          fetch_publication_details(pubmed_id,
-                                    [() => {search_button.disabled = false;}]);
-          return false;
-      });
-  });
-</script>
-{%endblock%}
diff --git a/uploader/templates/publications/sui-index.html b/uploader/templates/publications/sui-index.html
deleted file mode 100644
index e405dd1..0000000
--- a/uploader/templates/publications/sui-index.html
+++ /dev/null
@@ -1,109 +0,0 @@
-{%extends "publications/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Publications{%endblock%}
-
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row" style="padding-bottom: 1em;">
-  <div class="col">
-    <a href="{{url_for('publications.create_publication')}}"
-       class="btn btn-primary"
-       title="Create a new publication.">
-      add new publication</a>
-  </div>
-</div>
-
-<div class="row">
-  <p>Click on title to view more details and to edit details for that
-    publication.</p>
-</div>
-
-<div class="row">
-  <table id="tbl-list-publications" class="table compact stripe">
-    <thead>
-      <tr>
-        <th>#</th>
-        <th>PubMed ID</th>
-        <th>Title</th>
-        <th>Authors</th>
-      </tr>
-    </thead>
-
-    <tbody></tbody>
-  </table>
-</div>
-{%endblock%}
-
-
-{%block javascript%}
-<script type="text/javascript" src="/static/js/urls.js"></script>
-
-<script type="text/javascript">
-  $(function() {
-      var publicationsDataTable = buildDataTable(
-          "#tbl-list-publications",
-          [],
-          [
-              {data: "index"},
-              {
-                  searchable: true,
-                  data: (pub) => {
-                      if(pub.PubMed_ID) {
-                          return `<a href="https://pubmed.ncbi.nlm.nih.gov/` +
-                              `${pub.PubMed_ID}/" target="_blank" ` +
-                              `title="Link to publication on NCBI.">` +
-                              `${pub.PubMed_ID}</a>`;
-                      }
-                      return "";
-                  }
-              },
-              {
-                  searchable: true,
-                  data: (pub) => {
-                      var title = "⸻";
-                      if(pub.Title) {
-                          title = pub.Title
-                      }
-                      url=buildURLFromCurrentURL(
-                          `/publications/view/${pub.Id}`);
-                      return `<a href="${url}" target="_blank" ` +
-                          `title="Link to view publication details">` +
-                          `${title}</a>`;
-                  }
-              },
-              {
-                  searchable: true,
-                  data: (pub) => {
-                      authors = pub.Authors.split(",").map(
-                          (item) => {return item.trim();});
-                      if(authors.length > 1) {
-                          return authors[0] + ", et. al.";
-                      }
-                      return authors[0];
-                  }
-              }
-          ],
-          {
-              serverSide: true,
-              ajax: {
-                  url: "/publications/list",
-                  dataSrc: "publications"
-              },
-              scrollY: 700,
-              scroller: true,
-              scrollCollapse: true,
-              paging: true,
-              deferRender: true,
-              layout: {
-                  topStart: "info",
-                  topEnd: "search",
-                  bottomStart: "pageLength",
-                  bottomEnd: false
-              }
-          });
-  });
-</script>
-{%endblock%}
diff --git a/uploader/templates/publications/sui-view-publication.html b/uploader/templates/publications/sui-view-publication.html
deleted file mode 100644
index 740fc37..0000000
--- a/uploader/templates/publications/sui-view-publication.html
+++ /dev/null
@@ -1,80 +0,0 @@
-{%extends "publications/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}View Publication{%endblock%}
-
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <table class="table">
-    <tr>
-      <th>Linked Phenotypes</th>
-      <td>{{linked_phenotypes | count}}</td>
-    </tr>
-    <tr>
-      <th>PubMed</th>
-      <td>
-        {%if publication.PubMed_ID%}
-        <a href="https://pubmed.ncbi.nlm.nih.gov/{{publication.PubMed_ID}}/"
-           target="_blank">{{publication.PubMed_ID}}</a>
-        {%else%}
-        —
-        {%endif%}
-      </td>
-    </tr>
-    <tr>
-      <th>Title</th>
-      <td>{{publication.Title or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Authors</th>
-      <td>{{publication.Authors or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Journal</th>
-      <td>{{publication.Journal or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Published</th>
-      <td>{{publication.Month or ""}} {{publication.Year or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Volume</th>
-      <td>{{publication.Volume or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Pages</th>
-      <td>{{publication.Pages or "—"}}</td>
-    </tr>
-    <tr>
-      <th>Abstract</th>
-      <td>
-        {%for line in (publication.Abstract or "—").replace("\r\n", "<br />").replace("\n", "<br />").split("<br />")%}
-        <p>{{line}}</p>
-        {%endfor%}
-      </td>
-    </tr>
-  </table>
-</div>
-
-<div class="row">
-  <div>
-  <a href="{{url_for('publications.edit_publication', publication_id=publication.Id)}}"
-     title="Edit details for this publication."
-     class="btn btn-primary">Edit</a>
-  {%if linked_phenotypes | length == 0%}
-  <a href="{{url_for('publications.delete_publication', publication_id=publication.Id)}}"
-     class="btn btn-danger">delete</a>
-  {%endif%}
-  </div>
-</div>
-{%endblock%}
-
-
-{%block javascript%}
-<script type="text/javascript">
-  $(function() {});
-</script>
-{%endblock%}
diff --git a/uploader/templates/publications/view-publication.html b/uploader/templates/publications/view-publication.html
index 0bd7bc5..01ccf1e 100644
--- a/uploader/templates/publications/view-publication.html
+++ b/uploader/templates/publications/view-publication.html
@@ -3,8 +3,6 @@
 
 {%block title%}View Publication{%endblock%}
 
-{%block pagetitle%}View Publication{%endblock%}
-
 
 {%block contents%}
 {{flash_all_messages()}}
diff --git a/uploader/templates/samples/base.html b/uploader/templates/samples/base.html
index 291782b..7fd5020 100644
--- a/uploader/templates/samples/base.html
+++ b/uploader/templates/samples/base.html
@@ -1,12 +1,25 @@
 {%extends "populations/base.html"%}
+{%from "populations/macro-display-population-card.html" import display_sui_population_card%}
 
-{%block lvl3_breadcrumbs%}
-<li {%if activelink=="samples"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('species.populations.samples.index')}}">Samples</a>
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('species.populations.samples.list_samples',
+           species_id=species['SpeciesId'],
+           population_id=population.Id)}}">
+    Samples
+  </a>
 </li>
-{%block lvl4_breadcrumbs%}{%endblock%}
+{%endblock%}
+
+{%block contents%}
+<div class="row">
+  <h2 class="heading">{{population.FullName}} ({{population.Name}})</h2>
+</div>
+{%endblock%}
+
+
+
+{%block sidebarcontents%}
+{{display_sui_population_card(species, population)}}
 {%endblock%}
diff --git a/uploader/templates/samples/list-samples.html b/uploader/templates/samples/list-samples.html
index aed27c3..3aac984 100644
--- a/uploader/templates/samples/list-samples.html
+++ b/uploader/templates/samples/list-samples.html
@@ -1,53 +1,34 @@
 {%extends "samples/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
 {%from "populations/macro-select-population.html" import select_population_form%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block title%}Samples &mdash; List Samples{%endblock%}
 
-{%block pagetitle%}Samples &mdash; List Samples{%endblock%}
-
-{%block lvl4_breadcrumbs%}
-<li {%if activelink=="list-samples"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('species.populations.samples.list_samples',
-           species_id=species.SpeciesId,
-           population_id=population.Id)}}">List</a>
-</li>
-{%endblock%}
-
 {%block contents%}
-{{flash_all_messages()}}
+{{super()}}
 
 <div class="row">
-  <p>
-    You selected the population "{{population.FullName}}" from the
-    "{{species.FullName}}" species.
-  </p>
+  <h3 class="subheading">manage samples</h3>
+  {{flash_all_messages()}}
 </div>
 
 <div class="row">
-  <p>
+  <div class="col">
     <a href="{{url_for('species.populations.samples.upload_samples',
              species_id=species.SpeciesId,
              population_id=population.Id)}}"
        title="Add samples for population '{{population.FullName}}' from species
               '{{species.FullName}}'."
-       class="btn btn-primary">
-      add samples
-    </a>
-  </p>
+       class="btn btn-primary">add new samples</a>
+  </div>
 </div>
 
 {%if samples | length > 0%}
 <div class="row">
   <p>
-    This population already has <strong>{{total_samples}}</strong>
-    samples/individuals entered. You can explore the list of samples in this
-    population in the table below.
+    Population "{{population.FullName}} ({{population.Name}})" already has
+    <strong>{{total_samples}}</strong> samples/individuals entered. You can
+    explore the list of samples in the table below.
   </p>
 </div>
 
@@ -106,15 +87,6 @@
       {%endfor%}
     </tbody>
   </table>
-
-  <p>
-    <a href="#"
-       title="Delete samples from population '{{population.FullName}}' from species
-              '{{species.FullName}}'."
-       class="btn btn-danger not-implemented">
-      delete all samples
-    </a>
-  </p>
 </div>
 {%else%}
 <div class="row">
@@ -124,7 +96,3 @@
 {%endif%}
 
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
-{%endblock%}
diff --git a/uploader/templates/samples/sui-base.html b/uploader/templates/samples/sui-base.html
deleted file mode 100644
index 8ec7505..0000000
--- a/uploader/templates/samples/sui-base.html
+++ /dev/null
@@ -1,25 +0,0 @@
-{%extends "populations/sui-base.html"%}
-{%from "populations/macro-display-population-card.html" import display_sui_population_card%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('species.populations.samples.list_samples',
-           species_id=species['SpeciesId'],
-           population_id=population.Id)}}">
-    Samples
-  </a>
-</li>
-{%endblock%}
-
-{%block contents%}
-<div class="row">
-  <h2 class="heading">{{population.FullName}} ({{population.Name}})</h2>
-</div>
-{%endblock%}
-
-
-
-{%block sidebarcontents%}
-{{display_sui_population_card(species, population)}}
-{%endblock%}
diff --git a/uploader/templates/samples/sui-list-samples.html b/uploader/templates/samples/sui-list-samples.html
deleted file mode 100644
index e9ed71a..0000000
--- a/uploader/templates/samples/sui-list-samples.html
+++ /dev/null
@@ -1,98 +0,0 @@
-{%extends "samples/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "populations/macro-select-population.html" import select_population_form%}
-
-{%block title%}Samples &mdash; List Samples{%endblock%}
-
-{%block contents%}
-{{super()}}
-
-<div class="row">
-  <h3 class="subheading">manage samples</h3>
-  {{flash_all_messages()}}
-</div>
-
-<div class="row">
-  <div class="col">
-    <a href="{{url_for('species.populations.samples.upload_samples',
-             species_id=species.SpeciesId,
-             population_id=population.Id)}}"
-       title="Add samples for population '{{population.FullName}}' from species
-              '{{species.FullName}}'."
-       class="btn btn-primary">add new samples</a>
-  </div>
-</div>
-
-{%if samples | length > 0%}
-<div class="row">
-  <p>
-    Population "{{population.FullName}} ({{population.Name}})" already has
-    <strong>{{total_samples}}</strong> samples/individuals entered. You can
-    explore the list of samples in the table below.
-  </p>
-</div>
-
-<div class="row">
-  <div class="col-md-2">
-    {%if offset > 0:%}
-    <a href="{{url_for('species.populations.samples.list_samples',
-             species_id=species.SpeciesId,
-             population_id=population.Id,
-             from=offset-count,
-             count=count)}}">
-      <span class="glyphicon glyphicon-backward"></span>
-      Previous
-    </a>
-    {%endif%}
-  </div>
-
-  <div class="col-md-8" style="text-align: center;">
-    Samples {{offset}} &mdash; {{offset+(count if offset + count < total_samples else total_samples - offset)}} / {{total_samples}}
-                                                                   </div>
-
-  <div class="col-md-2">
-    {%if offset + count < total_samples:%}
-    <a href="{{url_for('species.populations.samples.list_samples',
-             species_id=species.SpeciesId,
-             population_id=population.Id,
-             from=offset+count,
-             count=count)}}">
-      Next
-      <span class="glyphicon glyphicon-forward"></span>
-    </a>
-    {%endif%}
-  </div>
-</div>
-<div class="row">
-  <table class="table">
-    <thead>
-      <tr>
-        <th></th>
-        <th>Name</th>
-        <th>Auxilliary Name</th>
-        <th>Symbol</th>
-        <th>Alias</th>
-      </tr>
-    </thead>
-
-    <tbody>
-      {%for sample in samples%}
-      <tr>
-        <td>{{sample.sequence_number}}</td>
-        <td>{{sample.Name}}</td>
-        <td>{{sample.Name2}}</td>
-        <td>{{sample.Symbol or "-"}}</td>
-        <td>{{sample.Alias or "-"}}</td>
-      </tr>
-      {%endfor%}
-    </tbody>
-  </table>
-</div>
-{%else%}
-<div class="row">
-  <p>There are no samples entered for this population. Click the "Add Samples"
-    button above, to add some new samples.</p>
-</div>
-{%endif%}
-
-{%endblock%}
diff --git a/uploader/templates/samples/sui-upload-failure.html b/uploader/templates/samples/sui-upload-failure.html
deleted file mode 100644
index d950c50..0000000
--- a/uploader/templates/samples/sui-upload-failure.html
+++ /dev/null
@@ -1,32 +0,0 @@
-{%extends "sui-base.html"%}
-{%from "cli-output.html" import cli_output%}
-
-{%block title%}Samples Upload Failure{%endblock%}
-
-{%block contents%}
-<div class="row">
-<h2 class="heading">{{job.job_name[0:50]}}&hellip;</h2>
-
-<p>There was a failure attempting to upload the samples.</p>
-
-<p>Here is some information to help with debugging the issue. Provide this
-  information to the developer/maintainer.</p>
-
-<h3>Debugging Information</h3>
-<ul>
-  <li><strong>job id</strong>: {{job.jobid}}</li>
-  <li><strong>status</strong>: {{job.status}}</li>
-  <li><strong>job type</strong>: {{job["job-type"]}}</li>
-</ul>
-</div>
-
-<div class="row">
-<h4>stdout</h4>
-{{cli_output(job, "stdout")}}
-</div>
-
-<div class="row">
-<h4>stderr</h4>
-{{cli_output(job, "stderr")}}
-</div>
-{%endblock%}
diff --git a/uploader/templates/samples/sui-upload-progress.html b/uploader/templates/samples/sui-upload-progress.html
deleted file mode 100644
index 8412c46..0000000
--- a/uploader/templates/samples/sui-upload-progress.html
+++ /dev/null
@@ -1,26 +0,0 @@
-{%extends "samples/sui-base.html"%}
-{%from "cli-output.html" import cli_output%}
-
-{%block extrameta%}
-<meta http-equiv="refresh" content="5">
-{%endblock%}
-
-{%block title%}Job Status{%endblock%}
-
-{%block contents%}
-<div class="row" style="overflow-x: clip;">
-<h2 class="heading">{{job.job_name[0:50]}}&hellip;</h2>
-
-<p>
-<strong>status</strong>:
-<span>{{job["status"]}} ({{job.get("message", "-")}})</span><br />
-</p>
-
-<p>saving to database...</p>
-</div>
-
-<div class="row">
-  {{cli_output(job, "stdout")}}
-</div>
-
-{%endblock%}
diff --git a/uploader/templates/samples/sui-upload-samples.html b/uploader/templates/samples/sui-upload-samples.html
deleted file mode 100644
index 83c2061..0000000
--- a/uploader/templates/samples/sui-upload-samples.html
+++ /dev/null
@@ -1,153 +0,0 @@
-{%extends "samples/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-
-{%block title%}Samples &mdash; Upload Samples{%endblock%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('species.populations.samples.upload_samples',
-           species_id=species['SpeciesId'],
-           population_id=population.Id)}}">
-    Upload
-  </a>
-</li>
-{%endblock%}
-
-{%block contents%}
-{{flash_all_messages()}}
-
-<div class="row">
-  <form id="form-samples"
-        method="POST"
-        action="{{url_for('species.populations.samples.upload_samples',
-                species_id=species.SpeciesId,
-                population_id=population.InbredSetId)}}"
-        enctype="multipart/form-data">
-    <legend class="heading">upload samples</legend>
-
-    <input type="hidden" name="species_id" value="{{species.SpeciesId}}" />
-    <input type="hidden" name="population_id" value="{{population.Id}}" />
-
-    <div class="form-group">
-      <label for="file-samples" class="form-label">select file</label>
-      <input type="file" name="samples_file" id="file-samples"
-	     accept="text/csv, text/tab-separated-values, text/plain"
-	     class="form-control" />
-      <small class="form-text text-muted">
-        See the <a href="#docs-samples-upload">documentation below</a> for
-        details on expected file format.</small>
-    </div>
-
-    <div class="form-group">
-      <label for="select-separator" class="form-label">field separator</label>
-      <select id="select-separator"
-	      name="separator"
-	      required="required"
-	      class="form-control">
-        <option value="">Select separator for your file: (default is comma)</option>
-        <option value="&#x0009;">TAB</option>
-        <option value="&#x0020;">Space</option>
-        <option value=",">Comma</option>
-        <option value=";">Semicolon</option>
-        <option value="other">Other</option>
-      </select>
-      <input id="txt-separator"
-	     type="text"
-	     name="other_separator"
-	     class="form-control" />
-      <small class="form-text text-muted">
-        If you select '<strong>Other</strong>' for the field separator value,
-        enter the character that separates the fields in your CSV file in the form
-        field below.
-      </small>
-    </div>
-
-    <div class="form-group form-check">
-      <input id="chk-heading"
-	     type="checkbox"
-	     name="first_line_heading"
-	     class="form-check-input" />
-      <label for="chk-heading" class="form-check-label">
-        first line is a heading?</label>
-      <small class="form-text text-muted">
-        Select this if the first line in your file contains headings for the
-        columns.
-      </small>
-    </div>
-
-    <div class="form-group">
-      <label for="txt-delimiter" class="form-label">field delimiter</label>
-      <input id="txt-delimiter"
-	     type="text"
-	     name="field_delimiter"
-	     maxlength="1"
-	     class="form-control" />
-      <small class="form-text text-muted">
-        If there is a character delimiting the string texts within particular
-        fields in your CSV, provide the character here. This can be left blank if
-        no such delimiters exist in your file.
-      </small>
-    </div>
-
-    <button type="submit"
-	    class="btn btn-primary">upload samples file</button>
-  </form>
-</div>
-
-<div class="row">
-  <h3>Preview File Content</h3>
-
-  <table id="tbl:samples-preview" class="table">
-    <caption class="heading">preview content</caption>
-
-    <thead>
-      <tr>
-        <th>Name</th>
-        <th>Name2</th>
-        <th>Symbol</th>
-        <th>Alias</th>
-      </tr>
-    </thead>
-
-    <tbody>
-      <tr id="default-row">
-        <td colspan="4">
-	  Please make some selections in the form above to preview the data.</td>
-      </tr>
-    </tbody>
-  </table>
-</div>
-
-
-
-<div class="row" id="docs-samples-upload">
-  <h3 class="subheading">File Format</h3>
-  <p>
-    Upload a <strong>character-separated value (CSV)</strong> file that contains
-    details about your samples. The CSV file should have the following fields:
-    <dl>
-      <dt>Name</dt>
-      <dd>The primary name/identifier for the sample/individual.</dd>
-
-      <dt>Name2</dt>
-      <dd>A secondary name for the sample. This can simply be the same as
-        <strong>Name</strong> above. This field <strong>MUST</strong> contain a
-        value.</dd>
-
-      <dt>Symbol</dt>
-      <dd>A symbol for the sample. This can be a strain name, e.g. 'BXD60' for
-        species that have strains. This field can be left empty for species like
-        Humans that do not have strains..</dd>
-
-      <dt>Alias</dt>
-      <dd>An alias for the sample. Can be an empty field, or take on the same
-        value as that of the Symbol.</dd>
-    </dl>
-  </p>
-</div>
-{%endblock%}
-
-{%block javascript%}
-<script src="/static/js/upload_samples.js" type="text/javascript"></script>
-{%endblock%}
diff --git a/uploader/templates/samples/sui-upload-success.html b/uploader/templates/samples/sui-upload-success.html
deleted file mode 100644
index 054bde8..0000000
--- a/uploader/templates/samples/sui-upload-success.html
+++ /dev/null
@@ -1,31 +0,0 @@
-{%extends "samples/sui-base.html"%}
-{%from "cli-output.html" import cli_output%}
-
-{%block title%}Job Status{%endblock%}
-
-{%block contents%}
-
-<div class="row" style="overflow-x: clip;">
-  <h2 class="heading">{{job.job_name[0:50]}}&hellip;</h2>
-
-  <p>
-    <strong>status</strong>:
-    <span>{{job["status"]}} ({{job.get("message", "-")}})</span><br />
-  </p>
-
-  <p>Successfully uploaded the samples.</p>
-  <p>
-    <a href="{{url_for('species.populations.samples.list_samples',
-             species_id=species.SpeciesId,
-             population_id=population.Id)}}"
-       title="View population samples">
-      View samples
-    </a>
-  </p>
-</div>
-
-<div class="row">
-  {{cli_output(job, "stdout")}}
-</div>
-
-{%endblock%}
diff --git a/uploader/templates/samples/upload-failure.html b/uploader/templates/samples/upload-failure.html
index 2cf8053..75192ec 100644
--- a/uploader/templates/samples/upload-failure.html
+++ b/uploader/templates/samples/upload-failure.html
@@ -1,6 +1,5 @@
 {%extends "base.html"%}
 {%from "cli-output.html" import cli_output%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block title%}Samples Upload Failure{%endblock%}
 
@@ -31,7 +30,3 @@
 {{cli_output(job, "stderr")}}
 </div>
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
-{%endblock%}
diff --git a/uploader/templates/samples/upload-progress.html b/uploader/templates/samples/upload-progress.html
index 677d457..38f931b 100644
--- a/uploader/templates/samples/upload-progress.html
+++ b/uploader/templates/samples/upload-progress.html
@@ -1,6 +1,5 @@
 {%extends "samples/base.html"%}
 {%from "cli-output.html" import cli_output%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block extrameta%}
 <meta http-equiv="refresh" content="5">
@@ -25,7 +24,3 @@
 </div>
 
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
-{%endblock%}
diff --git a/uploader/templates/samples/upload-samples.html b/uploader/templates/samples/upload-samples.html
index 4aa2f7f..1f665a3 100644
--- a/uploader/templates/samples/upload-samples.html
+++ b/uploader/templates/samples/upload-samples.html
@@ -1,21 +1,16 @@
 {%extends "samples/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
-{%from "populations/macro-select-population.html" import select_population_form%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block title%}Samples &mdash; Upload Samples{%endblock%}
 
-{%block pagetitle%}Samples &mdash; Upload Samples{%endblock%}
-
-{%block lvl4_breadcrumbs%}
-<li {%if activelink=="uploade-samples"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
   <a href="{{url_for('species.populations.samples.upload_samples',
-           species_id=species.SpeciesId,
-           population_id=population.Id)}}">List</a>
+           species_id=species['SpeciesId'],
+           population_id=population.Id)}}">
+    Upload
+  </a>
 </li>
 {%endblock%}
 
@@ -23,35 +18,6 @@
 {{flash_all_messages()}}
 
 <div class="row">
-  <p>
-    You can now upload the samples for the "{{population.FullName}}" population
-    from the "{{species.FullName}}" species here.
-  </p>
-  <p>
-    Upload a <strong>character-separated value (CSV)</strong> file that contains
-    details about your samples. The CSV file should have the following fields:
-    <dl>
-      <dt>Name</dt>
-      <dd>The primary name/identifier for the sample/individual.</dd>
-
-      <dt>Name2</dt>
-      <dd>A secondary name for the sample. This can simply be the same as
-        <strong>Name</strong> above. This field <strong>MUST</strong> contain a
-        value.</dd>
-
-      <dt>Symbol</dt>
-      <dd>A symbol for the sample. This can be a strain name, e.g. 'BXD60' for
-        species that have strains. This field can be left empty for species like
-        Humans that do not have strains..</dd>
-
-      <dt>Alias</dt>
-      <dd>An alias for the sample. Can be an empty field, or take on the same
-        value as that of the Symbol.</dd>
-    </dl>
-  </p>
-</div>
-
-<div class="row">
   <form id="form-samples"
         method="POST"
         action="{{url_for('species.populations.samples.upload_samples',
@@ -68,6 +34,9 @@
       <input type="file" name="samples_file" id="file-samples"
 	     accept="text/csv, text/tab-separated-values, text/plain"
 	     class="form-control" />
+      <small class="form-text text-muted">
+        See the <a href="#docs-samples-upload">documentation below</a> for
+        details on expected file format.</small>
     </div>
 
     <div class="form-group">
@@ -149,10 +118,34 @@
     </tbody>
   </table>
 </div>
-{%endblock%}
 
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
+
+
+<div class="row" id="docs-samples-upload">
+  <h3 class="subheading">File Format</h3>
+  <p>
+    Upload a <strong>character-separated value (CSV)</strong> file that contains
+    details about your samples. The CSV file should have the following fields:
+    <dl>
+      <dt>Name</dt>
+      <dd>The primary name/identifier for the sample/individual.</dd>
+
+      <dt>Name2</dt>
+      <dd>A secondary name for the sample. This can simply be the same as
+        <strong>Name</strong> above. This field <strong>MUST</strong> contain a
+        value.</dd>
+
+      <dt>Symbol</dt>
+      <dd>A symbol for the sample. This can be a strain name, e.g. 'BXD60' for
+        species that have strains. This field can be left empty for species like
+        Humans that do not have strains..</dd>
+
+      <dt>Alias</dt>
+      <dd>An alias for the sample. Can be an empty field, or take on the same
+        value as that of the Symbol.</dd>
+    </dl>
+  </p>
+</div>
 {%endblock%}
 
 {%block javascript%}
diff --git a/uploader/templates/samples/upload-success.html b/uploader/templates/samples/upload-success.html
index 881d466..d6318e9 100644
--- a/uploader/templates/samples/upload-success.html
+++ b/uploader/templates/samples/upload-success.html
@@ -1,6 +1,5 @@
 {%extends "samples/base.html"%}
 {%from "cli-output.html" import cli_output%}
-{%from "populations/macro-display-population-card.html" import display_population_card%}
 
 {%block title%}Job Status{%endblock%}
 
@@ -30,7 +29,3 @@
 </div>
 
 {%endblock%}
-
-{%block sidebarcontents%}
-{{display_population_card(species, population)}}
-{%endblock%}
diff --git a/uploader/templates/species/base.html b/uploader/templates/species/base.html
index f64f72b..a7c1a8f 100644
--- a/uploader/templates/species/base.html
+++ b/uploader/templates/species/base.html
@@ -1,17 +1,10 @@
 {%extends "base.html"%}
 
-{%block lvl1_breadcrumbs%}
-<li {%if activelink=="species"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  {%if species is mapping%}
-  <a href="{{url_for('species.view_species', species_id=species.SpeciesId)}}">
-    {{species.Name}}</a>
-  {%else%}
-  <a href="{{url_for('species.list_species')}}">Species</a>
-  {%endif%}
+{%block breadcrumbs%}
+{{super()}}
+<li class="breadcrumb-item">
+  <a href="{{url_for('species.view_species', species_id=species['SpeciesId'])}}">
+    {{species["Name"]|title}}
+  </a>
 </li>
-{%block lvl2_breadcrumbs%}{%endblock%}
 {%endblock%}
diff --git a/uploader/templates/species/sui-base.html b/uploader/templates/species/sui-base.html
deleted file mode 100644
index f7b4fef..0000000
--- a/uploader/templates/species/sui-base.html
+++ /dev/null
@@ -1,10 +0,0 @@
-{%extends "sui-base.html"%}
-
-{%block breadcrumbs%}
-{{super()}}
-<li class="breadcrumb-item">
-  <a href="{{url_for('species.view_species', species_id=species['SpeciesId'])}}">
-    {{species["Name"]|title}}
-  </a>
-</li>
-{%endblock%}
diff --git a/uploader/templates/species/sui-view-species.html b/uploader/templates/species/sui-view-species.html
deleted file mode 100644
index 4b6402e..0000000
--- a/uploader/templates/species/sui-view-species.html
+++ /dev/null
@@ -1,127 +0,0 @@
-{%extends "species/sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "macro-forms.html" import add_http_feature_flags%}
-{%from "macro-step-indicator.html" import step_indicator%}
-{%from "species/macro-display-species-card.html" import display_sui_species_card%}
-
-{%block title%}View Species{%endblock%}
-
-{%macro add_form_buttons()%}
-<div class="row form-buttons">
-  <div class="col">
-    <input type="submit"
-           value="use selected population"
-           class="btn btn-primary" />
-  </div>
-
-  <div class="col">
-    <a href="url_for('species.population.create_population',
-             species_id=species.SpeciesId,
-             return_to='species.view_species')"
-       title="Create a new population for species '{{species.Name}}'."
-       class="btn btn-outline-info">
-      Create a new population
-    </a>
-  </div>
-</div>
-{%endmacro%}
-
-
-{%block contents%}
-<div class="row">
-  <h2 class="heading">{{species.FullName}} ({{species.Name}})</h2>
-</div>
-
-<div class "row">
-  <ul class="nav nav-tabs" id="species-actions">
-    <li class="nav-item presentation">
-      <button class="nav-link active"
-              id="populations-tab"
-              data-bs-toggle="tab"
-              data-bs-target="#populations-content"
-              type="button"
-              role="tab"
-              aria-controls="populations-content"
-              aria-selected="true">Populations</button>
-    </li>
-    <li class="nav-item presentation">
-      <button class="nav-link"
-              id="sequencing-platforms-tab"
-              data-bs-toggle="tab"
-              data-bs-target="#sequencing-platforms-content"
-              type="button"
-              role="tab"
-              aria-controls="sequencing-platforms-content"
-              aria-selected="true">Sequencing Platforms</button>
-    </li>
-  </ul>
-</div>
-
-<div class="row">
-  <div class="tab-content" id="species-tabs-content">
-    <div class="tab-pane fade show active"
-         id="populations-content"
-         role="tabpanel"
-         aria-labelledby="populations-content-tab">
-      <p>Data belonging to a particular species is further divided into one or more
-        populations for easier handling. Please select the population you want to work
-        with.</p>
-
-      <form method="GET"
-            action="{{url_for('species.view_species', species_id=species.SpeciesId)}}"
-            class="form-horizontal">
-        {{add_http_feature_flags()}}
-        {{add_form_buttons()}}
-
-        {%if populations | length != 0%}
-        <div style="margin-top:0.3em;">
-          <table id="tbl-select-population" class="table compact stripe"
-                 data-populations-list='{{populations | tojson}}'>
-            <thead>
-              <tr>
-                <th></th>
-                <th>Population</th>
-              </tr>
-            </thead>
-
-            <tbody></tbody>
-          </table>
-        </div>
-
-        {%else%}
-        <p class="form-text">
-          There are no populations currently defined for {{species['FullName']}}
-          ({{species['SpeciesName']}}).</p>
-        {%endif%}
-
-        {{add_form_buttons()}}
-
-      </form>
-    </div>
-    <div class="tab-pane fade"
-         id="sequencing-platforms-content"
-         role="tabpanel"
-         aria-labelledby="sequencing-platforms-content-tab">
-      <p>Upload and manage the sequencing platforms for species
-        '{{species.Name | title}} ({{species.FullName}})'
-        <a href="{{url_for('species.platforms.list_platforms',
-                 species_id=species.SpeciesId)}}"
-           title="Manage sequencing platforms for {{species.Name}}">here</a>.
-      </p>
-    </div>
-  </div>
-</div>
-{%endblock%}
-
-{%block sidebarcontents%}
-<div class="row">
-  <p>You can manage species' populations and sequencing platforms here. Select
-    the tab for the feature you wish to continue working on.</p>
-</div>
-{{display_sui_species_card(species)}}
-{%endblock%}
-
-
-{%block javascript%}
-<script type="text/javascript" src="/static/js/populations.js"></script>
-{%endblock%}
diff --git a/uploader/templates/species/view-species.html b/uploader/templates/species/view-species.html
index 2d02f7e..81608fc 100644
--- a/uploader/templates/species/view-species.html
+++ b/uploader/templates/species/view-species.html
@@ -1,90 +1,127 @@
 {%extends "species/base.html"%}
 {%from "flash_messages.html" import flash_all_messages%}
+{%from "macro-forms.html" import add_http_feature_flags%}
+{%from "macro-step-indicator.html" import step_indicator%}
+{%from "species/macro-display-species-card.html" import display_sui_species_card%}
 
 {%block title%}View Species{%endblock%}
 
-{%block pagetitle%}View Species{%endblock%}
+{%macro add_form_buttons()%}
+<div class="row form-buttons">
+  <div class="col">
+    <input type="submit"
+           value="use selected population"
+           class="btn btn-primary" />
+  </div>
+
+  <div class="col">
+    <a href="{{url_for('species.populations.create_population',
+             species_id=species.SpeciesId,
+             return_to='species.view_species')}}"
+       title="Create a new population for species '{{species.Name}}'."
+       class="btn btn-outline-info">
+      Create a new population
+    </a>
+  </div>
+</div>
+{%endmacro%}
 
-{%block lvl2_breadcrumbs%}
-<li {%if activelink=="view-species"%}
-    class="breadcrumb-item active"
-    {%else%}
-    class="breadcrumb-item"
-    {%endif%}>
-  <a href="{{url_for('species.view_species', species_id=species.SpeciesId)}}">View</a>
-</li>
-{%endblock%}
 
 {%block contents%}
-{{flash_all_messages()}}
 <div class="row">
-  <h2>Details on species {{species.FullName}}</h2>
+  <h2 class="heading">{{species.FullName}} ({{species.Name}})</h2>
+</div>
 
-  <dl>
-    <dt>Common Name</dt>
-    <dd>{{species.SpeciesName}}</dd>
+<div class "row">
+  <ul class="nav nav-tabs" id="species-actions">
+    <li class="nav-item presentation">
+      <button class="nav-link active"
+              id="populations-tab"
+              data-bs-toggle="tab"
+              data-bs-target="#populations-content"
+              type="button"
+              role="tab"
+              aria-controls="populations-content"
+              aria-selected="true">Populations</button>
+    </li>
+    <li class="nav-item presentation">
+      <button class="nav-link"
+              id="sequencing-platforms-tab"
+              data-bs-toggle="tab"
+              data-bs-target="#sequencing-platforms-content"
+              type="button"
+              role="tab"
+              aria-controls="sequencing-platforms-content"
+              aria-selected="true">Sequencing Platforms</button>
+    </li>
+  </ul>
+</div>
 
-    <dt>Scientific Name</dt>
-    <dd>{{species.FullName}}</dd>
+<div class="row">
+  <div class="tab-content" id="species-tabs-content">
+    <div class="tab-pane fade show active"
+         id="populations-content"
+         role="tabpanel"
+         aria-labelledby="populations-content-tab">
+      <p>Data belonging to a particular species is further divided into one or more
+        populations for easier handling. Please select the population you want to work
+        with.</p>
 
-    <dt>Taxonomy ID</dt>
-    <dd>{{species.TaxonomyId}}</dd>
-  </dl>
+      <form method="GET"
+            action="{{url_for('species.view_species', species_id=species.SpeciesId)}}"
+            class="form-horizontal">
+        {{add_http_feature_flags()}}
+        {{add_form_buttons()}}
 
-  <h3>Actions</h3>
+        {%if populations | length != 0%}
+        <div style="margin-top:0.3em;">
+          <table id="tbl-select-population" class="table compact stripe"
+                 data-populations-list='{{populations | tojson}}'>
+            <thead>
+              <tr>
+                <th></th>
+                <th>Population</th>
+              </tr>
+            </thead>
 
-  <p>
-    You can proceed to perform any of the following actions for species
-    {{species.FullName}}
-  </p>
+            <tbody></tbody>
+          </table>
+        </div>
 
-  <ol>
-    <li>
-      <a href="{{url_for('species.populations.list_species_populations',
-               species_id=species.SpeciesId)}}"
-         title="Create/Edit populations for {{species.FullName}}">
-        Manage populations</a>
-    </li>
-    <li>
-      <a href="{{url_for('species.platforms.list_platforms',
-               species_id=species.SpeciesId)}}"
-         title="Create/Edit sequencing platforms for {{species.FullName}}">
-        Manage sequencing platforms</a>
-    </li>
-  </ol>
+        {%else%}
+        <p class="form-text">
+          There are no populations currently defined for {{species['FullName']}}
+          ({{species['SpeciesName']}}).</p>
+        {%endif%}
 
-  
+        {{add_form_buttons()}}
+
+      </form>
+    </div>
+    <div class="tab-pane fade"
+         id="sequencing-platforms-content"
+         role="tabpanel"
+         aria-labelledby="sequencing-platforms-content-tab">
+      <p>Upload and manage the sequencing platforms for species
+        '{{species.Name | title}} ({{species.FullName}})'
+        <a href="{{url_for('species.platforms.list_platforms',
+                 species_id=species.SpeciesId)}}"
+           title="Manage sequencing platforms for {{species.Name}}">here</a>.
+      </p>
+    </div>
+  </div>
 </div>
 {%endblock%}
 
 {%block sidebarcontents%}
-<div class="card">
-  <div class="card-body">
-    <h5 class="card-title">Species Extras</h5>
-    <div class="card-text">
-      <p>Some extra internal-use details (mostly for UI concerns on GeneNetwork)</p>
-      <p>
-        <small>
-          If you do not understand what the following are about, simply ignore them
-          &mdash;
-          They have no bearing whatsoever on your data, or its analysis.
-        </small>
-      </p>
-      <dl>
-        <dt>Family</dt>
-        <dd>{{species.Family}}</dd>
+<div class="row">
+  <p>You can manage species' populations and sequencing platforms here. Select
+    the tab for the feature you wish to continue working on.</p>
+</div>
+{{display_sui_species_card(species)}}
+{%endblock%}
 
-        <dt>FamilyOrderId</dt>
-        <dd>{{species.FamilyOrderId}}</dd>
 
-        <dt>OrderId</dt>
-        <dd>{{species.OrderId}}</dd>
-      </dl>
-    </div>
-    <a href="{{url_for('species.edit_species_extra',
-             species_id=species.SpeciesId)}}"
-       class="card-link"
-       title="Edit the species' internal-use details.">Edit</a>
-  </div>
-</div>
+{%block javascript%}
+<script type="text/javascript" src="/static/js/populations.js"></script>
 {%endblock%}
diff --git a/uploader/templates/sui-base.html b/uploader/templates/sui-base.html
deleted file mode 100644
index 719a646..0000000
--- a/uploader/templates/sui-base.html
+++ /dev/null
@@ -1,103 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-
-  <head>
-
-    <meta charset="UTF-8" />
-    <meta application-name="GeneNetwork Quality-Control Application" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    {%block extrameta%}{%endblock%}
-
-    <title>Data Upload and Quality Control: {%block title%}{%endblock%}</title>
-
-    <link rel="stylesheet" type="text/css"
-	  href="{{url_for('base.bootstrap',
-                filename='css/bootstrap.min.css')}}" />
-    <link rel="stylesheet" type="text/css"
-          href="{{url_for('base.datatables',
-                filename='css/dataTables.bootstrap5.min.css')}}" />
-    <link rel="stylesheet" type="text/css" href="/static/css/layout-common.css" />
-    <link rel="stylesheet" type="text/css" href="/static/css/layout-large.css" />
-    <link rel="stylesheet" type="text/css" href="/static/css/layout-medium.css" />
-    <link rel="stylesheet" type="text/css" href="/static/css/layout-small.css" />
-    <link rel="stylesheet" type="text/css" href="/static/css/theme.css" />
-
-    {%block css%}{%endblock%}
-
-  </head>
-
-  <body>
-    <header id="header">
-      <span id="header-text">GeneNetwork</span>
-      <nav id="header-nav">
-        <ul class="nav justify-content-end">
-          <li>
-            {%if user_logged_in()%}
-            <a href="{{url_for('oauth2.logout')}}"
-               title="Log out of the system">
-              <span class="glyphicon glyphicon-user"></span>
-              {{user_email()}} Sign Out</a>
-            {%else%}
-            <a href="{{authserver_authorise_uri()}}"
-               title="Log in to the system">Sign In</a>
-            {%endif%}
-          </li>
-        </ul>
-      </nav>
-    </header>
-
-
-    <main id="main" class="main">
-      <nav id="breadcrumbs" aria-label="breadcrumb">
-        <ol class="breadcrumb">
-          {%block breadcrumbs%}
-          <li class="breadcrumb-item">
-            <a href="{{url_for('base.index')}}">Home</a></li>
-          {%endblock%}
-        </ol>
-      </nav>
-
-      <div id="main-content">
-          {%block contents%}{%endblock%}
-        </div>
-
-      <div id="sidebar-content">
-          {%block sidebarcontents%}{%endblock%}
-        </div>
-    </main>
-
-
-
-    <script type="text/javascript" src="/static/js/debug.js"></script>
-    <!--
-        Core dependencies
-      -->
-    <script src="{{url_for('base.jquery',
-                 filename='jquery.min.js')}}"></script>
-    <script src="{{url_for('base.bootstrap',
-                 filename='js/bootstrap.min.js')}}"></script>
-
-    <!--
-        DataTables dependencies
-      -->
-    <script type="text/javascript"
-            src="{{url_for('base.datatables',
-                 filename='js/dataTables.min.js')}}"></script>
-    <script type="text/javascript"
-        src="{{url_for('base.datatables_extensions',
-             filename='scroller/js/dataTables.scroller.min.js')}}"></script>
-    <script type="text/javascript"
-            src="{{url_for('base.datatables_extensions',
-                 filename='buttons/js/dataTables.buttons.min.js')}}"></script>
-    <script type="text/javascript"
-            src="{{url_for('base.datatables_extensions',
-                 filename='select/js/dataTables.select.min.js')}}"></script>
-
-    <!--
-        local dependencies
-      -->
-    <script type="text/javascript" src="/static/js/utils.js"></script>
-    <script type="text/javascript" src="/static/js/datatables.js"></script>
-    {%block javascript%}{%endblock%}
-  </body>
-</html>
diff --git a/uploader/templates/sui-index.html b/uploader/templates/sui-index.html
deleted file mode 100644
index b93bf40..0000000
--- a/uploader/templates/sui-index.html
+++ /dev/null
@@ -1,161 +0,0 @@
-{%extends "sui-base.html"%}
-{%from "flash_messages.html" import flash_all_messages%}
-{%from "macro-forms.html" import add_http_feature_flags%}
-{%from "macro-step-indicator.html" import step_indicator%}
-
-{%block title%}Home{%endblock%}
-
-{%block pagetitle%}Home{%endblock%}
-
-{%block extra_breadcrumbs%}{%endblock%}
-
-{%block contents%}
-
-{%macro add_form_buttons()%}
-<div class="row form-buttons">
-  <div class="col">
-    <input type="submit"
-           class="btn btn-primary"
-           value="use selected species" />
-  </div>
-  <div class="col">
-    <a href="{{url_for('species.create_species', return_to='base.index')}}"
-       class="btn btn-outline-primary"
-       title="Create a new species.">Create a new Species</a>
-  </div>
-</div>
-{%endmacro%}
-
-<div class="row">{{flash_all_messages()}}</div>
-
-{%if user_logged_in()%}
-
-<div class="row">
-  <ul class="nav nav-tabs" id="index-actions">
-    <li class="nav-item presentation">
-      <button class="nav-link active"
-              id="upload-data-tab"
-              data-bs-toggle="tab"
-              data-bs-target="#upload-data-content"
-              type="button"
-              role="tab"
-              aria-controls="upload-data-content"
-              aria-selected="false">Upload Data</button></li>
-    <li class="nav-item presentation">
-      <button class="nav-link"
-              id="publications-tab"
-              data-bs-toggle="tab"
-              data-bs-target="#publications-content"
-              type="button"
-              role="tab"
-              aria-controls="publications-content"
-              aria-selected="true">Publications</button></li>
-  </ul>
-</div>
-
-<div class="row">
-  <div class="tab-content" id="upload-data-tabs-content">
-    <div class="tab-pane fade show active"
-         id="upload-data-content"
-         role="tabpanel"
-         aria-labelledby="upload-data-content-tab">
-      <h2 class="heading">Species</h2>
-
-      <p>Select the species you want to work with.</p>
-
-      <form method="GET" action="{{url_for('base.index')}}" class="form-horizontal">
-        {{add_http_feature_flags()}}
-
-        {{add_form_buttons()}}
-
-        {%if species | length != 0%}
-        <div style="margin-top:1em;">
-          <table id="tbl-select-species" class="table compact stripe"
-                 data-species-list='{{species | tojson}}'>
-            <thead>
-              <tr>
-                <th></th>
-                <th>Species Name</th>
-              </tr>
-            </thead>
-
-            <tbody></tbody>
-          </table>
-        </div>
-
-        {%else%}
-
-        <label class="control-label" for="rdo-cant-find-species">
-          <input id="rdo-cant-find-species" type="radio" name="species_id"
-                 value="CREATE-SPECIES" />
-          There are no species to select from. Create the first one.</label>
-
-        <div class="col-sm-offset-10 col-sm-2">
-          <input type="submit"
-                 class="btn btn-primary col-sm-offset-1"
-                 value="continue" />
-        </div>
-
-        {%endif%}
-
-        {{add_form_buttons()}}
-
-      </form>
-    </div>
-
-    <div class="tab-pane fade"
-         id="publications-content"
-         role="tabpanel"
-         aria-labelledby="publications-content-tab">
-      <p>View, edit and delete existing publications, and add new
-        publications by clicking on the button below.</p>
-
-      <a href="{{url_for('publications.index')}}"
-         title="Manage publications."
-         class="btn btn-primary">manage publications</a>
-    </div>
-  </div>
-</div>
-
-  {%else%}
-
-  <div class="row">
-    <p>The Genenetwork Uploader (<em>gn-uploader</em>) enables upload of new data
-      into the Genenetwork System. It provides Quality Control over data, and
-      guidance in case you data does not meet the standards for acceptance.</p>
-    <p>
-      <a href="{{authserver_authorise_uri()}}"
-         title="Sign in to the system"
-         class="btn btn-primary">Sign in</a>
-      to get started.</p>
-  </div>
-  {%endif%}
-
-  {%endblock%}
-
-
-
-  {%block sidebarcontents%}
-  <div class="row">
-    <p>The data in Genenetwork is related to one species or another. Use the form
-      provided to select from existing species, or click on the
-      "Create a New Species" button if you cannot find the species you want to
-      work with.</p>
-  </div>
-  <div class="row">
-    <form id="frm-quick-navigation">
-      <legend>Quick Navigation</legend>
-      <div class="form-group">
-        <label for="fqn-species-id">Species</label>
-        <select name="species_id">
-          <option value="">Select species</option>
-        </select>
-      </div>
-    </form>
-  </div>
-  {%endblock%}
-
-
-  {%block javascript%}
-  <script type="text/javascript" src="/static/js/species.js"></script>
-  {%endblock%}
diff --git a/uploader/templates/sui-login.html b/uploader/templates/sui-login.html
deleted file mode 120000
index 733bbd3..0000000
--- a/uploader/templates/sui-login.html
+++ /dev/null
@@ -1 +0,0 @@
-sui-index.html
\ No newline at end of file
diff --git a/uploader/ui.py b/uploader/ui.py
index 1994056..41791c7 100644
--- a/uploader/ui.py
+++ b/uploader/ui.py
@@ -1,5 +1,5 @@
 """Utilities to handle the UI"""
-from flask import render_template as flask_render_template
+from uploader.flask_extensions import render_template as flask_render_template
 
 def make_template_renderer(default):
     """Render template for species."""