diff options
-rw-r--r-- | wqflask/wqflask/oauth2/data.py | 98 | ||||
-rw-r--r-- | wqflask/wqflask/templates/oauth2/data-list-phenotype.html | 124 | ||||
-rw-r--r-- | wqflask/wqflask/templates/oauth2/data-list.html | 188 |
3 files changed, 215 insertions, 195 deletions
diff --git a/wqflask/wqflask/oauth2/data.py b/wqflask/wqflask/oauth2/data.py index 0cd110f6..432ca3b9 100644 --- a/wqflask/wqflask/oauth2/data.py +++ b/wqflask/wqflask/oauth2/data.py @@ -7,6 +7,39 @@ from .client import oauth2_get, oauth2_post data = Blueprint("data", __name__) +def __render_template__(templatepath, **kwargs): + roles = kwargs.get("roles", tuple()) + user_privileges = tuple( + privilege["privilege_id"] for role in roles + for privilege in role["privileges"]) + return render_template( + templatepath, **kwargs, user_privileges=user_privileges) + +@data.route("/<string:species_name>/<string:dataset_type>/list", + methods=["GET", "POST"]) +def list_data_by_species_and_dataset( + species_name: str, dataset_type: str) -> Response: + templates = { + "mrna": "oauth2/data-list-mrna.html", + "genotype": "oauth2/data-list-genotype.html", + "phenotype": "oauth2/data-list-phenotype.html"} + roles = oauth2_get("oauth2/user/roles").either( + lambda err: {"roles_error": process_error(err)}, + lambda roles: {"roles": roles}) + per_page = int(request.args.get("per_page", 500)) + traits = oauth2_get( + (f"search/?type={dataset_type}&per_page={per_page}&query=" + f"species:{species_name}")).either( + lambda err: {"traits_error": process_error(er)}, + lambda trts: {"traits": tuple({ + "index": idx, **trait + } for idx, trait in enumerate(trts, start=1))}) + + return __render_template__( + templates[dataset_type], **roles, **traits, species_name=species_name, + dataset_type=dataset_type, per_page=per_page, + query=request.args.get("query", "")) + @data.route("/list", methods=["GET", "POST"]) def list_data(): """List ungrouped data.""" @@ -23,65 +56,29 @@ def list_data(): **{key:val for key,val in kwargs.items() if key not in ("groups", "data_items", "user_privileges")}) - def __process_menus__(mns): - return { - species_id: { - "display_name": display_name, - "family": family, - "groups": { - group_id: { - "group_name": group_name, - "family": family, - "types": { - type_id: { - "menu_value": type_menu_value, - "menu_heading": type_menu_heading, - "datasets": tuple( - dict(zip(("accession_id", "dataset_id", - "dataset_fullname"), - dataset_row)) - for dataset_row in mns["datasets"][ - species_id][group_id][type_id]) - } - for type_id, type_menu_value, type_menu_heading - in mns["types"][species_id][group_id] - } - } - for group_id, group_name, family in mns["groups"][species_id] - } - } - for species_id, display_name, family in mns["species"]} - groups = oauth2_get("oauth2/group/list").either( lambda err: {"groups_error": process_error(err)}, lambda grp: {"groups": grp}) roles = oauth2_get("oauth2/user/roles").either( lambda err: {"roles_error": process_error(err)}, lambda roles: {"roles": roles}) - menus = oauth2_get("menu/generate/json").either( - lambda err: {"menus_error": process_error(err)}, - lambda mns: {"menus": __process_menus__(mns)}) + species = oauth2_get("oauth2/data/species").either( + lambda err: {"species_error": process_error(err)}, + lambda species: {"species": species}) if request.method == "GET": - return __render__(**{**groups, **roles, **menus}) + return __render__(**{**groups, **roles, **species}) + species_name = request.form["species_name"] dataset_type = request.form["dataset_type"] - offset = int(request.form.get("offset", 0)) + ( - 0 if request.form.get("offset_submit") is None else( - 100 if request.form["offset_submit"] == "Next" else -100)) if dataset_type not in ("mrna", "genotype", "phenotype"): flash("InvalidDatasetType: An invalid dataset type was provided", "alert-danger") - return __render__(**{**groups, **roles}) + return __render__(**{**groups, **roles, **species}) - data_items = oauth2_get( - f"oauth2/group/{dataset_type}/ungrouped-data?offset={offset}").either( - lambda err: {"data_items_error": process_error(err)}, - lambda data: {"data_items": data}) - return __render__(**{ - **groups, **roles, **menus, **data_items, "dataset_type": dataset_type, - "offset": offset - }) + return redirect(url_for( + "oauth2.data.list_data_by_species_and_dataset", + species_name=species_name, dataset_type=dataset_type)) @data.route("/link", methods=["POST"]) def link_data(): @@ -96,20 +93,25 @@ def link_data(): form = request.form try: - keys = ("dataset_id", "dataset_type", "group_id") + keys = ("dataset_type", "group_id") assert all(item in form for item in keys) assert all(bool(form[item]) for item in keys) state_data = { "dataset_type": form["dataset_type"], "offset": form.get("offset", 0)} + dataset_ids = form.getlist("dataset_ids") + if len(dataset_ids) == 0: + flash("You must select at least one item to link", "alert-danger") + return redirect(url_for( + "oauth2.data.list_data", **state_data)) return oauth2_post( "oauth2/group/data/link", data={ "dataset_type": form["dataset_type"], - "dataset_id": form["dataset_id"], + "dataset_ids": dataset_ids, "group_id": form["group_id"] }).either(lambda err: __error__(err, state_data), lambda success: __success__(success, state_data)) except AssertionError as aserr: - flash("You must provide all the expected data.", "alert-error") + flash("You must provide all the expected data.", "alert-danger") return redirect(url_for("oauth2.data.list_data")) diff --git a/wqflask/wqflask/templates/oauth2/data-list-phenotype.html b/wqflask/wqflask/templates/oauth2/data-list-phenotype.html new file mode 100644 index 00000000..3c58f275 --- /dev/null +++ b/wqflask/wqflask/templates/oauth2/data-list-phenotype.html @@ -0,0 +1,124 @@ +{%extends "base.html"%} +{%from "oauth2/profile_nav.html" import profile_nav%} +{%from "oauth2/display_error.html" import display_error%} + +{%block title%}View User{%endblock%} + +{%block css%} +<link rel="stylesheet" type="text/css" + href="/css/DataTables/css/jquery.dataTables.css" /> +<link rel="stylesheet" type="text/css" + href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" /> +<link rel="stylesheet" type="text/css" href="/static/new/css/show_trait.css" /> +{%endblock%} + +{%block content%} + +<div class="container" style="min-width: 1250px;"> + {{profile_nav("data", user_privileges)}} + + {{flash_me()}} + + <div class="row"> + <noscript>This page needs javascript to work correctly</noscript> + </div> + + <div class="row"> + <form id="frm-select-datatype" + action="#" + method="POST"> + {%if dataset_type == "mrna"%} + <legend>mRNA: Search</legend> + {%else%} + <legend style="text-transform: capitalize;"> + {{dataset_type}}: Search + </legend> + {%endif%} + <input type="hidden" value="{{species_name}}" name="species" /> + <input type="hidden" value="{{dataset_type}}" name="dataset_type" /> + <input type="hidden" value="{{per_page}}" name="per_page" /> + + <div class="form-group"> + <label for="txt-query">Search</label> + <div class="input-group"> + <span class="input-group-addon">species:{{species_name}}</span> + <input type="text" id="txt-query" name="query" class="form-control" + value="{{query}}"/> + </div> + </div> + </form> + </div> + + <div class="row"> + <table id="tbl-phenotypes" class="table-hover table-striped cell-border"> + <tbody> + <tr> + <td colspan="100%" align="center"> + <br><b><font size="15">Loading...</font></b><br> + </td> + </tr> + </table> + </div> + +</div> + +{%endblock%} + +{%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> + +<script language="javascript" type="text/javascript" + src="/static/new/javascript/create_datatable.js"></script> + +<script language="javascript" type="text/javascript"> + var traits = {{traits | list | tojson}}; + create_table( + tableId="tbl-phenotypes", tableData=traits, + columnDefs=[ + {"data": null, "render": function(data) { + return ( + '<input type="checkbox" name="pheno_traits" ' + + 'class="checkbox" value="' + + data.dataset + '::' + data.name + + '" />'); + }}, + {"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) { + console.debug(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"; + }}]); +</script> +{%endblock%} diff --git a/wqflask/wqflask/templates/oauth2/data-list.html b/wqflask/wqflask/templates/oauth2/data-list.html index 019e2346..4e0cf5ae 100644 --- a/wqflask/wqflask/templates/oauth2/data-list.html +++ b/wqflask/wqflask/templates/oauth2/data-list.html @@ -3,156 +3,50 @@ {%from "oauth2/display_error.html" import display_error%} {%block title%}View User{%endblock%} {%block content%} - <div class="container" style="min-width: 1250px;"> - {{profile_nav("data", user_privileges)}} - - {{flash_me()}} - - <div class="container-fluid"> - <div class="row"> - <form method="POST" action="{{url_for('oauth2.data.list_data')}}"> - <legend>Dataset Type</legend> - <input type="hidden" name="offset" value="0" /> - <input type="hidden" name="menus" value="{{menus | tojson}}" /> - <div class="form-group"> - <label for="select-menu">Dataset</label> - <select id="select-menu" name="dataset"> - {%for species_id, species_data in menus.items()%} - <optgroup label="{{species_data.display_name}}"> - {%for group_id, group_data in species_data["groups"].items()%} - <optgroup label=" {{group_data.group_name}}"> - {%for type_id, type_data in group_data["types"].items()%} - <optgroup label="{{type_data.menu_heading}}"> - {%for dataset in type_data["datasets"]%} - <option value="{{dataset.dataset_id}}"> - {{dataset.dataset_fullname}} - </option> - {%endfor%} - </optgroup> - {%endfor%} - </optgroup> - {%endfor%} - </optgroup> - {%endfor%} - </select> - </div> - <div class="form-group"> - <label for="dataset_type" class="form-label">Dataset Type</label> - <select name="dataset_type" required="required"> - <option value="">Select dataset type</option> - <option value="mrna" - {%if dataset_type=="mrna"%} - selected="selected" - {%endif%}>mRNA Assay Datasets</option> - <option value="genotype" - {%if dataset_type=="genotype"%} - selected="selected" - {%endif%}>Genotype Datasets</option> - <option value="phenotype" - {%if dataset_type=="phenotype"%} - selected="selected" - {%endif%}>Phenotype/Publish Datasets</option> - </select> - </div> - <input type="submit" value="Fetch Unlinked Data" class="btn btn-primary" /> - </form> +<div class="container" style="min-width: 1250px;"> + {{profile_nav("data", user_privileges)}} + + {{flash_me()}} + + <div class="row"> + <form id="frm-select-datatype" + action="{{url_for('oauth2.data.list_data')}}" + method="POST"> + <legend>Search</legend> + {%if species_error is defined%} + {{display_error("Species", species_error)}} + {%elif species | length == 0%} + <span class="glyphicon glyphicon-info-sign text-danger"> + </span> + + <strong class="text-danger">No list of species to select from</strong> + {%else%} + <div class="form-group"> + <label for="select-species">Species</label> + <select id="select-species" name="species_name" required="required"> + <option value="">Select Species</option> + {%for spc in species%} + <option value="{{spc.Name}}"> + {{spc.MenuName}} ({{spc.FullName}}) + </option> + {%endfor%} + </select> </div> - {%if dataset_type is defined%} - {%if data_items_error is defined%} - {{display_error("Data Error", data_items_error)}} - {%else%} - <div class="row"> - <form method="POST" action="{{url_for('oauth2.data.link_data')}}"> - <legend>Link Data to Group</legend> - <input type="hidden" name="offset" value="{{offset or 0}}" /> - <input type="hidden" name="dataset_type" value="{{dataset_type}}" /> - - <div class="form-group"> - <label for="select-group-id">Group</label> - <select name="group_id" required="required"> - <option value="">Select group</option> - {%for group in groups%} - <option value="{{group.group_id}}">{{group.group_name}}</option> - {%endfor%} - </select> - </div> - - <table class="table"> - <caption>Link Data to Group</caption> - - <thead> - <tr> - <th>Select</th> - {%if dataset_type == "phenotype"%} - <th>Trait ID</th> - <th>Data Group</th> - {%endif%} - <th>Dataset Name</th> - <th>Dataset Full Name</th> - <th>Link</th> - </tr> - </thead> - - <tbody> - {%for data_item in data_items%} - <tr> - <td> - <input type="checkbox" value="{{data_item.Id}}" - name="dataset_ids" /> - </td> - {%if dataset_type == "phenotype"%} - <td> - <a href="/show_trait?trait_id={{data_item.Id}}&dataset={{data_item.dataset_name}}" - title="Trait Page"> - {{data_item.Id}} - </a> - </td> - <td>{{data_item.InbredSetName}}</td> - {%endif%} - <td> - <a href="https://gn1.genenetwork.org/webqtl/main.py?FormID=sharinginfo&GN_AccessionId={{data_item.accession_id}}&InfoPageName={{data_item.dataset_name}}" - title="Link to information on dataset '{{data_item.dataset_fullname}}'" - target="_blank"> - {{data_item.dataset_name}} - </a> - </td> - <td>{{data_item.dataset_fullname}}</td> - <td> - <input type="submit" value="Link" class="btn btn-info" /> - </td> - </tr> - {%else%} - <tr> - <td colspan="4"> - <span class="glyphicon glyphicon-info-sign text-danger"> - </span> - - <strong class="text-info">No available data to link</strong> - </td> - </tr> - {%endfor%} - </tbody> - </table> - </form> - - <form method="POST" action="{{url_for('oauth2.data.list_data')}}"> - <input type="hidden" name="dataset_type" value="{{dataset_type}}" /> - <input type="hidden" name="offset" value="{{offset or 0}}" /> - <div class="form-group" style="margin: auto;width: 50%;"> - {%if offset != 0%} - <input type="submit" name="offset_submit" value="Previous" class="btn btn-warning" /> - {%endif%} - {%if data_items | length == 100:%} - <input type="submit" name="offset_submit" value="Next" class="btn btn-warning" /> - {%endif%} - </div> - </form> + <div class="form-group"> + <label for="select-dataset-type">Dataset/Trait Type</label> + <select id="select-dataset-type" name="dataset_type" + required="required"> + <option value="">Select dataset type</option> + <option value="mrna">mRNA Assay (ProbeSet) Dataset</option> + <option value="genotype">Genotype Dataset</option> + <option value="phenotype">Phenotype (Publish) Dataset</option> + </select> </div> - {%endif%} - {%endif%} - - </div> + <input type="submit" class="btn btn-primary" value="Search" /> + {%endif%} + </form> </div> +</div> {%endblock%} |