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

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

References #473: Register library processing results

Split the library registration wizard into two. One for registering QC results and one for the final registration of the complete plate.

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 quality control results.</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.