Skip to content

Commit

Permalink
sample summary report expansion (#106)
Browse files Browse the repository at this point in the history
* added new fields to sample summary

* lint

* add csv handling for sample summaries

* changes based on feedback

* update naming

* Apply suggestions from code review

---------

Co-authored-by: Cassidy Symons <[email protected]>
  • Loading branch information
ayobi and cassidysymons authored Oct 29, 2024
1 parent b5022c6 commit 43f6674
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 72 deletions.
113 changes: 65 additions & 48 deletions microsetta_admin/server.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import csv
import jwt
from flask import render_template, Flask, request, session, send_file, url_for
import secrets
Expand Down Expand Up @@ -401,63 +402,79 @@ def per_sample_summary():
projects=projects,
error_message=result,
**build_login_variables())

# if we are here then the user is querying using barcodes and we
# simply need to set up the query below to perform.
sample_barcodes = [sample_barcode, ]
else:
# assume POST, since there are only two methods defined in route.
# if we are here, it is because the user is querying using an uploaded
# file containing sample names.
sample_barcodes, err = upload_util.parse_request_csv_col(request,
'file',
'sample_name')
if err is not None:
# there was an error. abort early.
return render_template('per_sample_summary.html',
resource=None,
projects=projects,
**build_login_variables(),
search_error=[{'error': err}])
search_field = request.form.get('search_field')
search_value = request.form.get('single_search')
uploaded_file = request.files.get('upload_list')

# perform the main query.
payload = {'sample_barcodes': sample_barcodes}
status, result = APIRequest.post('/api/admin/account_barcode_summary?stri'
'p_sampleid=%s' % str(strip_sampleid),
json=payload)
search_values = []

if status == 200:
if result['partial_result'] is True:
unprocessed_barcodes = result['unprocessed_barcodes']
if uploaded_file:
file_content = io.TextIOWrapper(uploaded_file,
encoding='utf-8-sig')
csv_reader = csv.reader(file_content)

for row in csv_reader:
search_values.extend(row)
else:
unprocessed_barcodes = None
resource = pd.DataFrame(result['samples'])
order = ['sampleid', 'project', 'account-email',
'source-type', 'site-sampled', 'sample-date',
'sample-time', 'sample-status', 'sample-received',
'ffq-taken', 'ffq-complete', 'vioscreen_username']
order.extend(sorted(set(resource.columns) - set(order)))
resource = resource[order]
search_values = [search_value] if search_value else []

if unprocessed_barcodes:
return render_template('per_sample_summary.html',
resource=resource,
projects=projects,
error_message="Too many barcodes. S"
"erver processed only"
" the first 1000.",
**build_login_variables())
payload = {}
payload[search_field] = search_values

# perform the main query.
status, result = APIRequest.post('/api/admin/account_barcode_summary?'
'strip_sampleid=%s' %
str(strip_sampleid),
json=payload)

if status == 200:
if result['partial_result'] is True:
unprocessed_barcodes = result['unprocessed_barcodes']
else:
unprocessed_barcodes = None
resource = pd.DataFrame(result['samples'])
if not resource.empty:
order = ['sampleid', 'project', 'account-email',
'source-type', 'site-sampled', 'sample-date',
'sample-time', 'sample-status', 'sample-received',
'first-scan-status', 'first-scan-timestamp',
'latest-scan-status', 'latest-scan-timestamp',
'sample-has-inconsistencies', 'sample-is-valid',
'no-associated-source', 'no-collection-info',
'no-registered-account', 'received-unknown-validity',
'ffq-taken', 'ffq-complete', 'vioscreen_username',
'kit-id', 'outbound-tracking',
'inbound-tracking'
]
order.extend(sorted(set(resource.columns) - set(order)))
resource = resource[order]
else:
return render_template('per_sample_summary.html',
resource=resource,
projects=projects,
error_message="No sample found",
**build_login_variables())

if unprocessed_barcodes:
return render_template('per_sample_summary.html',
resource=resource,
projects=projects,
error_message="Too many barcodes. S"
"erver processed only"
" the first 1000.",
**build_login_variables())
else:
return render_template('per_sample_summary.html',
resource=resource,
projects=projects,
**build_login_variables())
else:
return render_template('per_sample_summary.html',
resource=resource,
resource=None,
projects=projects,
error_message=result,
**build_login_variables())
else:
return render_template('per_sample_summary.html',
resource=None,
projects=projects,
error_message=result,
**build_login_variables())


