aboutsummaryrefslogtreecommitdiff
path: root/uploader/templates/phenotypes
diff options
context:
space:
mode:
Diffstat (limited to 'uploader/templates/phenotypes')
-rw-r--r--uploader/templates/phenotypes/add-phenotypes-base.html166
-rw-r--r--uploader/templates/phenotypes/add-phenotypes-raw-files.html847
-rw-r--r--uploader/templates/phenotypes/add-phenotypes-with-rqtl2-bundle.html (renamed from uploader/templates/phenotypes/add-phenotypes.html)80
-rw-r--r--uploader/templates/phenotypes/base.html7
-rw-r--r--uploader/templates/phenotypes/bulk-edit-upload.html62
-rw-r--r--uploader/templates/phenotypes/create-dataset.html12
-rw-r--r--uploader/templates/phenotypes/edit-phenotype.html208
-rw-r--r--uploader/templates/phenotypes/index.html15
-rw-r--r--uploader/templates/phenotypes/job-status.html96
-rw-r--r--uploader/templates/phenotypes/list-datasets.html9
-rw-r--r--uploader/templates/phenotypes/load-phenotypes-success.html42
-rw-r--r--uploader/templates/phenotypes/macro-display-preview-table.html19
-rw-r--r--uploader/templates/phenotypes/macro-display-resumable-elements.html60
-rw-r--r--uploader/templates/phenotypes/review-job-data.html125
-rw-r--r--uploader/templates/phenotypes/select-population.html12
-rw-r--r--uploader/templates/phenotypes/view-dataset.html98
-rw-r--r--uploader/templates/phenotypes/view-phenotype.html83
17 files changed, 1800 insertions, 141 deletions
diff --git a/uploader/templates/phenotypes/add-phenotypes-base.html b/uploader/templates/phenotypes/add-phenotypes-base.html
new file mode 100644
index 0000000..9909c20
--- /dev/null
+++ b/uploader/templates/phenotypes/add-phenotypes-base.html
@@ -0,0 +1,166 @@
+{%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%}
+{{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/add-phenotypes-raw-files.html b/uploader/templates/phenotypes/add-phenotypes-raw-files.html
new file mode 100644
index 0000000..67b56e3
--- /dev/null
+++ b/uploader/templates/phenotypes/add-phenotypes-raw-files.html
@@ -0,0 +1,847 @@
+{%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%}
+
+{%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>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 sidebarcontents%}
+{{display_pheno_dataset_card(species, population, dataset)}}
+{%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/add-phenotypes.html b/uploader/templates/phenotypes/add-phenotypes-with-rqtl2-bundle.html
index 196bc69..898fc0c 100644
--- a/uploader/templates/phenotypes/add-phenotypes.html
+++ b/uploader/templates/phenotypes/add-phenotypes-with-rqtl2-bundle.html
@@ -1,4 +1,4 @@
-{%extends "phenotypes/base.html"%}
+{%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%}
@@ -16,52 +16,39 @@
<a href="{{url_for('species.populations.phenotypes.add_phenotypes',
species_id=species.SpeciesId,
population_id=population.Id,
- dataset_id=dataset.Id)}}">View Datasets</a>
+ dataset_id=dataset.Id)}}">Add Phenotypes</a>
</li>
{%endblock%}
-{%block contents%}
-{{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)}}">
- <legend>Add New Phenotypes</legend>
-
- <div class="form-text help-block">
- <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>See the <a href="#section-file-formats">File Formats</a> section below
- to get an understanding of what is expected of the bundle files you
- upload.</p>
- <p><strong>This will not update any existing phenotypes!</strong></p>
- </div>
-
- <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>
+{%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%}
- <div class="form-group">
- <input type="submit"
- value="upload phenotypes"
- class="btn btn-primary" />
- </div>
- </form>
+{%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
@@ -213,17 +200,6 @@
<code>pheno_transposed: True</code>, then the file will be a matrix of
<em>phenotypes × individuals</em>.</p>
</div>
-
-<div class="row text-warning">
- <h3 class="subheading">Notes for Devs (well… Fred, really.)</h3>
- <p>Use the following resources for automated retrieval of certain data</p>
- <ul>
- <li><a href="https://www.ncbi.nlm.nih.gov/pmc/tools/developers/"
- title="NCBI APIs: Retrieve articles' metadata etc.">
- NCBI APIS</a></li>
- </ul>
-</div>
-
{%endblock%}
{%block sidebarcontents%}
diff --git a/uploader/templates/phenotypes/base.html b/uploader/templates/phenotypes/base.html
index 3bc5dea..adbc012 100644
--- a/uploader/templates/phenotypes/base.html
+++ b/uploader/templates/phenotypes/base.html
@@ -6,7 +6,14 @@
{%else%}
class="breadcrumb-item"
{%endif%}>
+ {%if dataset is mapping%}
+ <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%}
</li>
{%block lvl4_breadcrumbs%}{%endblock%}
{%endblock%}
diff --git a/uploader/templates/phenotypes/bulk-edit-upload.html b/uploader/templates/phenotypes/bulk-edit-upload.html
new file mode 100644
index 0000000..d0f38f5
--- /dev/null
+++ b/uploader/templates/phenotypes/bulk-edit-upload.html
@@ -0,0 +1,62 @@
+{%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%}
+
+{%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%}
+<div class="row">
+ <p>Upload the edited file you downloaded and edited.</p>
+</div>
+
+<div class="row">
+ <form id="frm-bulk-edit-upload"
+ class="form-horizontal"
+ method="POST"
+ action="{{url_for(
+ 'species.populations.phenotypes.edit_upload_phenotype_data',
+ species_id=species.SpeciesId,
+ population_id=population.Id,
+ dataset_id=dataset.Id)}}"
+ enctype="multipart/form-data">
+
+ <div class="form-group row">
+ <label for="file-upload-bulk-edit-upload"
+ class="form-label col-form-label col-sm-2">
+ Edited File</label>
+ <div class="col-sm-10">
+ <input id="file-upload-bulk-edit-upload"
+ name="file-upload-bulk-edit-upload"
+ class="form-control"
+ type="file"
+ accept="text/tab-separated-values"
+ required="required" />
+ </div>
+ </div>
+
+ <input type="submit" class="btn btn-primary"
+ value="upload to edit" />
+
+ </form>
+</div>
+{%endblock%}
+
+
+{%block javascript%}
+{%endblock%}
diff --git a/uploader/templates/phenotypes/create-dataset.html b/uploader/templates/phenotypes/create-dataset.html
index 93de92f..19a2b34 100644
--- a/uploader/templates/phenotypes/create-dataset.html
+++ b/uploader/templates/phenotypes/create-dataset.html
@@ -42,7 +42,7 @@
<input type="text"
name="dataset-name"
id="txt-dataset-name"
- value="{{original_formdata.get('dataset-name') or (population.InbredSetCode + 'Publish')}}"
+ value="{{original_formdata.get('dataset-name') or (population.Name + 'Publish')}}"
{%if errors["dataset-name"] is defined%}
class="form-control danger"
{%else%}
@@ -51,7 +51,7 @@
required="required" />
<small class="form-text text-muted">
<p>A short representative name for the dataset.</p>
- <p>Recommended: Use the population code and append "Publish" at the end.
+ <p>Recommended: Use the population name and append "Publish" at the end.
<br />This field will only accept names composed of
letters ('A-Za-z'), numbers (0-9), hyphens and underscores.</p>
</small>
@@ -74,8 +74,10 @@
{%endif%}
required="required" />
<small class="form-text text-muted">
- <p>A longer, descriptive name for the dataset &mdash; useful for humans.
- </p></small>
+ <p>A longer, descriptive name for the dataset. The name is meant for use
+ by humans, and therefore, it should be clear what the dataset contains
+ from the name.</p>
+ </small>
</div>
<div class="form-group">
@@ -84,7 +86,7 @@
name="dataset-shortname"
type="text"
class="form-control"
- value="{{original_formdata.get('dataset-shortname') or (population.InbredSetCode + ' Publish')}}" />
+ value="{{original_formdata.get('dataset-shortname') or (population.Name + 'Publish')}}" />
<small class="form-text text-muted">
<p>An optional, short name for the dataset. <br />
If this is not provided, it will default to the value provided for the
diff --git a/uploader/templates/phenotypes/edit-phenotype.html b/uploader/templates/phenotypes/edit-phenotype.html
new file mode 100644
index 0000000..115d6af
--- /dev/null
+++ b/uploader/templates/phenotypes/edit-phenotype.html
@@ -0,0 +1,208 @@
+{%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=="edit-phenotype"%}
+ class="breadcrumb-item active"
+ {%else%}
+ class="breadcrumb-item"
+ {%endif%}>
+ <a href="{{url_for('species.populations.phenotypes.edit_phenotype_data',
+ species_id=species.SpeciesId,
+ population_id=population.Id,
+ dataset_id=dataset.Id,
+ xref_id=xref_id)}}">View Datasets</a>
+</li>
+{%endblock%}
+
+{%block contents%}
+{{flash_all_messages()}}
+
+<div class="row">
+ <h2 class="heading">edit phenotype data</h2>
+ <p>The forms provided in this page help you update the data for the
+ phenotypes, and the publication information for the phenotype,
+ respectively.</p>
+</div>
+
+<div class="row">
+ <h3 class="subheading">Basic metadata</h3>
+ <form name="frm-phenotype-basic-metadata"
+ class="form-horizontal"
+ method="POST"
+ action="{{url_for(
+ 'species.populations.phenotypes.edit_phenotype_data',
+ species_id=species.SpeciesId,
+ population_id=population.Id,
+ dataset_id=dataset.Id,
+ xref_id=xref_id)}}">
+ <input type="hidden" name="phenotype-id" value="{{phenotype.Id}}" />
+ <div class="form-group">
+ <label for="txt-pre-publication-description"
+ class="control-label col-sm-2">Pre-Publication Description</label>
+ <div class="col-sm-10">
+ <input type="text"
+ id="txt-pre-publication-description"
+ name="pre-publication-description"
+ class="form-control"
+ value="{{phenotype['Pre_publication_description'] or ''}}" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="txt-pre-publication-abbreviation"
+ class="control-label col-sm-2">Pre-Publication Abbreviation</label>
+ <div class="col-sm-10">
+ <input type="text"
+ id="txt-pre-publication-abbreviation"
+ name="pre-publication-abbreviation"
+ class="form-control"
+ value="{{phenotype['Pre_publication_abbreviation'] or ''}}" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="txt-post-publication-description"
+ class="control-label col-sm-2">Post-Publication Description</label>
+ <div class="col-sm-10">
+ <input type="text"
+ id="txt-post-publication-description"
+ name="post-publication-description"
+ class="form-control"
+ value="{{phenotype['Post_publication_description'] or ''}}" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="txt-post-publication-abbreviation"
+ class="control-label col-sm-2">Post-Publication Abbreviation</label>
+ <div class="col-sm-10">
+ <input type="text"
+ id="txt-post-publication-abbreviation"
+ name="post-publication-abbreviation"
+ class="form-control"
+ value="{{phenotype['Post_publication_abbreviation'] or ''}}" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="txt-original-description"
+ class="control-label col-sm-2">Original Description</label>
+ <div class="col-sm-10">
+ <input type="text"
+ id="txt-original-description"
+ name="original-description"
+ class="form-control"
+ value="{{phenotype['Original_description'] or ''}}" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <label for="txt-units"
+ class="control-label col-sm-2">units</label>
+ <div class="col-sm-10">
+ <input type="text"
+ id="txt-units"
+ name="units"
+ class="form-control"
+ required="required"
+ value="{{phenotype['Units']}}" />
+ </div>
+ </div>
+
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <input type="submit"
+ name="submit"
+ class="btn btn-primary"
+ value="update basic metadata">
+ </div>
+ </div>
+ </form>
+</div>
+
+
+<div class="row">
+ <h3 class="subheading">phenotype data</h3>
+ <form id="frm-edit-phenotype-data"
+ class="form-horizontal"
+ method="POST"
+ action="{{url_for(
+ 'species.populations.phenotypes.edit_phenotype_data',
+ species_id=species.SpeciesId,
+ population_id=population.Id,
+ dataset_id=dataset.Id,
+ xref_id=xref_id)}}">
+ <div style="max-height: 23.37em;overflow-y: scroll;">
+ <table class="table table-striped table-responsive table-form-table">
+ <thead style="position: sticky; top: 0;">
+ <tr>
+ <th>#</th>
+ <th>Sample</th>
+ <th>Value</th>
+ {%if population.Family in families_with_se_and_n%}
+ <th>Standard-Error</th>
+ <th>Number of Samples</th>
+ {%endif%}
+ </tr>
+ </thead>
+
+ <tbody>
+ {%for item in phenotype.data%}
+ <tr>
+ <td>{{loop.index}}</td>
+ <td>{{item.StrainName}}</td>
+ <td>
+ <input type="text"
+ name="value-new::{{item.DataId}}::{{item.StrainId}}"
+ value="{{item.value}}"
+ class="form-control" />
+ <input type="hidden"
+ name="value-original::{{item.DataId}}::{{item.StrainId}}"
+ value="{{item.value}}" /></td>
+ {%if population.Family in families_with_se_and_n%}
+ <td>
+ <input type="text"
+ name="se-new::{{item.DataId}}::{{item.StrainId}}"
+ value="{{item.error or ''}}"
+ data-original-value="{{item.error or ''}}"
+ class="form-control" />
+ <input type="hidden"
+ name="se-original::{{item.DataId}}::{{item.StrainId}}"
+ value="{{item.error or ''}}" /></td>
+ <td>
+ <input type="text"
+ name="n-new::{{item.DataId}}::{{item.StrainId}}"
+ value="{{item.count or ''}}"
+ data-original-value="{{item.count or "-"}}"
+ class="form-control" />
+ <input type="hidden"
+ name="n-original::{{item.DataId}}::{{item.StrainId}}"
+ value="{{item.count or ''}}" /></td>
+ {%endif%}
+ </tr>
+ {%endfor%}
+ </tbody>
+ </table>
+ </div>
+ <div class="form-group">
+ <div class="col-sm-offset-2 col-sm-10">
+ <input type="submit"
+ name="submit"
+ class="btn btn-primary"
+ value="update data" />
+ </div>
+ </div>
+ </form>
+</div>
+
+{%endblock%}
+
+{%block sidebarcontents%}
+{{display_population_card(species, population)}}
+{%endblock%}
diff --git a/uploader/templates/phenotypes/index.html b/uploader/templates/phenotypes/index.html
index 0c691e6..689c28e 100644
--- a/uploader/templates/phenotypes/index.html
+++ b/uploader/templates/phenotypes/index.html
@@ -11,16 +11,11 @@
{{flash_all_messages()}}
<div class="row">
- <p>This section deals with phenotypes that
- <span class="text-warning">
- <span class="glyphicon glyphicon-exclamation-sign"></span>
- … what are the characteristics of these phenotypes? …</span></p>
- <p>Select the species to begin the process of viewing/uploading data about
- your phenotypes</p>
+ {{select_species_form(url_for("species.populations.phenotypes.index"), species)}}
</div>
+{%endblock%}
-<div class="row">
- {{select_species_form(url_for("species.populations.phenotypes.index"),
- species)}}
-</div>
+
+{%block javascript%}
+<script type="text/javascript" src="/static/js/species.js"></script>
{%endblock%}
diff --git a/uploader/templates/phenotypes/job-status.html b/uploader/templates/phenotypes/job-status.html
index d531a71..12963c1 100644
--- a/uploader/templates/phenotypes/job-status.html
+++ b/uploader/templates/phenotypes/job-status.html
@@ -30,16 +30,101 @@
{%block contents%}
{%if job%}
+<h4 class="subheading">Progress</h4>
+<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">
- <p><strong>Status:</strong> {{job.status}}</p>
- {%if job.status in ("completed:success", "success")%}
- <p><a href="#"
- class="not-implemented btn btn-primary"
- title="Continue to process data">Continue</a>
+ {%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>
+<h4 class="subheading">Errors</h4>
+<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 | length > 25%}
+ {{error.cellvalue[0:24]}}&hellip;
+ {%else%}
+ {{error.cellvalue}}
+ {%endif%}
+ </td>
+ <td>
+ {%if error.message | length > 250 %}
+ {{error.message[0:249]}}&hellip;
+ {%else%}
+ {{error.message}}
+ {%endif%}
+ </td>
+ </tr>
+ {%endfor%}
+ </tbody>
+ </table>
+ {%endif%}
+</div>
+
<div class="row">
{{cli_output(job, "stdout")}}
</div>
@@ -47,6 +132,7 @@
<div class="row">
{{cli_output(job, "stderr")}}
</div>
+
{%else%}
<div class="row">
<h3 class="text-danger">No Such Job</h3>
diff --git a/uploader/templates/phenotypes/list-datasets.html b/uploader/templates/phenotypes/list-datasets.html
index 2eaf43a..2cf2c7f 100644
--- a/uploader/templates/phenotypes/list-datasets.html
+++ b/uploader/templates/phenotypes/list-datasets.html
@@ -48,9 +48,12 @@
</tbody>
</table>
{%else%}
- <p class="text-warning">
- <span class="glyphicon glyphicon-exclamation-sign"></span>
- There is no dataset for this population!</p>
+ <p>Phenotypes need to go into a dataset. We do not currently have a dataset
+ for species <strong>'{{species["FullName"]}} ({{species["Name"]}})'</strong>
+ phenotypes.</p>
+
+ <p>Do, please, create a new dataset by clicking on the "Create Dataset" button
+ below and following the prompts/instructions.</p>
<p><a href="{{url_for('species.populations.phenotypes.create_dataset',
species_id=species.SpeciesId,
population_id=population.Id)}}"
diff --git a/uploader/templates/phenotypes/load-phenotypes-success.html b/uploader/templates/phenotypes/load-phenotypes-success.html
new file mode 100644
index 0000000..645be16
--- /dev/null
+++ b/uploader/templates/phenotypes/load-phenotypes-success.html
@@ -0,0 +1,42 @@
+{%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%}
+<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 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
new file mode 100644
index 0000000..5a4c422
--- /dev/null
+++ b/uploader/templates/phenotypes/macro-display-preview-table.html
@@ -0,0 +1,19 @@
+{%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>
+{%endmacro%}
diff --git a/uploader/templates/phenotypes/macro-display-resumable-elements.html b/uploader/templates/phenotypes/macro-display-resumable-elements.html
new file mode 100644
index 0000000..ed14ea5
--- /dev/null
+++ b/uploader/templates/phenotypes/macro-display-resumable-elements.html
@@ -0,0 +1,60 @@
+{%macro display_resumable_elements(id, title, help)%}
+<div id="{{id}}"
+ class="resumable-elements visually-hidden"
+ style="background:#D4D4EE;border-radius: 5px;;padding: 1em;border-left: solid #B2B2CC 1px;border-bottom: solid #B2B2CC 2px;margin-top:0.3em;">
+ <strong style="line-height: 1.2em;">{{title | title}}</strong>
+
+ <span class="form-text text-muted">{{help | safe}}</span>
+
+ <div id="{{id}}-selected-files"
+ class="resumable-selected-files"
+ style="display:flex;flex-direction:row;flex-wrap: wrap;justify-content:space-around;gap:10px 20px;">
+ <div class="panel panel-info file-display-template visually-hidden">
+ <div class="panel-heading filename">The Filename Goes Here!</div>
+ <div class="panel-body">
+ <ul>
+ <li>
+ <strong>Name</strong>:
+ <span class="filename">the file's name</span></li>
+
+ <li><strong>Size</strong>: <span class="filesize">0 MB</span></li>
+
+ <li>
+ <strong>Unique Identifier</strong>:
+ <span class="fileuniqueid">brrr</span></li>
+
+ <li>
+ <strong>Mime</strong>:
+ <span class="filemimetype">text/csv</span></li>
+ </ul>
+ </div>
+ </div>
+ </div>
+
+ <a id="{{id}}-browse-button"
+ class="resumable-browse-button btn btn-info"
+ href="#{{id}}"
+ style="margin-left: 80%;">Browse</a>
+
+ <div id="{{id}}-progress-bar" class="progress visually-hidden">
+ <div class="progress-bar"
+ role="progress-bar"
+ aria-valuenow="60"
+ aria-valuemin="0"
+ aria-valuemax="100"
+ style="width: 0%;">
+ Uploading: 60%
+ </div>
+ </div>
+
+ <div id="{{id}}-cancel-resume-buttons">
+ <a id="{{id}}-resume-button"
+ class="resumable-resume-button btn btn-info visually-hidden"
+ href="#">resume upload</a>
+
+ <a id="{{id}}-cancel-button"
+ class="resumable-cancel-button btn btn-danger visually-hidden"
+ href="#">cancel upload</a>
+ </div>
+</div>
+{%endmacro%}
diff --git a/uploader/templates/phenotypes/review-job-data.html b/uploader/templates/phenotypes/review-job-data.html
new file mode 100644
index 0000000..859df74
--- /dev/null
+++ b/uploader/templates/phenotypes/review-job-data.html
@@ -0,0 +1,125 @@
+{%extends "phenotypes/base.html"%}
+{%from "cli-output.html" import cli_output%}
+{%from "flash_messages.html" import flash_all_messages%}
+{%from "macro-table-pagination.html" import table_pagination%}
+{%from "phenotypes/macro-display-pheno-dataset-card.html" import display_pheno_dataset_card%}
+
+{%block extrameta%}
+{%if not job%}
+<meta http-equiv="refresh"
+ content="20; url={{url_for('species.populations.phenotypes.view_dataset', species_id=species.SpeciesId,
+ population_id=population.Id,
+ dataset_id=dataset.Id)}}" />
+{%endif%}
+{%endblock%}
+
+{%block title%}Phenotypes{%endblock%}
+
+{%block pagetitle%}Phenotypes{%endblock%}
+
+{%block lvl4_breadcrumbs%}
+<li {%if activelink=="add-phenotypes"%}
+ class="breadcrumb-item active"
+ {%else%}
+ class="breadcrumb-item"
+ {%endif%}>
+ <a href="{{url_for('species.populations.phenotypes.add_phenotypes',
+ species_id=species.SpeciesId,
+ population_id=population.Id,
+ dataset_id=dataset.Id)}}">View Datasets</a>
+</li>
+{%endblock%}
+
+{%block contents%}
+
+{%if job%}
+<div class="row">
+ <h3 class="heading">Data Review</h3>
+ <p 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 sidebarcontents%}
+{{display_pheno_dataset_card(species, population, dataset)}}
+{%endblock%}
+
+
+{%block javascript%}
+<script type="text/javascript">
+ $(document).ready(function() {
+ var countdown = 20;
+ var countdown_element = $("#countdown-element");
+ if(countdown_element.length === 1) {
+ intv = window.setInterval(function() {
+ countdown = countdown - 1;
+ countdown_element.html(countdown);
+ }, 1000);
+ }
+ });
+</script>
+{%endblock%}
diff --git a/uploader/templates/phenotypes/select-population.html b/uploader/templates/phenotypes/select-population.html
index eafd4a7..48c19b1 100644
--- a/uploader/templates/phenotypes/select-population.html
+++ b/uploader/templates/phenotypes/select-population.html
@@ -11,18 +11,16 @@
{%block contents%}
{{flash_all_messages()}}
-<div class="row">
- <p>Select the population for your phenotypes to view and manage the phenotype
- datasets that relate to it.</p>
-</div>
<div class="row">
- {{select_population_form(url_for("species.populations.phenotypes.select_population",
- species_id=species.SpeciesId),
- populations)}}
+ {{select_population_form(url_for("species.populations.phenotypes.select_population", species_id=species.SpeciesId), species, populations)}}
</div>
{%endblock%}
{%block sidebarcontents%}
{{display_species_card(species)}}
{%endblock%}
+
+{%block javascript%}
+<script type="text/javascript" src="/static/js/populations.js"></script>
+{%endblock%}
diff --git a/uploader/templates/phenotypes/view-dataset.html b/uploader/templates/phenotypes/view-dataset.html
index b136bb6..306dcce 100644
--- a/uploader/templates/phenotypes/view-dataset.html
+++ b/uploader/templates/phenotypes/view-dataset.html
@@ -16,7 +16,7 @@
<a href="{{url_for('species.populations.phenotypes.view_dataset',
species_id=species.SpeciesId,
population_id=population.Id,
- dataset_id=dataset.Id)}}">View Datasets</a>
+ dataset_id=dataset.Id)}}">View</a>
</li>
{%endblock%}
@@ -57,36 +57,26 @@
<div class="row">
<h2>Phenotype Data</h2>
- <p>This dataset has a total of {{phenotype_count}} phenotypes.</p>
+ <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>
- {{table_pagination(start_from, count, phenotype_count, url_for('species.populations.phenotypes.view_dataset', species_id=species.SpeciesId, population_id=population.Id, dataset_id=dataset.Id), "phenotypes")}}
- <table class="table">
+<div class="row">
+
+ <table id="tbl-phenotypes-list" class="table compact stripe cell-border">
<thead>
<tr>
- <th>#</th>
+ <th></th>
+ <th>Index</th>
<th>Record</th>
<th>Description</th>
</tr>
</thead>
- <tbody>
- {%for pheno in phenotypes%}
- <tr>
- <td>{{pheno.sequence_number}}</td>
- <td><a href="{{url_for('species.populations.phenotypes.view_phenotype',
- species_id=species.SpeciesId,
- population_id=population.Id,
- dataset_id=dataset.Id,
- xref_id=pheno['pxr.Id'])}}"
- title="View phenotype details">
- {{pheno.InbredSetCode}}_{{pheno["pxr.Id"]}}</a></td>
- <td>{{pheno.Post_publication_description or pheno.Pre_publication_abbreviation or pheno.Original_description}}</td>
- </tr>
- {%else%}
- <tr><td colspan="5"></td></tr>
- {%endfor%}
- </tbody>
+ <tbody></tbody>
</table>
</div>
{%endblock%}
@@ -94,3 +84,67 @@
{%block sidebarcontents%}
{{display_population_card(species, population)}}
{%endblock%}
+
+
+{%block javascript%}
+<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}};
+ return `<a href="/species/${spcs_id}` +
+ `/populations/${pop_id}` +
+ `/phenotypes/datasets/${dtst_id}` +
+ `/phenotype/${pheno.xref_id}` +
+ `" 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}`;
+ }
+ });
+ });
+</script>
+{%endblock%}
diff --git a/uploader/templates/phenotypes/view-phenotype.html b/uploader/templates/phenotypes/view-phenotype.html
index 99bb8e5..21ac501 100644
--- a/uploader/templates/phenotypes/view-phenotype.html
+++ b/uploader/templates/phenotypes/view-phenotype.html
@@ -16,7 +16,7 @@
species_id=species.SpeciesId,
population_id=population.Id,
dataset_id=dataset.Id,
- xref_id=xref_id)}}">View Datasets</a>
+ xref_id=xref_id)}}">View Phenotype</a>
</li>
{%endblock%}
@@ -34,51 +34,58 @@
<td>{{phenotype.Post_publication_description or phenotype.Pre_publication_abbreviation or phenotype.Original_description}}
</tr>
<tr>
- <td><strong>Cross-Reference ID</strong></td>
- <td>{{phenotype.xref_id}}</td>
- </tr>
- <tr>
- <td><strong>Collation</strong></td>
+ <td><strong>Database</strong></td>
<td>{{dataset.FullName}}</td>
</tr>
<tr>
<td><strong>Units</strong></td>
<td>{{phenotype.Units}}</td>
</tr>
+ {%for key,value in publish_data.items()%}
+ <tr>
+ <td><strong>{{key}}</strong></td>
+ <td>{{value}}</td>
+ </tr>
+ {%else%}
+ <tr>
+ <td colspan="2" class="text-muted">
+ <span class="glyphicon glyphicon-exclamation-sign"></span>
+ No publication data found.
+ </td>
+ </tr>
+ {%endfor%}
</tbody>
</table>
+ </div>
+</div>
- <form action="#edit-delete-phenotype"
- method="POST"
- id="frm-delete-phenotype">
-
- <input type="hidden" name="species_id" value="{{species.SpeciesId}}" />
- <input type="hidden" name="population_id" value="{{population.Id}}" />
- <input type="hidden" name="dataset_id" value="{{dataset.Id}}" />
- <input type="hidden" name="phenotype_id" value="{{phenotype.Id}}" />
-
- <div class="btn-group btn-group-justified">
- <div class="btn-group">
- {%if "group:resource:edit-resource" in privileges%}
- <input type="submit"
- title="Edit the values for the phenotype. This is meant to be used when you need to update only a few values."
- class="btn btn-primary not-implemented"
- value="edit" />
- {%endif%}
- </div>
- <div class="btn-group"></div>
- <div class="btn-group">
- {%if "group:resource:delete-resource" in privileges%}
- <input type="submit"
- title="Delete the entire phenotype. This is useful when you need to change data for most or all of the fields for this phenotype."
- class="btn btn-danger not-implemented"
- value="delete" />
- {%endif%}
- </div>
- </div>
- </form>
+{%if "group:resource:edit-resource" in privileges
+or "group:resource:delete-resource" in privileges%}
+<div class="row">
+ <div class="btn-group btn-group-justified">
+ <div class="btn-group">
+ {%if "group:resource:edit-resource" in privileges%}
+ <a href="{{url_for('species.populations.phenotypes.edit_phenotype_data',
+ species_id=species.SpeciesId,
+ population_id=population.Id,
+ dataset_id=dataset.Id,
+ xref_id=xref_id)}}"
+ title="Edit the values for the phenotype. This is meant to be used when you need to update only a few values."
+ class="btn btn-primary">Edit</a>
+ {%endif%}
+ </div>
+ <div class="btn-group"></div>
+ <div class="btn-group">
+ {%if "group:resource:delete-resource" in privileges%}
+ <a href="#"
+ title="Delete the entire phenotype. This is useful when you need to change data for most or all of the fields for this phenotype."
+ class="btn btn-danger not-implemented"
+ disabled="disabled">delete</a>
+ {%endif%}
+ </div>
</div>
</div>
+{%endif%}
<div class="row">
<div class="panel panel-default">
@@ -90,9 +97,10 @@
<th>#</th>
<th>Sample</th>
<th>Value</th>
- <th>Symbol</th>
+ {%if has_se%}
<th>SE</th>
<th>N</th>
+ {%endif%}
</tr>
</thead>
@@ -102,9 +110,10 @@
<td>{{loop.index}}</td>
<td>{{item.StrainName}}</td>
<td>{{item.value}}</td>
- <td>{{item.Symbol or "-"}}</td>
+ {%if has_se%}
<td>{{item.error or "-"}}</td>
<td>{{item.count or "-"}}</td>
+ {%endif%}
</tr>
{%endfor%}
</tbody>