about summary refs log tree commit diff
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%}