3 $odk_crossing_data_service_name => undef
4 $odk_crossing_data_service_url => undef
5 $odk_crossing_data_test_form_name => undef
6 $odk_phenotyping_data_service_name => undef
7 $odk_phenotyping_data_service_url => undef
10 <& /util/import_javascript.mas, classes => [ 'jstree.dist.jstree', 'd3.d3Min', 'SGN.Scatterplot' ] &>
12 <& /util/import_css.mas, paths => ['/static/documents/inc/jstree_theme/jstree-bstheme-min.css'] &>
15 <& /page/page_title.mas, title=>"Manage ODK Data Collection" &>
17 <div class="container-fluid">
21 <ul><li>ODK is an application that allows mobile data collection using user defined forms on Android or IOS devices. Data collected on the device can be instantaneously synched to the ODK server. To find out more go to the <a href="https://opendatakit.org/">ODK site</a>. Many services have developed web interfaces to better streamline the ODK experience. These services assist in creating forms, deploying forms to your mobile application, and visualizing data uploaded back from the mobile device. Currently we are working with <a href="https://ona.io/home/">ONA</a> as an ODK service.</li></ul>
22 <h4>What do I do from this page?</h4>
24 <li>ONA is currently being used for collecting crossing information. This requires exporting a crossing plan from here to the ONA server. The crossing plan guides collection of cross information and this data is synched with ONA using ODK. From here, we run a script twice a day, which pulls data on ONA into our database.
27 <li>SMAP is currently being used for collecting phenotype information. The user collects phenotypes using a form they previously created. The questions in the form map directly to terms in the ontology. As they collect data on the mobile device, the data is synched to SMAP. From here, we run a script twice a day, which pulls data on SMAP into our database.
35 <&| /page/info_section.mas, title=>'Crossing Data: ONA ODK Application', collapsible=>1, collapsed=>0, is_subsection=>1, subtitle=>'' &>
37 <div class="panel panel-default">
38 <div class="panel-body">
39 <form class="form-horizontal" id="import_odk_cross_data_form" name="import_odk_cross_data_form">
40 <div class="form-group">
41 <label class="col-sm-4 control-label">Select An ODK Form on ONA: </label>
42 <div class="col-sm-8" >
43 <div id="import_odk_cross_data_available_forms">LOADING...</div>
50 <&| /page/info_section.mas, title=>'Management', collapsible=>1, collapsed=>0, is_subsection=>1, subtitle=>'' &>
52 <div class="panel panel-default">
53 <div class="panel-body">
55 <div class="col-sm-1">
56 <span style="font-size:3em;" class="glyphicon glyphicon-transfer"></span>
58 <div class="col-sm-11">
59 <button class="pull-right btn btn-info btn-sm" id="import_odk_cross_data" >Import Crossing Data from Selected Form on ONA</button>
66 <div class="panel panel-default">
67 <div class="panel-body">
69 <div class="col-sm-1">
70 <span style="font-size:3em;" class="glyphicon glyphicon-time"></span>
72 <div class="col-sm-11">
73 <form class="form-horizontal" id="schedule_import_odk_cross_data_form" name="schedule_import_odk_cross_data_form">
74 <div class="form-group">
75 <label class="col-sm-6 control-label">Schedule Import For Selected Form: </label>
76 <div class="col-sm-4" >
77 <select class="form-control" id="schedule_import_odk_crossing_form_data">
78 <option value="everyday">Once per day at midnight</option>
79 <option value="twicedaily">Twice daily at midnight and noon</option>
80 <option value="everyhour">Once per hour</option>
81 <option value="everyminute">Once per minute</option>
82 <option value="none">None</option>
85 <div class="col-sm-2" >
86 <button class="btn btn-info btn-sm" id="schedule_import_odk_cross_data" >Confirm</button>
89 <div class="form-group">
90 <label class="col-sm-6 control-label">Scheduled Time: </label>
91 <div class="col-sm-6" >
92 <div id="scheduled_odk_cross_import_time">
93 <input type="text" disabled value="Not Set" class="form-control" />
106 <&| /page/info_section.mas, title=>'Progress', collapsible=>1, collapsed=>0, is_subsection=>1, subtitle=>'' &>
108 <div id="testing_div"></div>
110 <div class="panel panel-default">
111 <div class="panel-body">
112 <h3>Summary of Received Plant Status</h3>
113 <div id="odk_cross_plant_status_progress_summary_div">
119 <div class="panel panel-default">
120 <div class="panel-body">
121 <h3>Summary of Received Cross Data</h3>
122 <div id="odk_cross_progress_summary_div">
128 <div class="panel panel-default">
129 <div class="panel-body">
130 <div id="odk_cross_progress_div">
132 <h3>Progress Tree</h3>
133 <input type="text" class="form-control input-sm" id="odk_cross_progress_tree_search" placeholder="Search Across Tree" /><br/>
134 <table class="table table-bordered">
137 <th>All Cross Wishlist Entries-- Crosses Completed -- Lab Actions Completed</th>
143 <div id="odk_cross_progress_tree_div" >[loading...]</div>
161 SMAP ODK NOT IMPLEMENTED
164 <&| /page/info_section.mas, title=>'Phenotype Data: SMAP ODK Application', collapsible=>1, collapsed=>0, is_subsection=>1, subtitle=>'[<a id="upload_fieldbook_phenotypes_link" >Upload Fieldbook Database File</a>]' &>
166 <button class="btn btn-primary btn-sm" id="import_odk_phenotype_data" >Import Phenotype Data from SMAP</button>
177 jQuery(document).ready(function () {
180 url : '/ajax/odk/get_crossing_available_forms',
181 beforeSend: function() {
182 jQuery("#working_modal").modal("show");
184 success: function(response){
185 console.log(response);
186 jQuery("#working_modal").modal("hide");
189 alert(response.error);
191 if (response.success){
194 url : '/ajax/odk/get_crossing_saved_ona_forms',
195 success: function(response_forms){
196 console.log(response_forms);
198 if (response_forms.error){
199 alert(response.error);
201 if (response_forms.success){
202 var form_dropdown_select_html = '<select class="form-control" id="availabe_odk_crossing_forms">';
203 var allowed_forms = response_forms.odk_ona_forms;
204 allowed_forms.push('<% $c->config->{odk_crossing_data_test_form_name} %>');
206 for(var i=0; i<response.forms.length; i++){
207 if (jQuery.inArray(response.forms[i].id_string, allowed_forms) != -1){
208 form_dropdown_select_html = form_dropdown_select_html + '<option value="'+response.forms[i].id+'">'+response.forms[i].id_string+'</option>';
209 form_ids.push(response.forms[i].id);
212 console.log(form_ids);
213 var first_form_id = form_ids[0];
214 form_dropdown_select_html = form_dropdown_select_html + '</select>';
215 jQuery('#import_odk_cross_data_available_forms').html(form_dropdown_select_html);
218 url : '/ajax/odk/get_odk_cross_summary_cached?form_id='+first_form_id,
219 success: function(response){
220 console.log(response);
221 summary = response.summary;
223 html = '<table id="odk_cross_info_status_table" class="table table-hover table-bordered"><thead><tr><th>Cross Information</th><th>Seeds Produced Graphs</th></tr></thead><tbody>';
224 for (var top_level in summary) {
225 if (summary.hasOwnProperty(top_level)) {
226 for (var cross_name in summary[top_level]){
227 if (summary[top_level].hasOwnProperty(cross_name)){
228 html = html + '<tr><td><h3>'+cross_name+'</h3>';
229 var cross = summary[top_level][cross_name];
230 //console.log(cross);
232 for (var activity in cross){
233 if (cross.hasOwnProperty(activity)){
234 html = html + '<b>'+activity + ' ('+cross[activity].length+')</b>: <br/>';
235 for (var i=0; i<cross[activity].length; i++){
236 var action = cross[activity][i];
237 for (var attr in action){
238 if (action.hasOwnProperty(attr)){
239 html = html + ' <small>'+attr + ': ' +action[attr]+"</small><br/>";
242 html = html + ' ----</br>';
244 if (activity == 'seedExtraction'){
245 var date = action['extraction_date'].replace('-','').replace('-','').replace('/','').replace('/','');
246 var datum = { "type":activity, "label":"Total Seeds Extracted", "x_pos":parseInt(date), "y_pos":parseInt(action['total_seeds_extracted']) };
247 plot_data.push(datum);
249 if (activity == 'embryoRescue'){
250 var date = action['embryorescue_date'].replace('-','').replace('-','').replace('/','').replace('/','');
251 var datum = { "type":activity, "label":"Good Seeds", "x_pos":parseInt(date), "y_pos":parseInt(action['good_seeds']) };
252 plot_data.push(datum);
253 var datum = { "type":activity, "label":"Bad Seeds", "x_pos":parseInt(date), "y_pos":parseInt(action['bad_seeds']) };
254 plot_data.push(datum);
255 var datum = { "type":activity, "label":"Embryo Rescued Seeds", "x_pos":parseInt(date), "y_pos":parseInt(action['embryorescue_seeds']) };
256 plot_data.push(datum);
258 if (activity == 'screenhouse_humiditychamber'){
259 var date = action['screenhse_transfer_date'].replace('-','').replace('-','').replace('/','').replace('/','');
260 var datum = { "type":activity, "label":"Screenhouse Humidity Chamber", "x_pos":parseInt(date), "y_pos":1 };
261 plot_data.push(datum);
263 if (activity == 'rooting'){
264 var date = action['rooting_date'].replace('-','').replace('-','').replace('/','').replace('/','');
265 var datum = { "type":activity, "label":"Rooting", "x_pos":parseInt(date), "y_pos":1 };
266 plot_data.push(datum);
268 if (activity == 'hardening'){
269 var date = action['hardening_date'].replace('-','').replace('-','').replace('/','').replace('/','');
270 var datum = { "type":activity, "label":"Hardening", "x_pos":parseInt(date), "y_pos":1 };
271 plot_data.push(datum);
273 if (activity == 'contamination'){
274 var date = action['lab_contamination_date'].replace('-','').replace('-','').replace('/','').replace('/','');
275 var datum = { "type":activity, "label":"Contamination", "x_pos":parseInt(date), "y_pos":1 };
276 plot_data.push(datum);
278 if (activity == 'subculture'){
279 var date = action['subculture_date'].replace('-','').replace('-','').replace('/','').replace('/','');
280 var datum = { "type":activity, "label":"Subcultures Count", "x_pos":parseInt(date), "y_pos":parseInt(action['subcultures_count']) };
281 plot_data.push(datum);
283 if (activity == 'germinating_after_2wks'){
284 var date = action['germinating_2wks_date'].replace('-','').replace('-','').replace('/','').replace('/','');
285 var datum = { "type":activity, "label":"Active Seeds 2weeks", "x_pos":parseInt(date), "y_pos":parseInt(action['actively_2wks']) };
286 plot_data.push(datum);
288 if (activity == 'germinating_after_8weeks'){
289 var date = action['germinating_8wksdate'].replace('-','').replace('-','').replace('/','').replace('/','');
290 var datum = { "type":activity, "label":"Active Seeds 8weeks", "x_pos":parseInt(date), "y_pos":parseInt(action['active_8weeks']) };
291 plot_data.push(datum);
296 //console.log(plot_data);
297 cross_name_clean = cross_name.replace('/', '').replace('(', '').replace(')','');
298 var div_id = encodeURI(cross_name_clean)+'_plot_div';
299 plot_data_fill.push([plot_data, div_id]);
300 html = html + '</td><td><div id="'+div_id+'"></div></td></tr>';
305 html = html + '</tbody></table>';
306 jQuery('#odk_cross_progress_summary_div').html(html);
307 for (var i=0; i<plot_data_fill.length; i++){
308 if (plot_data_fill[i][0].length > 0){
309 SGND3ScatterPlot(plot_data_fill[i][0], plot_data_fill[i][1], "Date of Activity");
312 jQuery('#odk_cross_info_status_table').DataTable({
313 "order": [[ 0, "desc" ]]
316 var plant_status_html = '<table id="odk_cross_plant_status_table" class="table table-hover table-bordered"><thead><tr><th>Plot Name</th><th>Date</th><th>Status</th></tr></thead><tbody>';
317 var plant_status_summary = response.plant_status_summary;
318 console.log(plant_status_summary);
319 for (var plot_name in plant_status_summary){
320 if (plant_status_summary.hasOwnProperty(plot_name)){
322 for (var status_type in plant_status_summary[plot_name]){
324 if (plant_status_summary[plot_name].hasOwnProperty(status_type)){
325 var status = plant_status_summary[plot_name][status_type];
326 //console.log(status);
327 if (status_type == 'status'){
328 plant_status_html = plant_status_html + '<tr><td>' + plot_name + '</td><td>' + status['status_date'] + '</td><td><b>Status:</b><br/>Accession Name: ' + status['status_accession_name'] + '<br/>Trial Name: ' + status['status_trial_name'] + '<br/>User: ' + status['status_user'] + '<br/>Status Location: ' + status['status_location'] + '<br/>Status: ' + status['status_message'] + '<br/>Note: ' + status['status_note'] + '<br/>Image: ' + status['attachment_display_thumb'] + '<br/></td></tr>';
330 if (status_type == 'flowering'){
331 plant_status_html = plant_status_html + '<tr><td>' + plot_name + '</td><td>' + status['FieldActivities/Flowering/flowering_date'] + '</td><td><b>Flowering:</b><br/>Accession Name: ' + status['FieldActivities/Flowering/flowerName'] + '<br/>Plant Sex: ' + status['FieldActivities/Flowering/plantSex'] + '<br/></td></tr>';
335 if (has_status == 0){
336 plant_status_html = plant_status_html+ '<tr><td>' + plot_name + '</td><td></td><td></td></tr>';
340 plant_status_html = plant_status_html + '</tbody></thead>';
341 jQuery('#odk_cross_plant_status_progress_summary_div').html(plant_status_html);
342 jQuery('#odk_cross_plant_status_table').DataTable({
343 "order": [[ 1, "desc" ]]
346 error: function(response){
347 alert("Error retrieving available ODK cross summary");
351 //Load ODK Cross Progress Tree
352 jQuery('#odk_cross_progress_tree_div').jstree({
355 'url' : '/ajax/odk/get_odk_cross_progress_cached?form_id='+first_form_id,
356 'data' : function (node) {
357 return { 'id' : node.id };
360 'themes': { 'name': 'proton', 'responsive': true}
363 "case_insensitive" : true,
365 "plugins" : ["html_data","search","sort"],
368 jQuery("#odk_cross_progress_tree_search").keyup(function() {
369 var v = jQuery("#odk_cross_progress_tree_search").val();
370 jQuery("#odk_cross_progress_tree_div").jstree(true).search(v);
374 error: function(response_forms){
375 alert("Error retrieving saved ODK ONA forms");
381 error: function(response){
382 jQuery("#working_modal").modal("hide");
383 alert("Error retrieving available ODK crossing forms");
388 url : '/ajax/odk/get_crossing_data_cronjobs',
389 beforeSend: function() {
390 jQuery("#working_modal").modal("show");
392 success: function(response){
393 console.log(response);
394 jQuery("#working_modal").modal("hide");
397 alert(response.error);
399 if (response.success){
400 var html = 'Not Set';
401 if (response.entries[0] == '0-59/1 * * * * '){
402 html = '<input type="text" disabled value="Once per minute" class="form-control" />';
404 if (response.entries[0] == '1 0 * * * '){
405 html = '<input type="text" disabled value="Once per day at midnight" class="form-control" />';
407 if (response.entries[0] == '0 * * * * '){
408 html = '<input type="text" disabled value="Once per hour" class="form-control" />';
410 if (response.entries[0] == '0 0,12 * * * '){
411 html = '<input type="text" disabled value="Twice daily at midnight and noon" class="form-control" />';
413 jQuery('#scheduled_odk_cross_import_time').html(html);
416 error: function(response){
417 jQuery("#working_modal").modal("hide");
421 jQuery('#import_odk_phenotype_data').click( function(){
423 url : '/ajax/odk/get_phenotyping_data?form_id='+jQuery('#availabe_odk_phenotyping_forms').val(),
424 beforeSend: function() {
425 jQuery("#working_modal").modal("show");
427 success: function(response){
428 //console.log(response);
429 jQuery("#working_modal").modal("hide");
432 alert(response.error);
434 alert('Not currently working.');
436 error: function(response){
437 jQuery("#working_modal").modal("hide");
438 alert("Error retrieving ODK phenotyping data.");
443 jQuery('#import_odk_cross_data').click( function(){
445 url : '/ajax/odk/get_crossing_data?form_id='+jQuery('#availabe_odk_crossing_forms').val(),
446 beforeSend: function() {
447 jQuery("#working_modal").modal("show");
449 success: function(response){
450 console.log(response);
451 jQuery("#working_modal").modal("hide");
454 alert(response.error);
458 error: function(response){
459 jQuery("#working_modal").modal("hide");
460 alert("Error retrieving ODK crossing data.");
465 jQuery('#schedule_import_odk_cross_data').click( function(){
467 url : '/ajax/odk/schedule_get_crossing_data?form_id='+jQuery('#availabe_odk_crossing_forms').val()+'&timing='+jQuery('#schedule_import_odk_crossing_form_data').val(),
468 beforeSend: function() {
469 jQuery("#working_modal").modal("show");
471 success: function(response){
472 console.log(response);
473 jQuery("#working_modal").modal("hide");
476 alert(response.error);
479 error: function(response){
480 jQuery("#working_modal").modal("hide");
481 alert("Error scheduling import of ODK crossing data.");