-
Notifications
You must be signed in to change notification settings - Fork 80
DataTables load using AJAX, Search by metadata on studies page #1006
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
616300f
d595016
90313f7
fb5eef3
1ffd4bc
16257c4
9ccc098
abeb46f
259bec2
b8472a8
cf6ca77
cd4f66e
ce4d334
58b28cd
1872555
4b7ffcf
515f0f6
21b17d6
04f87f4
ee4c9e2
ef16d18
fbe7c74
e0f22d0
0df6666
5085c35
ea69fe8
3a12f87
25ae8f2
e01e224
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,7 @@ | |
from qiita_core.exceptions import IncompetentQiitaDeveloperError | ||
from qiita_db.user import User | ||
from qiita_db.study import Study, StudyPerson | ||
from qiita_db.search import QiitaStudySearch | ||
from qiita_pet.handlers.base_handlers import BaseHandler | ||
from qiita_pet.handlers.util import study_person_linkifier, pubmed_linkifier | ||
|
||
|
@@ -35,15 +36,24 @@ def _get_shared_links_for_study(study): | |
return ", ".join(shared) | ||
|
||
|
||
def _build_study_info(studytype, user=None): | ||
def _build_study_info(studytype, user, studies=None): | ||
"""builds list of namedtuples for study listings""" | ||
if studytype == "standard": | ||
if studytype not in {"standard", "shared"}: | ||
raise IncompetentQiitaDeveloperError("Must use private, shared, " | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The error message doesn't seem to correspond to the conditional? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. woops, forgot to update. fixed. |
||
"or public!") | ||
# get list of studies for table | ||
if studies: | ||
# filter info to given studies | ||
if studytype == "standard": | ||
studylist = (user.user_studies | | ||
Study.get_by_status('public')).intersection(studies) | ||
elif studytype == "shared": | ||
studylist = user.shared_studies.intersection(studies) | ||
elif studytype == "standard": | ||
studylist = user.user_studies | Study.get_by_status('public') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. if possible, it would be nice to stick with either operators (this line), or methods (line 53), to improve consistency within the method being worked on. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. will stick with methods, since they are more universal. |
||
elif studytype == "shared": | ||
studylist = user.shared_studies | ||
else: | ||
raise IncompetentQiitaDeveloperError("Must use private, shared, " | ||
"or public!") | ||
|
||
if not studylist: | ||
return [] | ||
|
||
|
@@ -85,22 +95,10 @@ class ListStudiesHandler(BaseHandler): | |
def get(self): | ||
self.write(self.render_string('waiting.html')) | ||
self.flush() | ||
user = self.current_user | ||
user_studies = yield Task(self._get_standard, user) | ||
shared_studies = yield Task(self._get_shared, user) | ||
all_emails_except_current = yield Task(self._get_all_emails) | ||
all_emails_except_current.remove(self.current_user.id) | ||
self.render('list_studies.html', | ||
user_studies=user_studies, shared_studies=shared_studies, | ||
all_emails_except_current=all_emails_except_current, | ||
query='') | ||
|
||
def _get_standard(self, user, callback): | ||
callback(_build_study_info("standard", user)) | ||
|
||
def _get_shared(self, user, callback): | ||
"""builds list of tuples for studies that are shared with user""" | ||
callback(_build_study_info("shared", user)) | ||
all_emails_except_current=all_emails_except_current) | ||
|
||
def _get_all_emails(self, callback): | ||
callback(list(User.iter())) | ||
|
@@ -154,3 +152,102 @@ def get(self): | |
users, links = yield Task(self._get_shared_for_study, study) | ||
|
||
self.write(dumps({'users': users, 'links': links})) | ||
|
||
|
||
class SearchStudiesAJAX(BaseHandler): | ||
def _get_standard(self, user, callback): | ||
callback(_build_study_info("standard", user)) | ||
|
||
def _get_shared(self, user, callback): | ||
"""builds list of tuples for studies that are shared with user""" | ||
callback(_build_study_info("shared", user)) | ||
|
||
@authenticated | ||
def get(self, ignore): | ||
search_type = self.get_argument('type') | ||
user = self.get_argument('user') | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why are you passing the user as an argument? It doesn't look like is needed as... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. line 211 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's what I'm saying... it's not needed, just use self.current_user... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's to prevent URL hacking |
||
query = self.get_argument('query') | ||
echo = int(self.get_argument('sEcho')) | ||
|
||
res = None | ||
if query != "": | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
# Search for samples matching the query | ||
search = QiitaStudySearch() | ||
res, meta = search(query) | ||
info = _build_study_info(search_type, self.current_user, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this call only needs to be done once and can be done outside of the conditions if |
||
studies=search.keys()) | ||
else: | ||
# show everything | ||
info = _build_study_info(search_type, self.current_user) | ||
|
||
# build the table json | ||
results = { | ||
"sEcho": echo, | ||
"iTotalRecords": len(info), | ||
"iTotalDisplayRecords": len(info), | ||
"aaData": [] | ||
} | ||
if search_type == "standard": | ||
for row, s in enumerate(info): | ||
# build the HTML elements needed for table cell | ||
meta_complete = "ok" if s.meta_complete else "remove" | ||
share = "Not Available" if s.status == 'public' else \ | ||
("<span id='shared_html_{0}'>{1}</span><br/>" | ||
"<a class='btn btn-primary' data-toggle='modal' " | ||
"data-target='#share-study-modal-view' " | ||
"onclick='modify_sharing({0});'>Modify</a>".format( | ||
s.id, s.shared)) | ||
# add study to table | ||
results['aaData'].append([ | ||
"<input type='checkbox' value='%s'>" % s.id, | ||
|
||
"<a href='#'' data-toggle='modal' " | ||
"data-target='#study-abstract-modal' " | ||
"onclick='fillAbstract(\"user-studies-table\", {0})'>" | ||
"<span class=\'glyphicon glyphicon-file\' " | ||
"aria-hidden=\'true\'></span></a> | " | ||
"<a href=\'/study/description/{1}\' " | ||
"id=\'study{0}-title\'>{2}</a>".format( | ||
str(row), str(s.id), s.title), | ||
|
||
s.abstract, | ||
s.id, | ||
"<span class='glyphicon glyphicon-%s'></span>" % | ||
meta_complete, | ||
s.num_samples_collected, | ||
s.num_raw_data, | ||
share, | ||
s.pi, | ||
s.pmids, | ||
s.status | ||
]) | ||
elif search_type == "shared": | ||
for row, s in enumerate(info): | ||
# build the HTML elements needed for table cell | ||
meta_complete = "ok" if s.meta_complete else "remove" | ||
# add study to table | ||
results['aaData'].append([ | ||
"<input type='checkbox' value='%s'>" % s.id, | ||
|
||
"<a href='#'' data-toggle='modal' " | ||
"data-target='#study-abstract-modal' " | ||
"onclick='fillAbstract(\"shared-studies-table\", {0})'>" | ||
"<span class=\'glyphicon glyphicon-file\' " | ||
"aria-hidden=\'true\'></span></a> | " | ||
"<a href=\'/study/description/{1}\' " | ||
"id=\'study{0}-title\'>{2}</a>".format( | ||
str(row), str(s.id), s.title), | ||
|
||
s.abstract, | ||
s.id, | ||
s.owner, | ||
"<span class='glyphicon glyphicon-%s'></span>" % | ||
meta_complete, | ||
s.num_samples_collected, | ||
s.num_raw_data, | ||
s.pi, | ||
s.pmids | ||
]) | ||
|
||
# return the json | ||
self.write(dumps(results)) |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,20 +7,29 @@ | |
|
||
<script type="text/javascript"> | ||
var current_study; | ||
|
||
var query = ""; | ||
$(document).ready(function() { | ||
var randomnumber=Math.floor(Math.random()*11); | ||
$('#user-studies-table').dataTable({ | ||
order: [[10, "asc"], [ 1, "asc" ]], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this sort first by status and then by title? I would think sorting just by title would be a user's expectation, but I am not sure There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, status then title. Figured it was best to have all public then all your own stuff separated in some form at first glance. |
||
columnDefs: [{type:'natural', targets:[3,4,5,9]}, {"targets": [ 2 ],"visible": false}], | ||
"oLanguage": { | ||
"sSearch": "Refine search results:" | ||
} | ||
"sSearch": "Refine search results:", | ||
"sLoadingRecords": "Loading table data" | ||
}, | ||
"ajax": { | ||
"url": "/study/search/?type=standard&user={{current_user.id}}&query=" + query + "&sEcho=" + randomnumber | ||
} | ||
}); | ||
$('#shared-studies-table').dataTable({ | ||
order: [[ 1, "asc" ]], | ||
columnDefs: [{type:'natural', targets:[4,5,6]}, {"targets": [ 2 ],"visible": false}], | ||
"oLanguage": { | ||
"sSearch": "Refine search results:" | ||
"sSearch": "Refine search results:", | ||
"sLoadingRecords": "Loading table data" | ||
}, | ||
"ajax": { | ||
"url": "/study/search/?type=shared&user={{current_user.id}}&query=" + query + "&sEcho=" + randomnumber | ||
} | ||
}); | ||
$('#waiting').hide(); | ||
|
@@ -61,17 +70,16 @@ | |
<h1>Search</h1> | ||
<p><a href="#" data-toggle="modal" data-target="#searchexample">Search help</a></p> | ||
<form id="search-form" name="search-form" class="form-inline" method="POST" action="/study/search/"> | ||
<input type="textbox" id="searchbox" name="searchbox" class="form-control" style="width:80%;white-space:nowrap;" value='{{query}}' /> | ||
<input type="textbox" id="searchbox" name="searchbox" class="form-control" style="width:80%;white-space:nowrap;" /> | ||
<button type="submit" class="btn btn-default">Submit</button> | ||
</form> | ||
</div> | ||
<div class="col-sm-12" id="searchmsg" name="searchmsg"></div> | ||
</div> | ||
<!--User Studies--> | ||
<div class="row"> | ||
<div class="col-sm-12"> | ||
<div class="col-sm-12" id="user-studies-div"> | ||
<h1>Your Studies</h1> | ||
{% if len(user_studies) %} | ||
<table id="user-studies-table" class="display table-bordered table-hover"> | ||
<thead> | ||
<tr> | ||
|
@@ -89,65 +97,13 @@ <h1>Your Studies</h1> | |
</tr> | ||
</thead> | ||
<tbody> | ||
{% set row = 0 %} | ||
{% for s in user_studies %} | ||
<tr> | ||
<td><input type="checkbox" value="{{s.id}}"></td> | ||
{# Title #} | ||
<td><a href="#" data-toggle="modal" data-target="#study-abstract-modal" onclick="fillAbstract('user-studies-table', {{row}})"><span class="glyphicon glyphicon-file" aria-hidden="true"></span></a> | <a href="/study/description/{{ s.id }}" id="study{{row}}-title">{{ s.title }}</a></td> | ||
{# Abstract (hidden on page) #} | ||
<td>{% raw s.abstract %}</td> | ||
{# Study ID #} | ||
<td>{% raw s.id %}</td> | ||
{# Metadata Comlete #} | ||
{% if s.meta_complete %} | ||
<td><span class="glyphicon glyphicon-ok"></span></td> | ||
{% else %} | ||
<td><span class="glyphicon glyphicon-remove"></span></td> | ||
{% end %} | ||
{# Samples #} | ||
<td>{{ s.num_samples_collected }}</td> | ||
{# Sequence Files #} | ||
{% if s.num_raw_data %} | ||
<td>{{ s.num_raw_data }}</td> | ||
{% else %} | ||
<td><span class="glyphicon glyphicon-remove"></span></td> | ||
{% end %} | ||
{# Shared #} | ||
{% if s.status == 'public' %} | ||
<td>Not available</td> | ||
{% else %} | ||
<td><span id="shared_html_{{ s.id }}">{% raw s.shared %}</span> | ||
<br/> | ||
<a class="btn btn-primary" data-toggle="modal" data-target="#share-study-modal-view" onclick="modify_sharing({{ s.id }});">Modify</a> | ||
</td> | ||
{% end %} | ||
{# Principal Investigator #} | ||
<td>{% raw s.pi %}</td> | ||
{# Pubmed ID(s) #} | ||
<td>{% raw s.pmids %}</td> | ||
<td>{{ s.status }}</td> | ||
</tr> | ||
{% set row = row + 1 %} | ||
{% end %} | ||
</tbody> | ||
</table> | ||
{% else %} | ||
<div id="jumbotron" class="jumbotron"> | ||
<h1><span class="glyphicon glyphicon-thumbs-down"></span> There are no studies available.</h1> | ||
<p> | ||
This means that you have not yet created a study. <a href="/study/create/">Create a study</a>. | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
{% end %} | ||
<!--Shared Studies--> | ||
<form id="study-sel-form" name="study-sel-form"> | ||
<div class="row"> | ||
<div class="col-sm-12"> | ||
<div class="col-sm-12" id="user-studies-div"> | ||
<h1>Shared Studies</h1> | ||
{% if len(shared_studies) %} | ||
<table id="shared-studies-table" class="display table-bordered table-hover"> | ||
<thead> | ||
<tr> | ||
|
@@ -164,42 +120,8 @@ <h1>Shared Studies</h1> | |
</tr> | ||
</thead> | ||
<tbody> | ||
{% set row = 0 %} | ||
{% for s in shared_studies %} | ||
<tr> | ||
<td><input type="checkbox" value="{{s.id}}"></td> | ||
<td><a href="#" data-toggle="modal" data-target="#study-abstract-modal" onclick="fillAbstract('shared-studies-table', {{row}})"><span class="glyphicon glyphicon-file" aria-hidden="true"></span></a> | <a href="/study/description/{{ s.id }}" id="study{{row}}-title">{{ s.title }}</a></td> | ||
<td>{% raw s.abstract %}</a></td> | ||
<td>{% raw s.id %}</td> | ||
<td>{% raw s.owner %}</td> | ||
{% if s.meta_complete %} | ||
<td><span class="glyphicon glyphicon-ok"></span></td> | ||
{% else %} | ||
<td><span class="glyphicon glyphicon-remove"></span></td> | ||
{% end %} | ||
<td>{{ s.num_samples_collected }}</td> | ||
{% if s.num_raw_data %} | ||
<td>{{ s.num_raw_data }}</td> | ||
{% else %} | ||
<td><span class="glyphicon glyphicon-remove"></span></td> | ||
{% end %} | ||
<td>{% raw s.pi %}</td> | ||
<td>{% raw s.pmids %}</td> | ||
</tr> | ||
{% set row = row + 1 %} | ||
{% end %} | ||
</tbody> | ||
</table> | ||
{% else %} | ||
<div id="jumbotron" class="jumbotron"> | ||
<h1><span class="glyphicon glyphicon-thumbs-down"></span> There are no studies available.</h1> | ||
<p> | ||
This means that no one has shared any studies with you yet. | ||
</p> | ||
</div> | ||
</div> | ||
</div> | ||
{% end %} | ||
<!--Abstract Modal--> | ||
<div class="modal fade" tabindex="-1" role="dialog" aria-labelledby="myLargeModalLabel" aria-hidden="true" id="study-abstract-modal"> | ||
<div class="modal-dialog modal-med"> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Update the docstring (namedtuples no longer apply). Although this function is private, I think having a bit of numpy doc will help future developers...