source: extensions/net.sf.basedb.reggie/trunk/resources/libprep/flowcell_registration.jsp @ 2031

Last change on this file since 2031 was 2031, checked in by Nicklas Nordborg, 8 years ago

References #481: Register prepared flow cells

Added fields for "FlowCellID", "ReadString?" and sequence start date/operator when registering flow cells. But so far, only some of the information is saved in the database.

Not sure if we should introduce a DERIVEDBIOASSAY to represent the sequencing already at this point. If so, it would make sense to register the start date and operator on this item instead of on the flow cells.

Failure to cluster a flow cell is also not handled vere well at the moment.

File size: 17.0 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">
31
32var debug = true;
33var currentStep = 1;
34
35var dateIsValid = [];
36var flowCellIsValid = [];
37var commentsIsValid = false;
38
39
40function init()
41{
42  var frm = document.forms['reggie'];
43  var flowCells = getFlowCells();
44 
45  // Load existing Flow cells not yet registered
46  if (flowCells != null && flowCells.length > 0)
47  {
48    for (var i=0; i < flowCells.length; i++)
49    {
50      var flowCell = flowCells[i];
51      var option = new Option(flowCell.name, flowCell.id, i < 2);
52      option.flowCell = flowCell;
53      frm.flowcells.options[frm.flowcells.length] = option;
54    }
55    setInputStatus('flowcells', '', 'valid');
56    outcomeOnChange();
57  }
58  else
59  {
60    var msg = 'No flow cells available for processing.';
61    setFatalError(msg);
62    return;
63  }
64
65  // All is ok
66  frm.flowcells.focus();
67}
68
69
70function goNextAuto()
71{
72  goNext(false);
73}
74
75function goNext(manual)
76{
77  setInnerHTML('gonext.message', '');
78  if (currentStep == 1)
79  {   
80    gotoStep2();
81  }
82  setCurrentStep(currentStep);
83}
84
85
86
87function getFlowCells()
88{
89  var frm = document.forms['reggie']; 
90 
91  var request = Ajax.getXmlHttpRequest();
92  try
93  {
94    showLoadingAnimation('Loading flow cells lists...');
95    var url = '../FlowCell.servlet?ID=<%=ID%>&cmd=GetUnprocessedFlowCells';   
96    request.open("GET", url, false); 
97    request.send(null);
98  }
99  finally
100  {
101    hideLoadingAnimation();
102  }
103 
104  if (debug) Main.debug(request.responseText);
105  var response = JSON.parse(request.responseText); 
106  if (response.status != 'ok')
107  {
108    setFatalError(response.message);
109    return false;
110  }
111  return response.flowCells;
112}
113
114function gotoStep2()
115{
116  var frm = document.forms['reggie'];
117 
118  var selectedFlowCells = [];
119  for (var i = 0; i < frm.flowcells.length; i++)
120  {
121    if (frm.flowcells[i].selected)
122    {
123      selectedFlowCells[selectedFlowCells.length] = frm.flowcells[i].flowCell;
124    }
125  }
126 
127  if (selectedFlowCells.length == 0)
128  {
129    setInputStatus('flowcells', 'Select at least 1 flow cell', 'invalid');
130    return;
131  }
132
133 
134  frm.flowcells.disabled = true;
135  frm.outcome[0].disabled = true;
136  frm.outcome[1].disabled = true;
137
138  currentStep = 2;
139  Main.show('step.2.section');
140  Main.addClass(document.getElementById('step.1.section'), 'disabled');
141  Main.hide('gonext');
142  Main.show('gocancel');
143  Main.show('goregister');
144 
145  var html = '<tr valign="top">';
146  html += '<td class="prompt">Flow cell</td>';
147  html += '<td style="width: 11em;"><b>ID</b></td>';
148  html += '<td><b>ReadString</b></td>';
149  html += '<td class="status"></td>';
150  html += '<td class="help" rowspan="' + (selectedFlowCells.length+1) +'">';
151  html += 'ID and ReadString is required for registration. ';
152  html += 'ReadString must be a sequence of letters <b>Y</b>, <b>N</b>, <b>I</b>, <b>J</b> followed by digits.';
153  html += '</td>';
154  html += '</tr>';
155 
156  for (var i = 0; i < selectedFlowCells.length; i++)
157  {
158    var fc = selectedFlowCells[i];
159    var prefix = 'fc.'+fc.id;
160    html += '<tr>';
161    html += '<td class="subprompt">'+fc.name+'</td>';
162    html += '<td><input type="text" class="required" name="'+prefix+'.id" onblur="flowCellIdOnBlur('+fc.id+')"></td>';
163    html += '<td><input type="text" class="required" name="'+prefix+'.readString" onblur="readStringOnBlur('+fc.id+')" value="'+fc.ReadString+'"></td>';
164    html += '<td class="status" id="'+prefix+'.status">';
165    html += '</tr>';
166  }
167 
168  setInnerHTML('fc-data', html);
169 
170  // Load mRNA protocols
171  var clusterProtocols = getProtocols('CLUSTER_PROTOCOL');
172  for (var i = 0; i < clusterProtocols.length; i++)
173  {
174    var protocol = clusterProtocols[i];
175    frm.clusterProtocol[frm.clusterProtocol.length] = new Option(protocol.name, protocol.id, protocol.isDefault);
176    setInputStatus('clusterProtocol', '', 'valid');
177  }
178  if (frm.clusterProtocol.length == 0)
179  {
180    frm.clusterProtocol[0] = new Option('- none -', '');
181  }
182
183  frm['fc.'+selectedFlowCells[0].id+'.id'].focus();
184}
185
186function getProtocols(subtype)
187{
188  var request = Ajax.getXmlHttpRequest();
189  try
190  {
191    showLoadingAnimation('Loading ' + subtype + ' protocols...');
192    var url = '../Protocol.servlet?ID=<%=ID%>&cmd=GetProtocols&subtype='+subtype;   
193    request.open("GET", url, false); 
194    request.send(null);
195  }
196  finally
197  {
198    hideLoadingAnimation();
199  }
200
201  if (debug) Main.debug(request.responseText);
202  var response = JSON.parse(request.responseText); 
203  if (response.status != 'ok')
204  {
205    setFatalError(response.message);
206    return false;
207  }
208  return response.protocols;
209}
210
211function outcomeOnChange()
212{
213  var frm = document.forms['reggie'];
214  Main.addOrRemoveClass(frm['comments'], 'required', document.getElementById('outcomeFailed').checked);
215  commentsOnChange();
216}
217
218function dateOnChange(dateField)
219{
220  var frm = document.forms['reggie'];
221
222  setInputStatus(dateField, '', '');
223  dateIsValid[dateField] = true;
224  var date = frm[dateField].value;
225
226  if (date == '')
227  {
228    setInputStatus(dateField, 'Missing date', 'warning');
229    return;
230  }
231
232  // Auto-fill the date if it's only given with 4(MMdd) or 6(yyMMdd) digits.   
233  date = autoFillDate(date);
234  frm[dateField].value = date;
235  if (!Dates.isDate(date, 'yyyyMMdd'))
236  {
237    setInputStatus(dateField, 'Not a valid date', 'invalid');
238    dateIsValid[dateField] = false;
239    return;
240  }
241 
242  setInputStatus(dateField, '', 'valid');
243}
244
245function setDate(frmName, dateField, date)
246{
247  var frm = document.forms['reggie'];
248  frm[dateField].value = date;
249  dateOnChange(dateField);
250  frm[dateField].focus();
251}
252
253function commentsOnChange()
254{
255  var frm = document.forms['reggie'];
256  commentsIsValid = false;
257  setInputStatus('comments', '', '');
258 
259  var comments = frm.comments.value;
260 
261  if (comments == '' && document.getElementById('outcomeFailed').checked)
262  {
263    setInputStatus('comments', 'Missing', 'invalid');
264    return;
265  }
266
267  setInputStatus('comments', '', 'valid');
268  commentsIsValid = true;
269}
270
271function flowCellIdOnBlur(flowCellId)
272{
273  checkFlowCellData(flowCellId);
274}
275
276function readStringOnBlur(flowCellId)
277{
278  checkFlowCellData(flowCellId);
279}
280
281function checkFlowCellData(flowCellId)
282{
283  var frm = document.forms['reggie'];
284   
285  var prefix = 'fc.'+flowCellId;
286  setInputStatus(prefix, '', '');
287 
288  flowCellIsValid[prefix+'.id'] = false;
289  flowCellIsValid[prefix+'.readString'] = false;
290 
291  var id = frm[prefix+'.id'].value;
292  if (id == '')
293  {
294    setInputStatus(prefix, 'ID is a required value', 'invalid');
295    return;
296  }
297 
298  flowCellIsValid[prefix+'.id'] = true;
299 
300  var readString = frm[prefix+'.readString'].value;
301  if (readString == '')
302  {
303    setInputStatus(prefix, 'ReadString is a required value', 'invalid');
304    return;
305  }
306
307  if (!readString.match(/^([YNIJ]\d+)+$/))
308  {
309    setInputStatus(prefix, 'Not a valid ReadString value', 'invalid');
310    return;
311  }
312 
313  flowCellIsValid[prefix+'.readString'] = true;
314  setInputStatus(prefix, '', 'valid');
315}
316
317function step2IsValid()
318{
319  if (!commentsIsValid) return false;
320 
321  if (dateIsValid['clusterDate'] == false) return false;
322  if (dateIsValid['sequenceStartDate'] == false) return false;
323 
324  var frm = document.forms['reggie'];
325  for (var i = 0; i < frm.flowcells.length; i++)
326  {
327    if (frm.flowcells[i].selected)
328    {
329      var fc = frm.flowcells[i].flowCell;
330      Main.debug(fc.name + ':'+ fc.id + ':' + flowCellIsValid['fc.'+fc.id+'.id'] + ':' + flowCellIsValid['fc.'+fc.id+'.readString']);
331      if (flowCellIsValid['fc.'+fc.id+'.id'] != true) return false;
332      if (flowCellIsValid['fc.'+fc.id+'.readString'] != true) return false;
333    }
334  }
335 
336  return true;
337}
338
339function goRegister()
340{
341  if (!step2IsValid()) return;
342  var frm = document.forms['reggie'];
343 
344  Main.hide('goregister');
345  Main.hide('gocancel');
346  Main.addClass(document.getElementById('step.2.section'), 'disabled');
347
348  frm.clusterDate.disabled = true;
349  frm.clusterOperator.disabled = true;
350  frm.sequenceStartDate.disabled = true;
351  frm.sequenceOperator.disabled = true;
352  frm.clusterProtocol.disabled = true;
353  frm.comments.disabled = true;
354 
355  var submitInfo = {};
356  submitInfo.flowCells = [];
357  for (var i = 0; i < frm.flowcells.length; i++)
358  {
359    if (frm.flowcells[i].selected) 
360    {
361      var fc = frm.flowcells[i].flowCell;
362      fc.externalId = frm['fc.'+fc.id+'.id'].value;
363      fc.ReadString = frm['fc.'+fc.id+'.readString'].value;
364      submitInfo.flowCells[submitInfo.flowCells.length] = fc;
365    }
366  }
367 
368  submitInfo.clusterProtocol = parseInt(frm.clusterProtocol.value, 10);
369  submitInfo.failed = document.getElementById('outcomeSuccess').checked ? false : true;
370  submitInfo.clusterDate = frm.clusterDate.value;
371  submitInfo.clusterOperator = frm.clusterOperator.value;
372  submitInfo.sequenceStartDate = frm.sequenceStartDate.value;
373  submitInfo.sequenceOperator = frm.sequenceOperator.value;
374  submitInfo.comments = frm.comments.value;
375 
376  if (debug) Main.debug(JSON.stringify(submitInfo));
377  var url = '../FlowCell.servlet?ID=<%=ID%>&cmd=RegisterFlowCells';
378 
379  var request = Ajax.getXmlHttpRequest();
380  try
381  {
382    showLoadingAnimation('Performing registration...');
383    request.open("POST", url, false);
384    request.send(JSON.stringify(submitInfo));
385  }
386  finally
387  {
388    hideLoadingAnimation();
389  }
390 
391  if (debug) Main.debug(request.responseText);
392  var response = JSON.parse(request.responseText);
393 
394  if (response.messages && response.messages.length > 0)
395  {
396    var msg = '<ul>';
397    for (var i = 0; i < response.messages.length; i++)
398    {
399      var msgLine = response.messages[i];
400      if (msgLine.indexOf('[Warning]') >= 0)
401      {
402        msg += '<li class="warning">' + msgLine.replace('[Warning]', '');
403      }
404      else
405      {
406        msg += '<li>' + msgLine;
407      }
408    }
409    msg += '</ul>';
410    setInnerHTML('messages', msg);
411    Main.show('messages');
412  }
413 
414  if (response.status != 'ok')
415  {
416    Main.addClass(document.getElementById('messages'), 'failure');
417    setFatalError(response.message);
418    return false;
419  }
420
421  Main.show('gorestart');
422}
423
424
425</script>
426
427</base:head>
428<base:body onload="init()">
429
430  <p:path><p:pathelement 
431    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
432    /><p:pathelement title="Flow cell registration" 
433    /></p:path>
434
435  <div class="content">
436  <%
437  if (sc.getActiveProjectId() == 0)
438  {
439    %>
440    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
441      No project has been selected. You may proceed with the registration but
442      created items will not be shared.
443    </div>
444    <%
445  }
446  %>
447
448  <form name="reggie" onsubmit="return false;">
449    <input type="hidden" name="pdf.id" value="">
450 
451  <div id="step.1.section">
452  <table class="stepform">
453  <tr>
454    <td rowspan="3" class="stepno">1</td>
455    <td class="steptitle">Select flow cells</td>
456  </tr>
457  <tr>
458    <td class="stepfields">
459      <table>
460      <tr valign="top">
461        <td class="prompt">Flow cells</td>
462        <td class="input"><select class="required" style="width:90%;" 
463            name="flowcells" id="flowcells" multiple size="4"></select>
464        </td>
465        <td class="status" id="flowcells.status"></td>
466        <td class="help"><span id="flowcells.message" class="message" style="display: none;"></span>
467          Select one or more existing flow cells. The list contain all flow cells that
468          has not yet been processed (determined by the absence of a 'creation' date).
469        </td>
470      </tr>
471      <tr valign="top">
472        <td class="prompt">Outcome</td>
473        <td class="input">
474          <input type="radio" name="outcome" id="outcomeSuccess" 
475            onchange="outcomeOnChange()" checked><label for="outcomeSuccess">Success</label> - continue with sequencing<br>
476          <input type="radio" name="outcome" id="outcomeFailed" 
477            onchange="outcomeOnChange()"><label for="outcomeFailed">Failure</label> - no sequencing
478        </td>
479        <td class="status"></td>
480        <td class="help">
481          Select the <b>Failure</b> option if it is not possible to continue
482          with sequencing. RNA will be flagged and added
483          to the <b>Flagged RNA</b> list.
484        </td>
485      </tr>
486      </table>
487    </td>
488  </tr>
489  </table>
490  </div>
491 
492  <div id="step.2.section" style="display: none;">
493  <table class="stepform">
494  <tr>
495    <td rowspan="3" class="stepno">2</td>
496    <td class="steptitle">Clustering information</td>
497  </tr>
498  <tr>
499    <td class="stepfields">
500      <table>
501      <tbody id="fc-data"></tbody>
502      <tr valign="top">
503        <td class="prompt">Step</td>
504        <td style="width: 11em;"><b>Date</b></td>
505        <td><b>Operator</b></td>
506        <td class="status"></td>
507        <td class="help" rowspan="3">
508          Enter date and operator for each step in the clustering and sequencing startup.
509          (YYYYMMDD or MMDD)
510        </td>
511      </tr>
512      <tr>
513        <td class="subprompt">Clustering</td>
514        <td>
515          <input type="text" name="clusterDate" maxlength="10" style="width: 8em;"
516            onblur="dateOnChange('clusterDate')" onkeypress="focusOnEnter(event, 'clusterOperator')">
517            <base:icon 
518              onclick="Dates.selectDate('Cluster date', 'reggie', 'clusterDate', 'setDate', 'yyyyMMdd')"
519              image="calendar.png" 
520              tooltip="Select a date from a calendar" 
521              tabindex="-1"
522            />
523        </td>
524        <td>
525          <input type="text" name="clusterOperator" value="<%=HTML.encodeTags(user.getName()) %>" 
526            style="width: 95%;" maxlength="255" onkeypress="focusOnEnter(event, 'sequenceStartDate')">
527        </td>
528        <td class="status" id="clusterDate.status"></td>
529      </tr>
530      <tr>
531        <td class="subprompt">Sequence start</td>
532        <td>
533          <input type="text" name="sequenceStartDate" maxlength="10" style="width: 8em;"
534            onblur="dateOnChange('sequenceStartDate')" onkeypress="focusOnEnter(event, 'sequenceOperator')">
535            <base:icon 
536              onclick="Dates.selectDate('Sequence start date', 'reggie', 'sequenceStartDate', 'setDate', 'yyyyMMdd')"
537              image="calendar.png" 
538              tooltip="Select a date from a calendar" 
539              tabindex="-1"
540            />
541        </td>
542        <td>
543          <input type="text" name="sequenceOperator" value="<%=HTML.encodeTags(user.getName()) %>" 
544            style="width: 95%;" maxlength="255" onkeypress="focusOnEnter(event, 'clusterProtocol')">
545        </td>
546        <td class="status" id="sequenceStartDate.status"></td>
547      </tr>
548      <tr valign="top">
549        <td class="prompt">Protocol</td>
550        <td class="input" colspan="2"><select style="width:90%" name="clusterProtocol" id="clusterProtocol" 
551          onkeypress="focusOnEnter(event, 'comments')"></select></td>
552        <td class="status" id="clusterProtocol.status"></td>
553        <td class="help"><span id="clusterProtocol.message" class="message" style="display: none;"></span>
554          Select the protocol which was used in the clustering.
555        </td>
556      </tr>
557      <tr valign="top">
558        <td class="prompt">Comments</td>
559        <td class="input" colspan="2"><textarea rows="4" cols="50" style="width: 90%;" name="comments" value="" onblur="commentsOnChange()"></textarea></td>
560        <td class="status" id="comments.status"></td>
561        <td class="help"><span id="comments.message" class="message" style="display: none;"></span>Comments about the clustering.</td>
562      </tr>
563      </table>
564    </td>
565  </tr>
566  </table>
567  </div>
568 
569  <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>
570 
571  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
572 
573  <div id="messages" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
574 
575  <table style="margin-left: 20px; margin-top: 10px;" class="navigation">
576    <tr>
577      <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" style="display: none;"/></td>
578      <td><base:button id="gonext" title="Next" image="<%=home+"/images/gonext.png"%>" onclick="goNext(true)"/></td>
579      <td><base:button id="goregister" title="Register" image="<%=home+"/images/import.png"%>" onclick="goRegister()" style="display: none;"/></td>
580      <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
581      <td id="gonext.message" class="message"></td>
582    </tr>
583  </table>
584 
585  </form>
586  </div>
587 
588</base:body>
589</base:page>
590<%
591}
592finally
593{
594  if (dc != null) dc.close();
595}
596%>
Note: See TracBrowser for help on using the repository browser.