From c21016add8fb6b66e4413f8cacba256d4dbf2404 Mon Sep 17 00:00:00 2001 From: Frederick Muriuki Muriithi Date: Mon, 17 Apr 2023 14:18:56 +0300 Subject: oauth2: Build code to do search At this point, the code fails with a 404, despite the appropriate endpoint existing. Will need further debugging. --- wqflask/wqflask/oauth2/data.py | 44 +++--- .../wqflask/static/new/javascript/auth/search.js | 29 ++-- .../new/javascript/auth/search_phenotypes.js | 114 +++++++++++++++ .../templates/oauth2/data-list-phenotype.html | 160 +++------------------ 4 files changed, 177 insertions(+), 170 deletions(-) create mode 100644 wqflask/wqflask/static/new/javascript/auth/search_phenotypes.js 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 = $(""); - check = $(checkbox_str); - check.val(JSON.stringify(dataset)); + check = $( + ''); + 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, - ''); + return build_checkbox(dataset, "selected", "checkbox-selected"); } function search_checkbox(dataset) { - return __build_checkbox__( - dataset, - ''); + 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 @@ - + - {%if groups | length > 0%} - - {%else%} - - {%endif%} +
+ +
@@ -66,7 +70,8 @@
+ method="POST" + data-search-results-endpoint="{{results_endpoint}}"> {%if dataset_type == "mrna"%} mRNA: Search {%else%} @@ -84,17 +89,19 @@
- species:{{species_name}} AND ( + species:{{species_name}} AND - )
- +