source: extensions/net.sf.basedb.reggie/trunk/resources/libprep/lib_registration.jsp @ 1934

Last change on this file since 1934 was 1934, checked in by Nicklas Nordborg, 9 years ago

References #485: Select libraries for pooling

Very preliminary wizard for creating pooled library items. Expect it to change a lot in the future. For safety reasons, it will not save any information in the database. It would cause incorrect calculations in the (also preliminary) lab protocols for the pooling.

File size: 19.3 KB
Line 
1<%@ page
2  pageEncoding="UTF-8"
3  session="false"
4  import="net.sf.basedb.core.User"
5  import="net.sf.basedb.core.DbControl"
6  import="net.sf.basedb.core.SessionControl"
7  import="net.sf.basedb.core.Application"
8  import="net.sf.basedb.clients.web.Base" 
9  import="net.sf.basedb.clients.web.util.HTML" 
10  import="net.sf.basedb.clients.web.extensions.ExtensionsControl"
11%>
12<%@ taglib prefix="base" uri="/WEB-INF/base.tld" %>
13<%@ taglib prefix="p" uri="/WEB-INF/path.tld" %>
14<%
15final SessionControl sc = Base.getExistingSessionControl(request, true);
16final String ID = sc.getId();
17final float scale = Base.getScale(sc);
18final String home = ExtensionsControl.getHomeUrl("net.sf.basedb.reggie");
19DbControl dc = null;
20try
21{
22  dc = sc.newDbControl();
23  final User user = User.getById(dc, sc.getLoggedInUserId());
24%>
25<base:page type="default" >
26<base:head scripts="ajax.js" styles="path.css">
27  <link rel="stylesheet" type="text/css" href="../css/reggie.css">
28  <script language="JavaScript" src="../reggie.js" type="text/javascript" charset="UTF-8"></script>
29
30<script language="JavaScript">
31var debug = false;
32var currentStep = 1;
33
34var libDateIsValid = false;
35var wellTableIsValid = false;
36var qubitCsvIsValid = false;
37var libCommentsIsValid = false;
38
39function init()
40{
41  var frm = document.forms['reggie'];
42  var bioplates = getLibraryBioPlates();
43 
44  // Load existing Library plates not yet registered
45  var plates = frm.bioplate;
46  if (bioplates != null && bioplates.length > 0)
47  {
48    for (var i=0; i < bioplates.length; i++)
49    {
50      var bioplate = bioplates[i];
51      var option = new Option(bioplate.name, bioplate.id);
52      option.comments = bioplate.comments;
53      plates.options[plates.length] = option;
54    }
55    bioplateIsValid = true;
56    setInputStatus('bioplate', '', 'valid');
57    bioPlateOnChange();
58    outcomeOnChange();
59  }
60  else
61  {
62    var msg = 'No Library bioplates available for processing.';
63    setFatalError(msg);
64    return;
65  }
66
67  // All is ok
68  frm.bioplate.focus();
69}
70
71
72function goNextAuto()
73{
74  goNext(false);
75}
76
77function goNext(manual)
78{
79  setInnerHTML('gonext.message', '');
80  if (currentStep == 1)
81  {   
82    gotoStep2();
83  }
84  setCurrentStep(currentStep);
85}
86
87
88
89function getLibraryBioPlates()
90{
91  var frm = document.forms['reggie']; 
92 
93  var request = Ajax.getXmlHttpRequest();
94  try
95  {
96    showLoadingAnimation('Loading Library bioplates...');
97    var url = '../LibPrep.servlet?ID=<%=ID%>&cmd=GetLibraryPlatesForLibPrep';   
98    request.open("GET", url, false); 
99    request.send(null);
100  }
101  finally
102  {
103    hideLoadingAnimation();
104  }
105 
106  if (debug) Main.debug(request.responseText);
107  var response = JSON.parse(request.responseText); 
108  if (response.status != 'ok')
109  {
110    setFatalError(response.message);
111    return false;
112  }
113  return response.bioplates;
114}
115
116function gotoStep2()
117{
118  var frm = document.forms['reggie']; 
119  frm.bioplate.disabled = true;
120  frm.outcome[0].disabled = true;
121  frm.outcome[1].disabled = true;
122 
123  currentStep = 2;
124  Main.addClass(document.getElementById('step.1.section'), 'disabled');
125  Main.hide('gonext');
126  Main.show('gocancel');
127  Main.show('goregister');
128 
129  Main.show('step.2.section');
130  frm.libDate.focus();
131
132  // Load Library protocols
133  var libProtocols = getProtocols('LIBRARY_PROTOCOL');
134  for (var i = 0; i < libProtocols.length; i++)
135  {
136    var protocol = libProtocols[i];
137    frm.libProtocol[frm.libProtocol.length] = new Option(protocol.name, protocol.id, protocol.isDefault);
138    setInputStatus('libProtocol', '', 'valid');
139  }
140  if (frm.libProtocol.length == 0)
141  {
142    frm.libProtocol[0] = new Option('- none -', '');
143  }
144}
145
146function getProtocols(subtype)
147{
148  var request = Ajax.getXmlHttpRequest();
149  try
150  {
151    showLoadingAnimation('Loading ' + subtype + ' protocols...');
152    var url = '../Protocol.servlet?ID=<%=ID%>&cmd=GetProtocols&subtype='+subtype;   
153    request.open("GET", url, false); 
154    request.send(null);
155  }
156  finally
157  {
158    hideLoadingAnimation();
159  }
160
161  if (debug) Main.debug(request.responseText);
162  var response = JSON.parse(request.responseText); 
163  if (response.status != 'ok')
164  {
165    setFatalError(response.message);
166    return false;
167  }
168  return response.protocols;
169}
170
171function bioPlateOnChange()
172{
173  var frm = document.forms['reggie'];
174}
175
176function outcomeOnChange()
177{
178  var frm = document.forms['reggie'];
179  var failed = document.getElementById('outcomeFailed').checked
180
181  if (failed)
182  {
183    Main.addClass(frm.libComments, 'required');
184    Main.hide('filesSection');
185  }
186}
187
188var lastPrefix;
189function browseOnClick(prefix, extension)
190{
191  var frm = document.forms['reggie'];
192  if (frm[prefix+'.path'].disabled) return;
193 
194  var url = getRoot() + 'filemanager/index.jsp?ID=<%=ID%>&cmd=SelectOne&callback=setFileCallback';
195  url += '&resetTemporary=1&tmpfilter:STRING:name='+escape('%.' + extension);
196  lastPrefix = prefix;
197  Main.openPopup(url, 'SelectFile', 1000, 700);
198}
199
200function setFileCallback(id, path)
201{
202  var frm = document.forms['reggie'];
203  frm[lastPrefix+'.id'].value = id;
204  frm[lastPrefix+'.path'].value = path;
205 
206  if (lastPrefix == 'welltable')
207  {
208    preValidateCsvFile();
209  }
210  else if (lastPrefix == 'qubitcsv')
211  {
212    qubitCsvFileOnChange();
213    frm.libProtocol.focus();
214  }
215  else
216  {
217    setInputStatus(lastPrefix, '', 'valid');
218  }
219}
220
221function libDateOnChange()
222{
223  var frm = document.forms['reggie'];
224  libDateIsValid = false;
225  setInputStatus('libDate', '', '');
226 
227  var libDate = frm.libDate.value;
228  if (libDate == '')
229  {
230    setInputStatus('libDate', 'Missing', 'invalid');
231    return;
232  }
233
234  // Auto-fill the date if it's only given with 4(MMdd) or 6(yyMMdd) digits.   
235  libDate = autoFillDate(libDate);
236  frm.libDate.value = libDate;
237 
238  if (!Dates.isDate(libDate, 'yyyyMMdd'))
239  {
240    setInputStatus('libDate', 'Not a valid date', 'invalid');
241    return;
242  }
243 
244  setInputStatus('libDate', '', 'valid');
245  libDateIsValid = true;
246}
247
248
249function preValidateCsvFile()
250{
251  var frm = document.forms['reggie'];
252  var csvId = frm['welltable.id'].value;
253  var csvPath = frm['welltable.path'].value;
254 
255  wellTableIsValid = false;
256 
257  if (!csvId) 
258  {
259    setInputStatus('welltable', 'Missing', 'invalid');
260    return;
261  }
262 
263  var url = '../LibPrep.servlet?ID=<%=ID%>&cmd=PreValidateCaliperWellTable&csv='+csvId;
264 
265  var request = Ajax.getXmlHttpRequest();
266  request.open("POST", url, false); 
267  request.send('');
268 
269  if (debug) Main.debug(request.responseText);
270  var response = JSON.parse(request.responseText); 
271 
272  if (response.messages && response.messages.length > 0)
273  {
274    var messages = '<ul>';
275    for (var i = 0; i < response.messages.length; i++)
276    {
277      messages += '<li>' + response.messages[i];
278    }
279    messages += '</ul>';
280    setInnerHTML('messages', messages);
281    Main.show('messages');
282  }
283  else
284  {
285    Main.hide('messages'); 
286  }
287 
288  if (response.status != 'ok')
289  {
290    setInputStatus('welltable', response.message, 'invalid');
291    Main.addClass(document.getElementById('messages'), 'failure');
292    return;
293  }
294
295  setInputStatus('welltable', '', 'valid');
296  wellTableIsValid = true;
297}
298
299
300function qubitCsvFileOnChange()
301{
302  var frm = document.forms['reggie'];
303  qubitCsvIsValid = false;
304  if (!frm['qubitcsv.id'].value)
305  {
306    // A PDF is reuired for successful registration, optional after a failure
307    var msg = frm['qubitcsv.path'].value ? 'Use the Browse button to select a file' : 'Missing';
308    setInputStatus('qubitcsv', msg, 'invalid');
309    return;
310  }
311  qubitCsvIsValid = true;
312  setInputStatus('qubitcsv', '', 'valid');
313}
314
315function libCommentsOnChange()
316{
317  var failed = document.getElementById('outcomeFailed').checked;
318  if (!failed) return;
319
320  var frm = document.forms['reggie'];
321  libCommentsIsValid = false;
322  setInputStatus('libComments', '', '');
323 
324  var comments = frm.libComments.value;
325  if (comments == '')
326  {
327    setInputStatus('libComments', 'Missing', 'invalid');
328    return;
329  }
330
331  setInputStatus('libComments', '', 'valid');
332  libCommentsIsValid = true;
333}
334
335
336function step2IsValid()
337{
338  var failed = document.getElementById('outcomeFailed').checked;
339  if (failed)
340  {
341    return libDateIsValid && libCommentsIsValid;
342  }
343  else
344  {
345    return libDateIsValid && wellTableIsValid && qubitCsvIsValid;
346  }
347}
348
349function goRegister()
350{
351  if (!step2IsValid()) return;
352  var frm = document.forms['reggie'];
353
354 
355  Main.hide('goregister');
356  Main.hide('gocancel');
357
358  var submitInfo = {};
359  submitInfo.bioplate = parseInt(frm.bioplate.value, 10);
360
361  Main.addClass(document.getElementById('step.2.section'), 'disabled');
362  var url = '../LibPrep.servlet?ID=<%=ID%>&cmd=ImportLibPrepResults';
363  var failed = document.getElementById('outcomeFailed').checked;
364  submitInfo.failed = failed;
365   
366  if (!failed)
367  {
368    submitInfo.wellTableCsv = parseInt(frm['welltable.id'].value, 10);
369    submitInfo.caliperGxd = parseInt(frm['calipergxd.id'].value, 10);
370    submitInfo.caliperPdf = parseInt(frm['caliperpdf.id'].value, 10);
371    submitInfo.qubitCsv = parseInt(frm['qubitcsv.id'].value, 10);
372  }
373   
374  submitInfo.libDate = frm.libDate.value;
375  submitInfo.libProtocol = parseInt(frm.libProtocol.value, 10);
376  submitInfo.libOperator = frm.libOperator.value;
377  submitInfo.libComments = frm.libComments.value;
378 
379  if (debug) Main.debug(JSON.stringify(submitInfo));
380 
381  var request = Ajax.getXmlHttpRequest();
382  try
383  {
384    showLoadingAnimation('Performing registration...');
385    request.open("POST", url, false);
386    request.send(JSON.stringify(submitInfo));
387  }
388  finally
389  {
390    hideLoadingAnimation();
391  }
392 
393  if (debug) Main.debug(request.responseText);
394  var response = JSON.parse(request.responseText);
395 
396  if (response.messages && response.messages.length > 0)
397  {
398    var msg = '<ul>';
399    for (var i = 0; i < response.messages.length; i++)
400    {
401      var msgLine = response.messages[i];
402      if (msgLine.indexOf('[Warning]') >= 0)
403      {
404        msg += '<li class="warning">' + msgLine.replace('[Warning]', '');
405      }
406      else
407      {
408        msg += '<li>' + msgLine;
409      }
410    }
411    msg += '</ul>';
412    setInnerHTML('messages', msg);
413    Main.show('messages');
414  }
415 
416  if (response.status != 'ok')
417  {
418    Main.addClass(document.getElementById('messages'), 'failure');
419    setFatalError(response.message);
420    return false;
421  }
422
423  Main.show('gorestart');
424}
425
426
427</script>
428
429</base:head>
430<base:body onload="init()">
431
432  <p:path><p:pathelement 
433    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
434    /><p:pathelement title="Library registration" 
435    /></p:path>
436
437  <div class="content">
438  <%
439  if (sc.getActiveProjectId() == 0)
440  {
441    %>
442    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
443      No project has been selected. You may proceed with the registration but
444      created items will not be shared.
445    </div>
446    <%
447  }
448  %>
449
450  <form name="reggie" onsubmit="return false;">
451    <input type="hidden" name="pdf.id" value="">
452 
453  <div id="step.1.section">
454  <table class="stepform">
455  <tr>
456    <td rowspan="3" class="stepno">1</td>
457    <td class="steptitle">Select Library bioplate</td>
458  </tr>
459  <tr>
460    <td class="stepfields">
461      <table>
462      <tr valign="top">
463        <td class="prompt">Library bioplate</td>
464        <td class="input"><select class="required" style="width:90%;" 
465            name="bioplate" id="bioplate" onchange="bioPlateOnChange()"></select>
466        </td>
467        <td class="status" id="bioplate.status"></td>
468        <td class="help"><span id="bioplate.message" class="message" style="display: none;"></span>
469          Select an existing Library bioplate. The list contain all Library bioplates that
470          has not yet been processed (determined by the absence of a 'creation' date).
471        </td>
472      </tr>
473      <tr valign="top" id="outcomeSection">
474        <td class="prompt">Outcome</td>
475        <td class="input">
476          <input type="radio" name="outcome" id="outcomeSuccess" 
477            onchange="outcomeOnChange()" checked><label for="outcomeSuccess">Success</label> - continue processing<br>
478          <input type="radio" name="outcome" id="outcomeFailed" 
479            onchange="outcomeOnChange()"><label for="outcomeFailed">Failure</label> - no further processing
480        </td>
481        <td class="status"></td>
482        <td class="help">
483          Select the <b>Failure</b> option if further processing to pooled libraries is not possible.
484          Existing RNA will be flagged and added to the <b>Flagged RNA</b> list.
485        </td>
486      </tr>
487      </table>
488    </td>
489  </tr>
490  </table>
491  </div>
492 
493 
494  <div id="step.2.section" style="display: none;">
495  <table class="stepform">
496  <tr>
497    <td rowspan="3" class="stepno">2</td>
498    <td class="steptitle">Full plate registration</td>
499  </tr>
500  <tr>
501    <td class="stepfields">
502      <table>
503      <tr valign="top">
504        <td class="prompt">Date</td>
505        <td class="input">
506          <input type="text" class="required" name="libDate" value="" size="12" maxlength="10"
507            onblur="libDateOnChange()" onkeypress="focusOnEnter(event, 'welltable.path')">
508        </td>
509        <td class="status" id="libDate.status"></td>
510        <td class="help">
511          <span id="libDate.message" class="message" style="display: none;"></span>(YYYYMMDD or MMDD)
512        </td>
513      </tr>
514      <tbody id="filesSection">
515      <tr>
516        <td class="prompt">Caliper files</td>
517        <td class="input"></td>
518        <td class="status"></td>
519        <td class="help"></td>
520      </tr>
521      <tr valign="top">
522        <td class="subprompt">Well table CSV</td>
523        <td class="input">
524          <input type="hidden" name="welltable.id" value="">
525          <table>
526          <tr>
527          <td><input class="text required" type="text" 
528            name="welltable.path" value=""
529            size="50" onkeypress="doOnEnter(event, function(){document.getElementById('btnWellTable').click()})"
530            onblur="csvFileOnChange()"
531            ></td>
532          <td style="padding-left: 4px;"><base:button 
533              title="Browse&hellip;"
534              onclick="browseOnClick('welltable', 'csv')"
535              id="btnWellTable"
536              />
537          </td>
538          </tr>
539          </table>
540        </td>
541        <td class="status" id="welltable.status"></td>
542        <td class="help"><span id="welltable.message" class="message" style="display: none;"></span>
543           Select the <b>Well Table CSV</b> file that contains the exported analysis
544           result from the Caliper software.
545        </td>
546      </tr>
547      <tr valign="top">
548        <td class="subprompt">GXD raw data</td>
549        <td class="input">
550          <input type="hidden" name="calipergxd.id" value="">
551          <table>
552          <tr>
553          <td><input class="text" type="text" 
554            name="calipergxd.path" value=""
555            size="50" onkeypress="doOnEnter(event, function(){document.getElementById('btnCaliperGxd').click()})"
556            onblur="caliperGxdFileOnChange()"
557            ></td>
558          <td style="padding-left: 4px;"><base:button 
559              title="Browse&hellip;"
560              onclick="browseOnClick('calipergxd', 'gxd')"
561              id="btnCaliperGxd"
562              />
563          </td>
564          </tr>
565          </table>
566        </td>
567        <td class="status" id="calipergxd.status"></td>
568        <td class="help"><span id="calipergxd.message" class="message" style="display: none;"></span>
569          Select the <b>GXD raw data file</b> from Caliper.
570        </td>
571      </tr>
572      <tr valign="top">
573        <td class="subprompt">PDF file</td>
574        <td class="input">
575          <input type="hidden" name="caliperpdf.id" value="">
576          <table>
577          <tr>
578          <td><input class="text" type="text" 
579            name="caliperpdf.path" value=""
580            size="50" onkeypress="doOnEnter(event, function(){document.getElementById('btnCaliperPdf').click()})"
581            onblur="caliperPdfFileOnChange()"
582            ></td>
583          <td style="padding-left: 4px;"><base:button 
584              title="Browse&hellip;"
585              onclick="browseOnClick('caliperpdf', 'pdf')"
586              id="btnCaliperPdf"
587              />
588          </td>
589          </tr>
590          </table>
591        </td>
592        <td class="status" id="caliperpdf.status"></td>
593        <td class="help"><span id="caliperpdf.message" class="message" style="display: none;"></span>
594          Select the <b>PDF file</b> that contains a printout with diagrams and other
595          useful documentation.
596        </td>
597      </tr>
598      <tr>
599        <td class="prompt">Qubit files</td>
600        <td class="input"></td>
601        <td class="status"></td>
602        <td class="help"></td>
603      </tr>
604      <tr valign="top">
605        <td class="subprompt">Conc. CSV</td>
606        <td class="input">
607          <input type="hidden" name="qubitcsv.id" value="">
608          <table>
609          <tr>
610          <td><input class="text required" type="text" 
611            name="qubitcsv.path" value=""
612            size="50" onkeypress="doOnEnter(event, function(){document.getElementById('btnQubitCsv').click()})"
613            onblur="qubitCsvFileOnChange()"
614            ></td>
615          <td style="padding-left: 4px;"><base:button 
616              title="Browse&hellip;"
617              onclick="browseOnClick('qubitcsv', 'csv')"
618              id="btnQubitCsv"
619              />
620          </td>
621          </tr>
622          </table>
623        </td>
624        <td class="status" id="qubitcsv.status"></td>
625        <td class="help"><span id="qubitcsv.message" class="message" style="display: none;"></span>
626          Select the <b>Qubit CSV</b> file that contains the table with concentration
627          measurements.
628        </td>
629      </tr>
630      </tbody>
631      <tr valign="top">
632        <td class="prompt">Protocol</td>
633        <td class="input"><select style="width:90%" name="libProtocol" id="libProtocol" 
634          onkeypress="focusOnEnter(event, 'libOperator')"></select></td>
635        <td class="status" id="libProtocol.status"></td>
636        <td class="help"><span id="libProtocol.message" class="message" style="display: none;"></span>
637          Select the protocol used for library preparation.
638        </td>
639      </tr>
640      <tr valign="top">
641        <td class="prompt">Operator</td>
642        <td class="input">
643          <input type="text" name="libOperator" value="<%=HTML.encodeTags(user.getName()) %>" 
644            style="width: 90%;" maxlength="255" onkeypress="focusOnEnter(event, 'libComments')">
645        </td>
646        <td class="status" id="libOperator.status"></td>
647        <td class="help">
648          <span id="libOperator.message" class="message" style="display: none;"></span>
649        </td>
650      </tr>
651      <tr valign="top">
652        <td class="prompt">Comments</td>
653        <td class="input"><textarea rows="4" cols="50" style="width: 90%;" name="libComments" value="" onblur="libCommentsOnChange()"></textarea></td>
654        <td class="status" id="libComments.status"></td>
655        <td class="help"><span id="libComments.message" class="message" style="display: none;"></span>Comments about the library preparation.</td>
656      </tr>
657      </table>
658    </td>
659  </tr>
660  </table>
661  </div>
662 
663 
664  <div class="loading" id="loading" style="display: none;"><table><tr><td><img src="../images/loading.gif"></td><td id="loading.msg">Please wait...</td></tr></table></div>
665 
666  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
667 
668  <div id="messages" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
669 
670  <table style="margin-left: 20px; margin-top: 10px;" class="navigation">
671    <tr>
672      <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" style="display: none;"/></td>
673      <td><base:button id="gonext" title="Next" image="<%=home+"/images/gonext.png"%>" onclick="goNext(true)"/></td>
674      <td><base:button id="goregister" title="Register" image="<%=home+"/images/import.png"%>" onclick="goRegister()" style="display: none;"/></td>
675      <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
676      <td id="gonext.message" class="message"></td>
677    </tr>
678  </table>
679 
680  </form>
681  </div>
682 
683</base:body>
684</base:page>
685<%
686}
687finally
688{
689  if (dc != null) dc.close();
690}
691%>
Note: See TracBrowser for help on using the repository browser.