fix test with new description field.
[sgn.git] / mason / breeders_toolbox / manage_odk_data_collection.mas
blobee9d61761b2a7cc56b897ad876c62b6a854a9f9b
2 <%args>
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
8 </%args>
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">
19 <div class="well">
20 <h4>What is ODK?</h4>
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>
23 <ul>
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.
25 </li>
26 <!--
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.
28 </li>
29 -->
30 </ul>
31 </div>
33 <div class="well">
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>
44                 </div>
45             </div>
46         </form>
47     </div>
48 </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">
54         <div class="row">
55             <div class="col-sm-1">
56                 <span style="font-size:3em;" class="glyphicon glyphicon-transfer"></span>
57             </div>
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>
60             </div>
61         </div>
62     </div>
63 </div>
65 <!--
66 <div class="panel panel-default">
67     <div class="panel-body">
68         <div class="row">
69             <div class="col-sm-1">
70                 <span style="font-size:3em;" class="glyphicon glyphicon-time"></span>
71             </div>
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>
83                             </select>
84                         </div>
85                         <div class="col-sm-2" >
86                             <button class="btn btn-info btn-sm" id="schedule_import_odk_cross_data" >Confirm</button>
87                         </div>
88                     </div>
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" />
94                             </div>
95                         </div>
96                     </div>
97                 </form>
98             </div>
99         </div>
100     </div>
101 </div>
104 </&>
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">
114         [LOADING...]
115         </div>
116     </div>
117 </div>
118 <!--
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">
123         [LOADING...]
124         </div>
125     </div>
126 </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">
135                 <thead>
136                     <tr>
137                         <th>All Cross Wishlist Entries-- Crosses Completed -- Lab Actions Completed</th>
138                     </tr>
139                 </thead>
140                 <tbody>
141                     <tr>
142                         <td>
143                             <div id="odk_cross_progress_tree_div" >[loading...]</div>
144                         </td>
145                     </tr>
146                 </tbody>
147             </table>
149         </div>
150     </div>
151 </div>
153 </&>
156 </&>
158 </div>
160 <!--
161 SMAP ODK NOT IMPLEMENTED
162 <div class="well">
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>
168 </&>
170 </div>
173 </div>
175 <script>
177 jQuery(document).ready(function () {
179     jQuery.ajax ( {
180         url : '/ajax/odk/get_crossing_available_forms',
181         beforeSend: function() {
182             jQuery("#working_modal").modal("show");
183         },
184         success: function(response){
185             console.log(response);
186             jQuery("#working_modal").modal("hide");
188             if (response.error){
189                 alert(response.error);
190             }
191             if (response.success){
193                 jQuery.ajax ({
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);
200                         }
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} %>');
205                             var form_ids = [];
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);
210                                 }
211                             }
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);
217                             jQuery.ajax ({
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;
222                                     plot_data_fill = [];
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);
231                                                     var plot_data = [];
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 + '&nbsp;&nbsp;&nbsp;&nbsp;<small>'+attr + ': ' +action[attr]+"</small><br/>";
240                                                                     }
241                                                                 }
242                                                                 html = html + '&nbsp;&nbsp;&nbsp;&nbsp;----</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);
248                                                                 }
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);
257                                                                 }
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);
262                                                                 }
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);
267                                                                 }
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);
272                                                                 }
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);
277                                                                 }
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);
282                                                                 }
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);
287                                                                 }
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);
292                                                                 }
293                                                             }
294                                                         }
295                                                     }
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>';
301                                                 }
302                                             }
303                                         }
304                                     }
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");
310                                         }
311                                     }
312                                     jQuery('#odk_cross_info_status_table').DataTable({
313                                         "order": [[ 0, "desc" ]]
314                                     });
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)){
321                                             var has_status = 0;
322                                             for (var status_type in plant_status_summary[plot_name]){
323                                                 has_status = 1;
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>';
329                                                     }
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>';
332                                                     }
333                                                 }
334                                             }
335                                             if (has_status == 0){
336                                                 plant_status_html = plant_status_html+ '<tr><td>' + plot_name + '</td><td></td><td></td></tr>';
337                                             }
338                                         }
339                                     }
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" ]]
344                                     });
345                                 },
346                                 error: function(response){
347                                     alert("Error retrieving available ODK cross summary");
348                                 }
349                             });
351                             //Load ODK Cross Progress Tree
352                             jQuery('#odk_cross_progress_tree_div').jstree({
353                                 "core": {
354                                     'data' : {
355                                         'url' : '/ajax/odk/get_odk_cross_progress_cached?form_id='+first_form_id,
356                                         'data' : function (node) {
357                                             return { 'id' : node.id };
358                                         }
359                                     },
360                                     'themes': { 'name': 'proton', 'responsive': true}
361                                 },
362                                 "search" : {
363                                     "case_insensitive" : true,
364                                 },
365                                 "plugins" : ["html_data","search","sort"],
366                             });
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);
371                             });
372                         }
373                     },
374                     error: function(response_forms){
375                         alert("Error retrieving saved ODK ONA forms");
376                     }
377                 });
379             }
380         },
381         error: function(response){
382             jQuery("#working_modal").modal("hide");
383             alert("Error retrieving available ODK crossing forms");
384         }
385     });
387     jQuery.ajax ( {
388         url : '/ajax/odk/get_crossing_data_cronjobs',
389         beforeSend: function() {
390             jQuery("#working_modal").modal("show");
391         },
392         success: function(response){
393             console.log(response);
394             jQuery("#working_modal").modal("hide");
396             if (response.error){
397                 alert(response.error);
398             }
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" />';
403                 }
404                 if (response.entries[0] == '1 0 * * * '){
405                     html = '<input type="text" disabled value="Once per day at midnight" class="form-control" />';
406                 }
407                 if (response.entries[0] == '0 * * * * '){
408                     html = '<input type="text" disabled value="Once per hour" class="form-control" />';
409                 }
410                 if (response.entries[0] == '0 0,12 * * * '){
411                     html = '<input type="text" disabled value="Twice daily at midnight and noon" class="form-control" />';
412                 }
413                 jQuery('#scheduled_odk_cross_import_time').html(html);
414             }
415         },
416         error: function(response){
417             jQuery("#working_modal").modal("hide");
418         }
419     });
421     jQuery('#import_odk_phenotype_data').click( function(){
422         jQuery.ajax ( {
423             url : '/ajax/odk/get_phenotyping_data?form_id='+jQuery('#availabe_odk_phenotyping_forms').val(),
424             beforeSend: function() {
425                 jQuery("#working_modal").modal("show");
426             },
427             success: function(response){
428                 //console.log(response);
429                 jQuery("#working_modal").modal("hide");
431                 if (response.error){
432                     alert(response.error);
433                 }
434                 alert('Not currently working.');
435             },
436             error: function(response){
437                 jQuery("#working_modal").modal("hide");
438                 alert("Error retrieving ODK phenotyping data.");
439             }
440         });
441     });
443     jQuery('#import_odk_cross_data').click( function(){
444         jQuery.ajax ( {
445             url : '/ajax/odk/get_crossing_data?form_id='+jQuery('#availabe_odk_crossing_forms').val(),
446             beforeSend: function() {
447                 jQuery("#working_modal").modal("show");
448             },
449             success: function(response){
450                 console.log(response);
451                 jQuery("#working_modal").modal("hide");
453                 if (response.error){
454                     alert(response.error);
455                 }
456                 location.reload();
457             },
458             error: function(response){
459                 jQuery("#working_modal").modal("hide");
460                 alert("Error retrieving ODK crossing data.");
461             }
462         });
463     });
465     jQuery('#schedule_import_odk_cross_data').click( function(){
466         jQuery.ajax ( {
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");
470             },
471             success: function(response){
472                 console.log(response);
473                 jQuery("#working_modal").modal("hide");
475                 if (response.error){
476                     alert(response.error);
477                 }
478             },
479             error: function(response){
480                 jQuery("#working_modal").modal("hide");
481                 alert("Error scheduling import of ODK crossing data.");
482             }
483         });
484     });
488 </script>