aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--wqflask/wqflask/oauth2/data.py44
-rw-r--r--wqflask/wqflask/static/new/javascript/auth/search.js29
-rw-r--r--wqflask/wqflask/static/new/javascript/auth/search_phenotypes.js114
-rw-r--r--wqflask/wqflask/templates/oauth2/data-list-phenotype.html160
4 files changed, 177 insertions, 170 deletions
diff --git a/wqflask/wqflask/oauth2/data.py b/wqflask/wqflask/oauth2/data.py
index 2b4dfc75..c3d426cf 100644
--- a/wqflask/wqflask/oauth2/data.py
+++ b/wqflask/wqflask/oauth2/data.py
@@ -1,11 +1,16 @@
"""Handle linking data to groups."""
+import sys
import json
+import uuid
+from datetime import datetime
from urllib.parse import urljoin
+from redis import Redis
from flask import (
flash, request, jsonify, url_for, redirect, Response, Blueprint,
render_template, current_app as app)
+from jobs import jobs
from .request_utils import process_error
from .client import oauth2_get, oauth2_post
@@ -59,24 +64,31 @@ def __search_genotypes__(query, template, **kwargs):
return __render_template__(template, search_uri=search_uri, **datasets, **kwargs)
def __search_phenotypes__(query, template, **kwargs):
+ page = int(request.args.get("page", 1))
per_page = int(request.args.get("per_page", 500))
- species_name = kwargs["species_name"]
- search_uri = (f"search/?type=phenotype&per_page={per_page}&query="
- f"species:{species_name}") + (
- f" AND ({query})" if bool(query) else "")
- traits = oauth2_get(search_uri).either(
- lambda err: {"traits_error": process_error(err)},
- lambda trts: {"traits": tuple({
- "index": idx, **trait
- } for idx, trait in enumerate(trts, start=1))})
-
selected_traits = request.form.getlist("selected_traits")
-
- return __render_template__(
- template, **traits, per_page=per_page, query=query,
- selected_traits=selected_traits,
- search_endpoint=urljoin(app.config["GN_SERVER_URL"], "search/"),
- **kwargs)
+ def __search_error__(error):
+ raise Exception(error)
+ def __search_success__(search_results):
+ job_id = uuid.UUID(search_results["job_id"])
+ return __render_template__(
+ template, traits=[], per_page=per_page, query=query,
+ selected_traits=selected_traits, search_results=search_results,
+ search_endpoint=urljoin(
+ app.config["GN_SERVER_URL"], "oauth2/data/search"),
+ results_endpoint=urljoin(
+ app.config["GN_SERVER_URL"],
+ f"oauth2/data/search/phenotype/{job_id}"),
+ **kwargs)
+ return oauth2_get("oauth2/data/search", json={
+ "dataset_type": "phenotype",
+ "species_name": kwargs["species_name"],
+ "per_page": per_page,
+ "page": page,
+ "gn3_server_uri": app.config["GN_SERVER_URL"]
+ }).either(
+ lambda err: __search_error__(process_error(err)),
+ __search_success__)
@data.route("/genotype/search", methods=["POST"])
def json_search_genotypes() -> Response:
diff --git a/wqflask/wqflask/static/new/javascript/auth/search.js b/wqflask/wqflask/static/new/javascript/auth/search.js
index 5226000d..cd86a9df 100644
--- a/wqflask/wqflask/static/new/javascript/auth/search.js
+++ b/wqflask/wqflask/static/new/javascript/auth/search.js
@@ -134,30 +134,31 @@ function debounce(func, delay=500) {
}
/**
- * Build a checkbox: For internal use only
- * @param {Genotype Dataset object} A genotype dataset object
- * @param {String} A string to initialise the checkbox
+ * Build a checkbox
+ * @param {Dataset Object} A JSON.stringify-able object
+ * @param {String} The name to assign the checkbox
*/
-function __build_checkbox__(dataset, checkbox_str) {
+function build_checkbox(data_object, checkbox_name, checkbox_aux_classes="") {
cell = $("<td>");
- check = $(checkbox_str);
- check.val(JSON.stringify(dataset));
+ check = $(
+ '<input type="checkbox" class="checkbox" ' +
+ 'name="' + checkbox_name + '" checked="checked">');
+ check.val(JSON.stringify(data_object));
+ auxilliary_classes = checkbox_aux_class.trim();
+ if(Boolean(auxilliary_classes)) {
+ check.attr("class",
+ check.attr("class") + " " + auxilliary_classes.trim());
+ }
cell.append(check);
return cell;
}
function link_checkbox(dataset) {
- return __build_checkbox__(
- dataset,
- '<input type="checkbox" class="checkbox checkbox-selected" ' +
- 'name="selected" checked="checked">');
+ return build_checkbox(dataset, "selected", "checkbox-selected");
}
function search_checkbox(dataset) {
- return __build_checkbox__(
- dataset,
- '<input type="checkbox" class="checkbox checkbox-search" ' +
- 'name="search_datasets">');
+ return build_checkbox(dataset, "search_datasets", "checkbox-search");
}
function table_cell(value) {
diff --git a/wqflask/wqflask/static/new/javascript/auth/search_phenotypes.js b/wqflask/wqflask/static/new/javascript/auth/search_phenotypes.js
new file mode 100644
index 00000000..b172ffd1
--- /dev/null
+++ b/wqflask/wqflask/static/new/javascript/auth/search_phenotypes.js
@@ -0,0 +1,114 @@
+/**
+ * Global variables: Bad idea - figure out how to pass them down a call stack.
+ */
+search_table = new TableDataSource(
+ "#tbl-phenotypes", "data-traits",
+ function(trait) {build_checkbox(trait, "search_traits")});
+link_table = new TableDataSource(
+ "#tbl-link-phenotypes", "data-traits",
+ function(trait) {build_checkbox(trait, "selected")});
+
+/**
+ * Toggle the state for the "Link Traits" button
+ */
+function toggle_link_button() {
+ num_groups = $("#frm-link-phenotypes select option").length - 1;
+ num_selected = JSON.parse(
+ $("#tbl-link-phenotypes").attr("data-datasets")).length;
+ if(num_groups > 0 && num_selected > 0) {
+ $("#frm-link-phenotypes input[type='submit']").prop("disabled", false);
+ } else {
+ $("#frm-link-phenotypes input[type='submit']").prop("disabled", true);
+ }
+}
+
+/**
+ * Default error function: print out debug messages
+ */
+function default_error_fn(jqXHR, textStatus, errorThrown) {
+ console.debug("XHR:", jqXHR);
+ console.debug("STATUS:", textStatus);
+ console.debug("ERROR:", errorThrown);
+}
+
+function display_search_results(data, textStatus, jqXHR) {
+ $("#tbl-phenotypes").attr(
+ "data-traits", JSON.stringify(data.search_results));
+ render_table(search_table);
+}
+
+/**
+ * Fetch the search results
+ * @param {UUID}: The job id to fetch data for
+ */
+function fetch_search_results(job_id, success, error=default_error_fn) {
+ endpoint = $("#frm-search-traits").attr("data-search-results-endpoint");
+ $.ajax(
+ endpoint,
+ {
+ "method": "GET",
+ "contentType": "application/json; charset=utf-8",
+ "dataType": "json",
+ "error": error,
+ "success": success
+ }
+ );
+}
+
+function search_phenotypes() {
+ query = document.getElementById("txt-query").value;
+ selected = JSON.parse(document.getElementById(
+ "tbl-link-phenotypes").getAttribute("data-traitss"));
+ species_name = document.getElementById("txt-species-name").value
+ per_page = document.getElementById("txt-per-page").value
+ search_table = new TableDataSource(
+ "#tbl-phenotypes", "data-traits", search_checkbox);
+ $.ajax(
+ "/oauth2/data/search",
+ {
+ "method": "GET",
+ "contentType": "application/json; charset=utf-8",
+ "dataType": "json",
+ "data": JSON.stringify({
+ "query": query,
+ "species_name": species_name,
+ "dataset_type": "phenotype",
+ "per_page": per_page
+ }),
+ "error": default_error_fn,
+ "success": (data, textStatus, jqXHR) => {
+ fetch_search_results(data.job_id);
+ }
+ });
+}
+
+$(document).ready(function() {
+ $("#frm-search-traits").submit(event => {
+ event.preventDefault();
+ return false;
+ });
+
+ $("#txt-query").keyup(debounce(search_phenotypes));
+
+ $("#tbl-phenotypes").on("change", ".checkbox-selected", function(event) {
+ if(this.checked) {
+ select_deselect(JSON.parse(this.value), search_table, link_table);
+ toggle_link_button();
+ }
+ });
+
+ $("#tbl-link-phenotypes").on("change", ".checkbox-search", function(event) {
+ if(!this.checked) {
+ select_deselect(JSON.parse(this.value), search_table, link_table);
+ toggle_link_button();
+ }
+ });
+
+ setTimeout(
+ function() {
+ fetch_search_results(
+ $("#tbl-phenotypes").attr("data-initial-job-id"),
+ display_search_results)
+ },
+ 500);
+});
diff --git a/wqflask/wqflask/templates/oauth2/data-list-phenotype.html b/wqflask/wqflask/templates/oauth2/data-list-phenotype.html
index 53c6ce8c..e6998d28 100644
--- a/wqflask/wqflask/templates/oauth2/data-list-phenotype.html
+++ b/wqflask/wqflask/templates/oauth2/data-list-phenotype.html
@@ -40,7 +40,9 @@
</select>
</div>
- <table id="tbl-link-phenotypes" class="table-hover table-striped cell-border">
+ <table id="tbl-link-phenotypes"
+ class="table-hover table-striped cell-border dataTable no-footer"
+ data-traits="[]">
<tbody>
<tr>
<td colspan="100%" align="center" style="text-align: center;">
@@ -53,12 +55,14 @@
</tr>
</table>
- {%if groups | length > 0%}
- <input type="submit" value="Link Selected" class="btn btn-primary" />
- {%else%}
- <input type="submit" value="No group to link to" class="btn btn-warning"
- disabled="disabled" />
- {%endif%}
+ <div class="form-group text-center">
+ <input type="submit" value="Link Selected"
+ class="btn btn-primary"
+ style="border-top: 0.3em;"
+ {%if groups | length <= 0 or traits | length <= 0%}
+ disabled="disabled"
+ {%endif%} />
+ </div>
</form>
</div>
@@ -66,7 +70,8 @@
<span id="search-messages" class="alert-danger" style="display:none"></span>
<form id="frm-search-traits"
action="#"
- method="POST">
+ method="POST"
+ data-search-results-endpoint="{{results_endpoint}}">
{%if dataset_type == "mrna"%}
<legend>mRNA: Search</legend>
{%else%}
@@ -84,17 +89,19 @@
<div class="form-group">
<label for="txt-query">Search</label>
<div class="input-group">
- <span class="input-group-addon">species:{{species_name}} AND (</span>
+ <span class="input-group-addon">species:{{species_name}} AND </span>
<input type="text" id="txt-query" name="query" class="form-control"
value="{{query}}"/>
- <span class="input-group-addon">)</span>
</div>
</div>
</form>
</div>
<div class="row">
- <table id="tbl-phenotypes" class="table-hover table-striped cell-border">
+ <table id="tbl-phenotypes"
+ class="table-hover table-striped cell-border dataTable no-footer"
+ data-traits="[]"
+ data-initial-job-id={{search_results.job_id}}>
<tbody>
<tr>
<td colspan="100%" align="center">
@@ -110,134 +117,7 @@
{%block js%}
<script language="javascript" type="text/javascript"
- src="/js/DataTables/js/jquery.dataTables.min.js"></script>
-
-<script language="javascript" type="text/javascript"
- src="/js/DataTablesExtensions/plugins/sorting/natural.js"></script>
-
-<script language="javascript" type="text/javascript"
- src="/js/DataTablesExtensions/colReorder/js/dataTables.colReorder.js">
-</script>
-
-<script language="javascript" type="text/javascript"
- src="/js/DataTablesExtensions/colResize/dataTables.colResize.js">
-</script>
-
+ src="/static/new/javascript/auth/search.js"></script>
<script language="javascript" type="text/javascript"
- src="/static/new/javascript/create_datatable.js"></script>
-
-<script language="javascript" type="text/javascript">
- function init_table(table_id, traits) {
- create_table(
- tableId=table_id, tableData=traits,
- columnDefs=[
- {"data": null, "render": function(data) {
- return (
- '<input type="checkbox" ' +
- (table_id == 'tbltbl-phenotypes' ?
- 'name="pheno_traits" ': 'name="selected_traits" ') +
- 'class="checkbox" value="' +
- data.name + ':' + data.dataset +
- '" />');
- }},
- {"title": "Index", "data": "index"},
- {"title": "Dataset", "data": "dataset_fullname"},
- {"title": "Group", "data": "group"},
- {"title": "Record", "data": null, "render": function(data) {
- return (
- '<a target="_blank" href="/show_trait?trait_id=' +
- data.name + '&dataset=' + data.dataset +
- '">' + data.name + "</a>");
- }},
- {"title": "Description", "data": "description"},
- {"title": "Authors", "data": "authors"},
- {"title": "Year", "data": null, render: function(data) {
- return (
- '<a target="_blank" href="' + data.pubmed_link +
- '" >' + data.year + '</a>');
- }},
- {"title": "LRS", "data": null, "render": function(data) {
- return data.lrs ? data.lrs.toFixed(4) : "N/A";
- }},
- {"title": "Peak Location", "data": null, "render": function(data) {
- return 'Chr' + data.geno_chr + ': ' + data.geno_mb;
- }},
- {"title": "Additive Effects", "data": null, "render": function(data) {
- return data.additive ? data.additive.toFixed(4) : "N/A";
- }}],
- customSettings = {
- "scrollY": "40vh",
- "language": {
- "emptyTable": "No traits to display!",
- "info": "Showing _START_ to _END_ of _TOTAL_ entries",
- "infoEmpty": "No entries to show",
- "loadingRecords": "Loading entries ..."
- }
- });
- }
-
- function add_index(item, index) {
- return {"index": index, ...item};
- }
-
- function do_search() {
- /*vent.preventDefault();*/
- user_query = $("#txt-query").val();
- dataset_type = $("#txt-dataset-type").val();
- per_page = $("#txt-per-page").val();
- species = $("#txt-species").val();
- query = "species:" + species;
- if (user_query.length > 2) {
- query = query + " AND (" + user_query + ")";
- }
- $("#search-messages").html("");
- $("#search-messages").attr("style", "display:none;");
- $.ajax(
- "{{search_endpoint}}",
- {
- "method": "GET",
- "data": {
- "type": dataset_type,
- "per_page": per_page,
- "query": query
- },
- "error": function(jqXHR, textStatus, errorThrown) {
- msg_elt = $("#search-messages")
- console.debug(jqXHR)
- $("#search-messages").html(
- "<strong>" + textStatus + "</strong>: Search for '" +
- user_query + "' failed! Try a different search.");
- $("#search-messages").attr("style", "display: block;");
- },
- "success": function (data, textStatus, jqXHR) {
- init_table("tbl-phenotypes", data.map(add_index));
- }
- });
- }
-
- function debounced_search() {
- var timeout;
- return function search(event) {
- clearTimeout(timeout);
- timeout = setTimeout(do_search, 500);
- };
- }
-
- function sanitised_table_data(data) {
- if(data && data.length > 0) {
- return data
- }
- return null
- }
-
- $(document).ready(function() {
- $("#frm-search-traits").submit(function(event) {
- event.preventDefault();
- return false;
- });
- $("#txt-query").keyup(debounced_search())
- init_table("tbl-phenotypes", {{traits | list | tojson}});
- init_table("tbl-link-phenotypes", {{selected_traits | list | tojson}});
- });
-</script>
+ src="/static/new/javascript/auth/search_phenotypes.js"></script>
{%endblock%}