def _get_by_sample_barcode(sample_barcodes, strip_sampleid, projects):
Expand Down
81 changes: 57 additions & 24 deletions microsetta_admin/templates/per_sample_summary.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,25 @@
block.innerHTML = "";
}
};

function handleFormSubmit(event) {
var uploadList = document.getElementById('upload_list');
var singleSearch = document.getElementById('single_search');

if (uploadList.files.length > 0 && singleSearch.value.trim() !== "") {
alert("Please provide either a text input or a file, not both.");
event.preventDefault();
return false;
} else if (uploadList.files.length === 0 && singleSearch.value.trim() === "") {
alert("Please provide either a text input or a file.");
event.preventDefault();
return false;
} else {
remove_error_messages();
return true;
}
}

$(document).ready(function() {
{% if resource is not none %}
$('#search_results').DataTable({
Expand All @@ -27,36 +46,50 @@
{% block content %}
<h3>Sample Summaries</h3>
<hr class="dashed">
<h5>Retrieve summary for a single sample</h5>
{% if error_message %}
<p style="color:red">
{{ error_message |e }}
</p>
{% endif %}
<div style="height: 400px; width: 400px">
{% if error_message %}
<p style="color:red">
{{ error_message |e }}
</p>
{% endif %}
<form name="search_form" id="search_form" method="GET">
<table width=100% border=0>
<tr>
<td colspan=3 style="text-align:left;padding:4px"> <input type="text" name="sample_barcode" placeholder="Enter barcode here" id="sample_barcode" {% if info %} value="{{info.barcode}}"{% endif %}> </td>
<td colspan=1 style="text-align:right;padding:4px"> <input type="submit" value="Retrieve"> </td>
</tr>
</table>
<script> document.search_form.sample_barcode.focus() </script>
</form>
<hr class="dashed">
<h5>Retrieve summaries using a csv file</h5>
<form name="upload_csv" id="search_csv" method="POST" enctype="multipart/form-data" onsubmit="return remove_error_messages()">
<h5>Retrieve summary for a sample</h5>
<form name="search_form" id="search_form" method="POST" enctype="multipart/form-data" onsubmit="return handleFormSubmit(event)">
<table width=100% border=0>
<tr>
<td colspan=3 style="text-align:left;padding:4px"><input type=file name=file></td>
<td colspan=1 style="text-align:right;padding:4px"><input type=submit value=Upload></td>
<td colspan=4 style="text-align:left;padding:4px">
<label for="search_field">Select search field:</label>
<select id="search_field" name="search_field">
<option value="sample_barcodes">Barcode</option>
<option value="kit_ids">Kit ID</option>
<option value="emails">Email</option>
<option value="outbound_tracking_numbers">Outbound Tracking Number</option>
<option value="inbound_tracking_numbers">Inbound Tracking Number</option>
</select>
</td>
</tr>
<tr><td colspan=4>&nbsp;</td></tr>
<tr>
<td colspan=4 style="text-align:left;padding:4px">
Single Value Search: <input type="text" name="single_search" placeholder="Enter value here" id="single_search">
</td>
</tr>
<tr><td colspan=4 style="text-align: center; padding: 4px">-- OR --</td></tr>
<tr>
<td colspan=4 style="text-align:left;padding:4px">
Upload List: <input type="file" name="upload_list" id="upload_list">
</td>
</tr>
<tr>
<td colspan=4 style="text-align:right;padding:4px">
<input type="submit" value="Retrieve">
</td>
</tr>
<tr><td colspan=4></td></tr>
<tr><td colspan=4 style="text-align:center;padding:4px"><i>Barcodes must be listed in column "sample_name"<br>(max: 1000)</i> </td></tr>
<tr><td colspan=4></td></tr>
<tr>
<td colspan=3> <label for="strip_sampleid"> Check to remove sample IDs from summary</label> </td>
<td colspan=1 style="text-align:center;padding:4px"> <input type="checkbox" id="strip_sampleid" name="strip_sampleid"> </td>
<td colspan=3><label for="strip_sampleid">Check to remove sample IDs from summary</label></td>
<td colspan=1 style="text-align:center;padding:4px">
<input type="checkbox" id="strip_sampleid" name="strip_sampleid">
</td>
</tr>
</table>
</form>
Expand Down

0 comments on commit 43f6674

Please sign in to comment.