diff options
author | Frederick Muriuki Muriithi | 2024-09-09 14:06:31 -0500 |
---|---|---|
committer | Frederick Muriuki Muriithi | 2024-09-09 16:41:46 -0500 |
commit | 9cd33ddac3d6848c5443962d66494635feadef51 (patch) | |
tree | 385a559380f4d6a961fefb38ad410ad9ca27b052 /uploader | |
parent | 707c715d1e336ee45bdcced031881ed603b9297a (diff) | |
download | gn-uploader-9cd33ddac3d6848c5443962d66494635feadef51.tar.gz |
Initialise samples uploads
* Move existing code to new module
* Rework the UI: create new templates
* Rework the routes: Select species and populations before attempting
an upload.
Diffstat (limited to 'uploader')
18 files changed, 371 insertions, 433 deletions
diff --git a/uploader/datautils.py b/uploader/datautils.py new file mode 100644 index 0000000..b95a9e0 --- /dev/null +++ b/uploader/datautils.py @@ -0,0 +1,21 @@ +"""Generic data utilities: Rename module.""" +import math +from functools import reduce + +def order_by_family(items: tuple[dict, ...], + family_key: str = "Family", + order_key: str = "FamilyOrderId") -> list: + """Order the populations by their families.""" + def __family_order__(item): + orderval = item[order_key] + return math.inf if orderval is None else orderval + + def __order__(ordered, current): + _key = (__family_order__(current), current[family_key]) + return { + **ordered, + _key: ordered.get(_key, tuple()) + (current,) + } + + return sorted(tuple(reduce(__order__, items, {}).items()), + key=lambda item: item[0][0]) diff --git a/uploader/expression_data/__init__.py b/uploader/expression_data/__init__.py index b773bce..206a764 100644 --- a/uploader/expression_data/__init__.py +++ b/uploader/expression_data/__init__.py @@ -4,10 +4,8 @@ from flask import Blueprint from .rqtl2 import rqtl2 from .index import indexbp from .parse import parsebp -from .samples import samples exprdatabp = Blueprint("expression-data", __name__) exprdatabp.register_blueprint(indexbp, url_prefix="/") exprdatabp.register_blueprint(rqtl2, url_prefix="/rqtl2") exprdatabp.register_blueprint(parsebp, url_prefix="/parse") -exprdatabp.register_blueprint(samples, url_prefix="/sample") diff --git a/uploader/population/views.py b/uploader/population/views.py index 5be19ae..003787a 100644 --- a/uploader/population/views.py +++ b/uploader/population/views.py @@ -13,6 +13,7 @@ from flask import (flash, from uploader.ui import make_template_renderer from uploader.authorisation import require_login from uploader.db_utils import database_connection +from uploader.samples.views import samplesbp from uploader.species.models import (all_species, species_by_id, order_species_by_family) @@ -25,6 +26,7 @@ from .models import (save_population, __active_link__ = "populations" popbp = Blueprint("populations", __name__) +popbp.register_blueprint(samplesbp, url_prefix="/") render_template = make_template_renderer("populations") diff --git a/uploader/samples/models.py b/uploader/samples/models.py new file mode 100644 index 0000000..15e509e --- /dev/null +++ b/uploader/samples/models.py @@ -0,0 +1,19 @@ +"""Functions for handling samples.""" +import MySQLdb as mdb +from MySQLdb.cursors import DictCursor + +def samples_by_species_and_population( + conn: mdb.Connection, + species_id: int, + population_id: int +) -> tuple[dict, ...]: + """Fetch the samples by their species and population.""" + with conn.cursor(cursorclass=DictCursor) as cursor: + cursor.execute( + "SELECT iset.InbredSetId, s.* FROM InbredSet AS iset " + "INNER JOIN StrainXRef AS sxr ON iset.InbredSetId=sxr.InbredSetId " + "INNER JOIN Strain AS s ON sxr.StrainId=s.Id " + "WHERE s.SpeciesId=%(species_id)s " + "AND iset.InbredSetId=%(population_id)s", + {"species_id": species_id, "population_id": population_id}) + return tuple(cursor.fetchall()) diff --git a/uploader/expression_data/samples.py b/uploader/samples/views.py index d430aa9..6af90f4 100644 --- a/uploader/expression_data/samples.py +++ b/uploader/samples/views.py @@ -22,124 +22,106 @@ from functional_tools import take from uploader import jobs from uploader.files import save_file +from uploader.datautils import order_by_family from uploader.authorisation import require_login from uploader.input_validation import is_integer_input from uploader.db_utils import ( with_db_connection, database_connection, with_redis_connection) -from uploader.species.models import species_by_id, all_species as fetch_species +from uploader.species.models import (all_species, + species_by_id, + order_species_by_family) from uploader.population.models import(save_population, population_by_id, populations_by_species) -samples = Blueprint("samples", __name__) +from .models import samples_by_species_and_population -@samples.route("/upload/species", methods=["GET", "POST"]) -@require_login -def select_species(): - """Select the species.""" - if request.method == "GET": - return render_template("samples/select-species.html", - species=with_db_connection(fetch_species)) - - index_page = redirect(url_for("expression-data.index.upload_file")) - species_id = request.form.get("species_id") - if bool(species_id): - species_id = int(species_id) - species = with_db_connection( - lambda conn: species_by_id(conn, species_id)) - if bool(species): - return redirect(url_for( - "samples.select_population", species_id=species_id)) - flash("Invalid species selected!", "alert-error") - flash("You need to select a species", "alert-error") - return index_page +samplesbp = Blueprint("samples", __name__) + +@samplesbp.route("/samples", methods=["GET"]) +def index(): + """Direct entry-point for uploading/handling the samples.""" + with database_connection(app.config["SQL_URI"]) as conn: + if not bool(request.args.get("species_id")): + return render_template( + "samples/index.html", + species=order_species_by_family(all_species(conn)), + activelink="samples") + species = species_by_id(conn, request.args.get("species_id")) + if not bool(species): + flash("No such species!", "alert-danger") + return redirect(url_for("species.populations.samples.index")) + return redirect(url_for("species.populations.samples.select_population", + species_id=species["SpeciesId"])) -@samples.route("/upload/species/<int:species_id>/create-population", - methods=["POST"]) -@require_login -def create_population(species_id: int): - """Create new grouping/population.""" - if not is_integer_input(species_id): - flash("You did not provide a valid species. Please select one to " - "continue.", - "alert-danger") - return redirect(url_for("expression-data.samples.select_species")) - species = with_db_connection(lambda conn: species_by_id(conn, species_id)) - if not bool(species): - flash("Species with given ID was not found.", "alert-danger") - return redirect(url_for("expression-data.samples.select_species")) - species_page = redirect(url_for("expression-data.samples.select_species"), code=307) +@samplesbp.route("<int:species_id>/samples/select-population", methods=["GET"]) +def select_population(species_id: int): + """Select the population to use for the samples.""" with database_connection(app.config["SQL_URI"]) as conn: species = species_by_id(conn, species_id) - pop_name = request.form.get("inbredset_name", "").strip() - pop_fullname = request.form.get("inbredset_fullname", "").strip() - if not bool(species): - flash("Invalid species!", "alert-error error-create-population") - return species_page - if (not bool(pop_name)) or (not bool(pop_fullname)): - flash("You *MUST* provide a grouping/population name", - "alert-error error-create-population") - return species_page - - pop = save_population(conn, { - "SpeciesId": species["SpeciesId"], - "Name": pop_name, - "InbredSetName": pop_fullname, - "FullName": pop_fullname, - "Family": request.form.get("inbredset_family") or None, - "Description": request.form.get("description") or None - }) - - flash("Grouping/Population created successfully.", "alert-success") - return redirect(url_for("samples.upload_samples", - species_id=species_id, - population_id=pop["population_id"])) + flash("Invalid species!", "alert-danger") + return redirect(url_for("species.populations.samples.index")) + + if not bool(request.args.get("population_id")): + return render_template("samples/select-population.html", + species=species, + populations=order_by_family( + populations_by_species( + conn, + species_id), + order_key="FamilyOrder"), + activelink="samples") + + population = population_by_id(conn, request.args.get("population_id")) + if not bool(population): + flash("Population not found!", "alert-danger") + return redirect(url_for( + "species.populations.samples.select_population", + species_id=species_id)) -@samples.route("/upload/species/<int:species_id>/population", - methods=["GET", "POST"]) -@require_login -def select_population(species_id: int): - """Select from existing groupings/populations.""" - if not is_integer_input(species_id): - flash("You did not provide a valid species. Please select one to " - "continue.", - "alert-danger") - return redirect(url_for("expression-data.samples.select_species")) - species = with_db_connection(lambda conn: species_by_id(conn, species_id)) - if not bool(species): - flash("Species with given ID was not found.", "alert-danger") - return redirect(url_for("expression-data.samples.select_species")) + return redirect(url_for("species.populations.samples.list_samples", + species_id=species_id, + population_id=population["Id"])) + +@samplesbp.route("<int:species_id>/populations/<int:population_id>/samples") +def list_samples(species_id: int, population_id: int): + """ + List the samples in a particular population and give the ability to upload + new ones. + """ + with database_connection(app.config["SQL_URI"]) as conn: + species = species_by_id(conn, species_id) + if not bool(species): + flash("Invalid species!", "alert-danger") + return redirect(url_for("species.populations.samples.index")) - if request.method == "GET": - return render_template( - "samples/select-population.html", - species=species, - populations=with_db_connection( - lambda conn: populations_by_species(conn, species_id))) - - population_page = redirect(url_for( - "samples.select_population", species_id=species_id), code=307) - _population_id = request.form.get("inbredset_id") - if not is_integer_input(_population_id): - flash("You did not provide a valid population. Please select one to " - "continue.", - "alert-danger") - return population_page - population = with_db_connection( - lambda conn: population_by_id(conn, _population_id)) - if not bool(population): - flash("Invalid grouping/population!", - "alert-error error-select-population") - return population_page + population = population_by_id(conn, population_id) + if not bool(population): + flash("Population not found!", "alert-danger") + return redirect(url_for( + "species.populations.samples.select_population", + species_id=species_id)) + + all_samples = samples_by_species_and_population( + conn, species_id, population_id) + total_samples = len(all_samples) + offset = int(request.args.get("from") or 0) + if offset < 0: + offset = 0 + count = int(request.args.get("count") or 10) + return render_template("samples/list-samples.html", + species=species, + population=population, + samples=all_samples[offset:offset+count], + offset=offset, + count=count, + total_samples=total_samples, + activelink="list-samples") - return redirect(url_for("samples.upload_samples", - species_id=species_id, - population_id=_population_id), - code=307) def read_samples_file(filepath, separator: str, firstlineheading: bool, **kwargs) -> Iterator[dict]: """Read the samples file.""" @@ -154,6 +136,7 @@ def read_samples_file(filepath, separator: str, firstlineheading: bool, **kwargs for row in reader: yield row + def save_samples_data(conn: mdb.Connection, speciesid: int, file_data: Iterator[dict]): @@ -174,6 +157,7 @@ def save_samples_data(conn: mdb.Connection, total += len(batch) print(f"\tSaved {total} samples total so far.") + def cross_reference_samples(conn: mdb.Connection, species_id: int, population_id: int, @@ -218,6 +202,7 @@ def cross_reference_samples(conn: mdb.Connection, print(f"\t{total} total samples cross-referenced to the population " "so far.") + def build_sample_upload_job(# pylint: disable=[too-many-arguments] speciesid: int, populationid: int, @@ -233,7 +218,8 @@ def build_sample_upload_job(# pylint: disable=[too-many-arguments] f"--quotechar={quotechar}" ] + (["--firstlineheading"] if firstlineheading else []) -@samples.route("/upload/species/<int:species_id>/populations/<int:population_id>/samples", + +@samplesbp.route("/upload/species/<int:species_id>/populations/<int:population_id>/samples", methods=["GET", "POST"]) @require_login def upload_samples(species_id: int, population_id: int):#pylint: disable=[too-many-return-statements] @@ -312,7 +298,7 @@ def upload_samples(species_id: int, population_id: int):#pylint: disable=[too-ma return redirect(url_for( "samples.upload_status", job_id=the_job["jobid"])) -@samples.route("/upload/status/<uuid:job_id>", methods=["GET"]) +@samplesbp.route("/upload/status/<uuid:job_id>", methods=["GET"]) def upload_status(job_id: uuid.UUID): """Check on the status of a samples upload job.""" job = with_redis_connection(lambda rconn: jobs.job( @@ -339,7 +325,7 @@ def upload_status(job_id: uuid.UUID): return render_template("no_such_job.html", job_id=job_id), 400 -@samples.route("/upload/failure/<uuid:job_id>", methods=["GET"]) +@samplesbp.route("/upload/failure/<uuid:job_id>", methods=["GET"]) def upload_failure(job_id: uuid.UUID): """Display the errors of the samples upload failure.""" job = with_redis_connection(lambda rconn: jobs.job( diff --git a/uploader/templates/base.html b/uploader/templates/base.html index 5c7f123..d68c6c0 100644 --- a/uploader/templates/base.html +++ b/uploader/templates/base.html @@ -50,7 +50,7 @@ title="Upload Genotype data.">Genotype Data</a></li> <li><a href="{{url_for('species.populations.index')}}" title="View and manage species populations.">Populations</a></li> - <li><a href="#" + <li><a href="{{url_for('species.populations.samples.index')}}" title="Upload population samples.">Samples</a></li> <li><a href="{{url_for('expression-data.index.index')}}" title="Upload expression data.">Expression Data</a></li> diff --git a/uploader/templates/populations/macro-display-population-card.html b/uploader/templates/populations/macro-display-population-card.html new file mode 100644 index 0000000..e68f8e3 --- /dev/null +++ b/uploader/templates/populations/macro-display-population-card.html @@ -0,0 +1,32 @@ +{%from "species/macro-display-species-card.html" import display_species_card%} + +{%macro display_population_card(species, population)%} +{{display_species_card(species)}} + +<div class="card"> + <div class="card-body"> + <h5 class="card-title">Population</h5> + <div class="card-text"> + <dl> + <dt>Name</dt> + <dd>{{population.Name}}</dd> + + <dt>Full Name</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>Description</dt> + <dd>{{population.Description or "-"}}</dd> + </dl> + </div> + </div> +</div> +{%endmacro%} diff --git a/uploader/templates/populations/macro-select-population.html b/uploader/templates/populations/macro-select-population.html new file mode 100644 index 0000000..af4fd3a --- /dev/null +++ b/uploader/templates/populations/macro-select-population.html @@ -0,0 +1,30 @@ +{%macro select_population_form(form_action, populations)%} +<form method="GET" action="{{form_action}}"> + <legend>Select Population</legend> + + <div class="form-group"> + <label for="select-population" class="form-label">Select Population</label> + <select id="select-population" + name="population_id" + class="form-control" + required="required"> + <option value="">Select Population</option> + {%for family in populations%} + <optgroup {%if family[0][1] is not none%} + label="{{family[0][1]}}" + {%else%} + label="Undefined" + {%endif%}> + {%for population in family[1]%} + <option value="{{population.Id}}">{{population.FullName}}</option> + {%endfor%} + </optgroup> + {%endfor%} + </select> + </div> + + <div class="form-group"> + <input type="submit" value="Select" class="btn btn-primary" /> + </div> +</form> +{%endmacro%} diff --git a/uploader/templates/populations/view-population.html b/uploader/templates/populations/view-population.html index 52dadc4..31db54f 100644 --- a/uploader/templates/populations/view-population.html +++ b/uploader/templates/populations/view-population.html @@ -59,7 +59,11 @@ <nav class="nav"> <ul> <li> - <a href="#" title="Upload samples">upload samples</a> + <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="#" title="Upload expression data">upload expression data</a> diff --git a/uploader/templates/samples/base.html b/uploader/templates/samples/base.html new file mode 100644 index 0000000..291782b --- /dev/null +++ b/uploader/templates/samples/base.html @@ -0,0 +1,12 @@ +{%extends "populations/base.html"%} + +{%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> +</li> +{%block lvl4_breadcrumbs%}{%endblock%} +{%endblock%} diff --git a/uploader/templates/samples/index.html b/uploader/templates/samples/index.html new file mode 100644 index 0000000..7c88c01 --- /dev/null +++ b/uploader/templates/samples/index.html @@ -0,0 +1,21 @@ +{%extends "samples/base.html"%} +{%from "flash_messages.html" import flash_all_messages%} +{%from "species/macro-select-species.html" import select_species_form%} + +{%block title%}Populations{%endblock%} + +{%block pagetitle%}Populations{%endblock%} + + +{%block contents%} +{{flash_all_messages()}} + +<div class="row"> + <p>Here, you can upload the samples/individuals that were used in your + experiments.</p> + <p>Since the samples are linked to specific species and populations, we will + need to first select them in the next few steps.</p> + + {{select_species_form(url_for("species.populations.samples.index"), species)}} +</div> +{%endblock%} diff --git a/uploader/templates/samples/list-samples.html b/uploader/templates/samples/list-samples.html new file mode 100644 index 0000000..a29dc1c --- /dev/null +++ b/uploader/templates/samples/list-samples.html @@ -0,0 +1,114 @@ +{%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 — List Samples{%endblock%} + +{%block pagetitle%}Samples — 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()}} + +<div class="row"> + <p> + Samples for population "{{population.FullName}}" from the + "{{species.FullName}}" species. + </p> + + {%if samples | length > 0%} + <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}} — {{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> + <table class="table"> + <thead> + <tr> + <th>Name</th> + <th>Auxilliary Name</th> + <th>Symbol</th> + <th>Alias</th> + </tr> + </thead> + + <tbody> + {%for sample in samples%} + <tr> + <td>{{sample.Name}}</td> + <td>{{sample.Name2}}</td> + <td>{{sample.Symbol or "-"}}</td> + <td>{{sample.Alias or "-"}}</td> + </tr> + {%endfor%} + </tbody> + </table> + + <p> + <a href="#" + title="Add samples for population '{{population.FullName}}' from species + '{{species.FullName}}'." + class="btn btn-danger"> + delete all samples + </a> + </p> + {%else%} + <p class="text-danger"> + <span class="glyphicon glyphicon-exclamation-sign"></span> + There are no samples for this population at this time. + </p> + + <p> + <a href="#" + title="Add samples for population '{{population.FullName}}' from species + '{{species.FullName}}'." + class="btn btn-primary"> + add samples + </a> + </p> + {%endif%} +</div> +{%endblock%} + +{%block sidebarcontents%} +{{display_population_card(species, population)}} +{%endblock%} + diff --git a/uploader/templates/samples/select-population.html b/uploader/templates/samples/select-population.html index da19ddc..8e22ac1 100644 --- a/uploader/templates/samples/select-population.html +++ b/uploader/templates/samples/select-population.html @@ -1,99 +1,34 @@ -{%extends "base.html"%} -{%from "flash_messages.html" import flash_messages%} +{%extends "samples/base.html"%} +{%from "flash_messages.html" import flash_all_messages%} +{%from "populations/macro-select-population.html" import select_population_form%} +{%from "species/macro-display-species-card.html" import display_species_card%} -{%block title%}Select Grouping/Population{%endblock%} +{%block title%}Samples — Select Population{%endblock%} -{%block contents%} -<h1 class="heading">Select grouping/population</h1> - -<div> - <p>We organise the samples/cases/strains in a hierarchichal form, starting - with <strong>species</strong> at the very top. Under species, we have a - grouping in terms of the relevant population - (e.g. Inbred populations, cell tissue, etc.)</p> -</div> - -<form method="POST" action="{{url_for('samples.select_population', - species_id=species.SpeciesId)}}"> - <legend class="heading">select grouping/population</legend> - {{flash_messages("error-select-population")}} - - <input type="hidden" name="species_id" value="{{species.SpeciesId}}" /> - - <div class="form-group"> - <label for="select:inbredset" class="form-label">grouping/population</label> - <select id="select:inbredset" - name="inbredset_id" - required="required" - class="form-control"> - <option value="">Select a grouping/population</option> - {%for pop in populations%} - <option value="{{pop.InbredSetId}}"> - {{pop.InbredSetName}} ({{pop.FullName}})</option> - {%endfor%} - </select> - </div> - - <button type="submit" class="btn btn-primary">select population</button> -</form> - -<p style="color:#FE3535; padding-left:20em; font-weight:bolder;">OR</p> - -<form method="POST" action="{{url_for('samples.create_population', - species_id=species.SpeciesId)}}"> - <legend class="heading">create new grouping/population</legend> - {{flash_messages("error-create-population")}} +{%block pagetitle%}Samples — Select Population{%endblock%} - <input type="hidden" name="species_id" value="{{species.SpeciesId}}" /> - <div class="form-group"> - <legend>mandatory</legend> - <label for="txt:inbredset-name" class="form-label">name</label> - <input id="txt:inbredset-name" - name="inbredset_name" - type="text" - required="required" - placeholder="Enter grouping/population name" - class="form-control" /> - - <label for="txt:" class="form-label">full name</label> - <input id="txt:inbredset-fullname" - name="inbredset_fullname" - type="text" - required = "required" - placeholder="Enter the grouping/population's full name" - class="form-control" /> - </div> - <div class="form-group"> - <legend>Optional</legend> - - <label for="num:public" class="form-label">public?</label> - <input id="num:public" - name="public" - type="number" - min="0" max="2" value="2" - class="form-control" /> - - <label for="txt:inbredset-family" class="form-label">family</label> - <input id="txt:inbredset-family" - name="inbredset_family" - type="text" - placeholder="I am not sure what this is about." - class="form-control" /> - - <label for="txtarea:" class="form-label">Description</label> - <textarea id="txtarea:description" - name="description" - rows="5" - placeholder="Enter a description of this grouping/population" - class="form-control"></textarea> - </div> - - <button type="submit" class="btn btn-primary">create grouping/population</button> -</form> +{%block contents%} +{{flash_all_messages()}} +<div class="row"> + <p>Select the population to use with your samples:</p> + {{select_population_form( + url_for("species.populations.samples.select_population", species_id=species.SpeciesId), + populations)}} +</div> +<div class="row"> + <p><strong>Cannot find your population in the list?</strong></p> + + <p>If you cannot find the population you want in the drop-down above, you can + instead, + <a href="{{url_for('species.populations.create_population', + species_id=species.SpeciesId)}}" + title="Create a new population for species '{{species.FullName}},"> + create a new population</a>. +</div> {%endblock%} - -{%block javascript%} +{%block sidebarcontents%} +{{display_species_card(species)}} {%endblock%} diff --git a/uploader/templates/samples/select-species.html b/uploader/templates/samples/select-species.html deleted file mode 100644 index aa64ecf..0000000 --- a/uploader/templates/samples/select-species.html +++ /dev/null @@ -1,30 +0,0 @@ -{%extends "base.html"%} -{%from "flash_messages.html" import flash_all_messages%} - -{%block title%}Select Grouping/Population{%endblock%} - -{%block contents%} -<h2 class="heading">upload samples/cases</h2> - -<p>We need to know what species your data belongs to.</p> - -{{flash_all_messages()}} - -<form method="POST" action="{{url_for('expression-data.samples.select_species')}}"> - <legend class="heading">upload samples</legend> - <div class="form-group"> - <label for="select_species02" class="form-label">Species</label> - <select id="select_species02" - name="species_id" - required="required" - class="form-control"> - <option value="">Select species</option> - {%for spec in species%} - <option value="{{spec.SpeciesId}}">{{spec.MenuName}}</option> - {%endfor%} - </select> - </div> - - <button type="submit" class="btn btn-primary">submit</button> -</form> -{%endblock%} diff --git a/uploader/templates/samples/upload-failure.html b/uploader/templates/samples/upload-failure.html deleted file mode 100644 index 09e2ecf..0000000 --- a/uploader/templates/samples/upload-failure.html +++ /dev/null @@ -1,27 +0,0 @@ -{%extends "base.html"%} -{%from "cli-output.html" import cli_output%} - -{%block title%}Samples Upload Failure{%endblock%} - -{%block contents%} -<h1 class="heading">{{job.job_name}}</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.job_id}}</li> - <li><strong>status</strong>: {{job.status}}</li> - <li><strong>job type</strong>: {{job["job-type"]}}</li> -</ul> - -<h4>stdout</h4> -{{cli_output(job, "stdout")}} - -<h4>stderr</h4> -{{cli_output(job, "stderr")}} - -{%endblock%} diff --git a/uploader/templates/samples/upload-progress.html b/uploader/templates/samples/upload-progress.html deleted file mode 100644 index 7bb02be..0000000 --- a/uploader/templates/samples/upload-progress.html +++ /dev/null @@ -1,22 +0,0 @@ -{%extends "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%} -<h1 class="heading">{{job.job_name}}</h2> - -<p> -<strong>status</strong>: -<span>{{job["status"]}} ({{job.get("message", "-")}})</span><br /> -</p> - -<p>saving to database...</p> - -{{cli_output(job, "stdout")}} - -{%endblock%} diff --git a/uploader/templates/samples/upload-samples.html b/uploader/templates/samples/upload-samples.html deleted file mode 100644 index e62de57..0000000 --- a/uploader/templates/samples/upload-samples.html +++ /dev/null @@ -1,139 +0,0 @@ -{%extends "base.html"%} -{%from "flash_messages.html" import flash_messages%} - -{%block title%}Upload Samples{%endblock%} - -{%block css%}{%endblock%} - -{%block contents%} -<h1 class="heading">upload samples</h1> - -{{flash_messages("alert-success")}} - -<p>You can now upload a character-separated value (CSV) file that contains - details about your samples. The CSV file should have the following fields: - <dl> - <dt>Name</dt> - <dd>The primary name for the sample</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. Can be an empty field.</dd> - - <dt>Alias</dt> - <dd>An alias for the sample. Can be an empty field.</dd> - </dl> -</p> - -<form id="form-samples" - method="POST" - action="{{url_for('samples.upload_samples', - species_id=species.SpeciesId, - population_id=population.InbredSetId)}}" - enctype="multipart/form-data"> - <legend class="heading">upload samples</legend> - - <div class="form-group"> - <input type="hidden" name="species_id" value="{{species.SpeciesId}}" /> - <label class="form-label">species:</label> - <span class="form-text">{{species.SpeciesName}} [{{species.MenuName}}]</span> - </div> - - <div class="form-group"> - <input type="hidden" name="inbredset_id" value="{{population.InbredSetId}}" /> - <label class="form-label">grouping/population:</label> - <span class="form-text">{{population.Name}} [{{population.FullName}}]</span> - </div> - - <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" - class="form-control" /> - </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="	">TAB</option> - <option value=" ">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> - -<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 to preview the data.</td> - </tr> - </tbody> -</table> - -{%endblock%} - - -{%block javascript%} -<script src="/static/js/upload_samples.js" type="text/javascript"></script> -{%endblock%} diff --git a/uploader/templates/samples/upload-success.html b/uploader/templates/samples/upload-success.html deleted file mode 100644 index cb745c3..0000000 --- a/uploader/templates/samples/upload-success.html +++ /dev/null @@ -1,18 +0,0 @@ -{%extends "base.html"%} -{%from "cli-output.html" import cli_output%} - -{%block title%}Job Status{%endblock%} - -{%block contents%} -<h1 class="heading">{{job.job_name}}</h2> - -<p> -<strong>status</strong>: -<span>{{job["status"]}} ({{job.get("message", "-")}})</span><br /> -</p> - -<p>Successfully uploaded the samples.</p> - -{{cli_output(job, "stdout")}} - -{%endblock%} |