source: extensions/net.sf.basedb.reggie/trunk/resources/libprep/create_flowcells.jsp @ 2020

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

References #481: Register prepared flow cells

Preliminary wizards for flow cell creation and registration.

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  <link rel="stylesheet" type="text/css" href="../css/plate.css">
29  <script language="JavaScript" src="../reggie.js" type="text/javascript" charset="UTF-8"></script>
30
31<script language="JavaScript">
32var debug = true;
33var currentStep = 1;
34
35var poolsAreValid = false;
36var flowCellsAreValid = false;
37
38var flowCells = [];
39var selectedPools = [];
40
41function init()
42{
43  var frm = document.forms['reggie'];
44  var pools = getUnusedPools();
45 
46  var poolsList = frm.pools;
47  if (pools != null && pools.length > 0)
48  {
49    for (var poolNo=0; poolNo < pools.length; poolNo++)
50    {
51      var pool = pools[poolNo];
52      poolsList[poolsList.length] = new Option(pool.name, pool.id, poolNo < 4);
53    }
54  }
55 
56  Main.show('step.1.section');
57  Main.show('gocreate');
58  Main.show('navigation');
59  poolsOnChange();
60}
61
62function getUnusedPools()
63{
64  var frm = document.forms['reggie']; 
65 
66  var request = Ajax.getXmlHttpRequest();
67  try
68  {
69    showLoadingAnimation('Loading pools...');
70    var url = '../FlowCell.servlet?ID=<%=ID%>&cmd=GetUnusedPools';   
71    request.open("GET", url, false); 
72    request.send(null);
73  }
74  finally
75  {
76    hideLoadingAnimation();
77  }
78 
79  if (debug) Main.debug(request.responseText);
80  var response = JSON.parse(request.responseText); 
81  if (response.status != 'ok')
82  {
83    setFatalError(response.message);
84    return false;
85  }
86  return response.pools;
87}
88
89function loadFlowCellNames(numNames)
90{
91  var frm = document.forms['reggie'];
92
93  // Load Libraries and related info from the selected bioplate
94  var request = Ajax.getXmlHttpRequest();
95  try
96  {
97    showLoadingAnimation('Loading flow cell information...');
98    var url = '../FlowCell.servlet?ID=<%=ID%>&cmd=GetNextAutoGeneratedFlowCellNames&numNames='+numNames;   
99    request.open("GET", url, false);
100    request.send(null);
101  }
102  finally
103  {
104    hideLoadingAnimation();
105  }
106 
107  if (debug) Main.debug(request.responseText);
108  var response = JSON.parse(request.responseText);
109  if (response.status != 'ok')
110  {
111    setFatalError(response.message);
112    return false;
113  }
114 
115  var names = response.names;
116  for (var i = 0; i < names.length; i++)
117  {
118    var fc = {};
119    fc.name = names[i];
120    flowCells[i] = fc;
121    setInnerHTML('fc.'+i, fc.name);
122  }
123}
124
125function poolsOnChange()
126{
127  poolsAreValid = false;
128 
129  var frm = document.forms['reggie'];
130  var poolsList = frm.pools;
131 
132  var numSelected = 0;
133  for (var i = 0; i < poolsList.length; i++)
134  {
135    if (poolsList[i].selected) numSelected++;
136  }
137
138  setInnerHTML('numSelected', numSelected + ' selected');
139 
140  if (numSelected == 0)
141  {
142    setInputStatus('pools', 'Must select at least 1 pool.', 'invalid');
143    return;
144  }
145 
146  poolsAreValid = true;
147  setInputStatus('pools', '', 'valid');
148}
149
150
151var subtypePooledLibrary = null;
152function selectPools()
153{
154  var frm = document.forms['reggie'];
155  if (frm.pools.disabled) return;
156 
157  if (subtypePooledLibrary == null)
158  {
159    var request = Ajax.getXmlHttpRequest();
160    var url = '../Subtype.servlet?ID=<%=ID%>&cmd=GetSubtypeInfo&name=POOLED_LIBRARY';
161    request.open("GET", url, false); 
162    request.send(null);
163
164    if (debug) Main.debug(request.responseText);
165    var response = JSON.parse(request.responseText); 
166    if (response.status != 'ok')
167    {
168      setFatalError(response.message);
169      return false;
170    }
171    subtypePooledLibrary = response.subtype;
172  }
173
174  var url = getRoot() + 'biomaterials/extracts/index.jsp?ID=<%=ID%>&cmd=UpdateContext&mode=selectmultiple&callback=setPoolCallback';
175  url += '&tmpfilter:INT:itemSubtype='+subtypePooledLibrary.id;
176  url += '&tmpfilter:DATE:creationEvent.eventDate='+encodeURIComponent('<>');
177  url += '&resetTemporary=1';
178  Main.openPopup(url, 'SelectPooledLibraries', 1050, 700);
179}
180
181function setPoolCallback(id, name)
182{
183  var frm = document.forms['reggie'];
184  var poolsList = frm.pools;
185  for (var i = 0; i < poolsList.length; i++)
186  {
187    if (poolsList[i].value == id)
188    {
189      poolsList[i].selected = true;
190      poolsOnChange();
191      return;
192    }
193  }
194
195  var option = new Option(name, id, true, true);
196  poolsList[poolsList.length] = option;
197  poolsOnChange();
198}
199
200
201function goNext(manual)
202{
203  setInnerHTML('gonext.message', '');
204  if (currentStep == 1)
205  {   
206    gotoStep2();
207  }
208  setCurrentStep(currentStep);
209}
210
211function gotoStep2()
212{
213  if (!poolsAreValid) return;
214 
215  var frm = document.forms['reggie'];
216  frm.pools.disabled = true;
217  frm.num_flowcells[0].disabled = true;
218  frm.num_flowcells[1].disabled = true;
219  frm.num_lanes[0].disabled = true;
220  frm.num_lanes[1].disabled = true;
221 
222  var numFlowCells = Forms.getCheckedRadio(frm.num_flowcells).value;
223  loadFlowCellNames(numFlowCells);
224  var plate = document.getElementById('plate');
225  if (numFlowCells == 1)
226  {
227    Main.addClass(plate, 'hide-fc-1');
228  }
229 
230  var numLanes = Forms.getCheckedRadio(frm.num_lanes).value;
231  for (var i = numLanes; i < 8; i++)
232  {
233    Main.hide('lane.'+i);
234  }
235
236  var selectPoolHtml = ''; 
237  for (var i = 0; i < frm.pools.length; i++)
238  {
239    if (frm.pools[i].selected)
240    {
241      var pool = {};
242      pool.id = parseInt(frm.pools[i].value, 10);
243      pool.name = frm.pools[i].text;
244      var index = selectedPools.length;
245      selectedPools[index] = pool;
246     
247      selectPoolHtml += '<div class="menuitem enabled" id="pool-'+pool.id+'" data-index="'+index+'">';
248      selectPoolHtml += pool.name+'</div>';
249    }
250  }
251  setInnerHTML('select-pool-all', selectPoolHtml);
252
253  // Initialize flowCell->lane->pool array
254  for (var fcNo = 0; fcNo < numFlowCells; fcNo++)
255  {
256    var pools = [];
257    pools.length = numLanes;
258    flowCells[fcNo].pools = pools;
259  }
260 
261  // Case 1: 4 pools on 2+2 lanes
262  if (numFlowCells == 2 && numLanes == 8 && selectedPools.length == 4)
263  {
264    // Assign all pools to 2 lanes on each flow cell
265    for (var poolNo = 0; poolNo < 4; poolNo++)
266    {
267      var pool = selectedPools[poolNo];
268      flowCells[0].pools[poolNo] = pool;
269      flowCells[0].pools[poolNo+4] = pool;
270      flowCells[1].pools[3-poolNo] = pool;
271      flowCells[1].pools[7-poolNo] = pool;
272    }
273  }
274 
275  // Case 2: A single pool on all lanes
276  if (selectedPools.length == 1)
277  {
278    var pool = selectedPools[0];
279    for (var fcNo = 0; fcNo < numFlowCells; fcNo++)
280    {
281      for (var laneNo = 0; laneNo < numLanes; laneNo++)
282      {
283        flowCells[fcNo].pools[laneNo] = pool;
284      }
285    }
286  }
287 
288  // Set the name on all lanes
289  for (var fcNo = 0; fcNo < numFlowCells; fcNo++)
290  {
291    for (var laneNo = 0; laneNo < numLanes; laneNo++)
292    {
293      var pool = flowCells[fcNo].pools[laneNo];
294      setInnerHTML('lane.'+laneNo+'.'+fcNo, pool ? pool.name : '');
295    }
296  }
297  checkFlowCells();
298
299 
300  currentStep = 2;
301  Main.show('step.2.section');
302  Main.addClass(document.getElementById('step.1.section'), 'disabled');
303  Main.hide('gonext');
304  Main.show('gocancel');
305  Main.show('goregister');
306}
307
308function checkFlowCells()
309{
310  setInputStatus('flowCells', '', '');
311  flowCellsAreValid = false;
312 
313  for (var fcNo = 0; fcNo < flowCells.length; fcNo++)
314  {
315    for (var laneNo = 0; laneNo < flowCells[fcNo].pools.length; laneNo++)
316    {
317      var pool = flowCells[fcNo].pools[laneNo];
318      if (!pool)
319      {
320        setInputStatus('flowCells', 'Missing', 'invalid');
321        return;
322      }
323    }
324  }
325  setInputStatus('flowCells', '', 'valid');
326  flowCellsAreValid = true;
327}
328
329function goRegister()
330{
331  if (!flowCellsAreValid) return;
332 
333  var frm = document.forms['reggie'];
334 
335  Main.hide('goregister');
336  Main.hide('gocancel');
337  Main.addClass(document.getElementById('step.1.section'), 'disabled');
338
339  var submitInfo = {};
340  submitInfo.flowCells = flowCells;
341 
342  // Calculate volume to use for each pool
343  for (var fcNo = 0; fcNo < flowCells.length; fcNo++)
344  {
345    for (var laneNo = 0; laneNo < flowCells[fcNo].pools.length; laneNo++)
346    {
347      var pool = flowCells[fcNo].pools[laneNo];
348      pool.count = pool.count ? pool.count+1 : 1;
349    }
350  }
351 
352  for (var poolNo = 0; poolNo < selectedPools.length; poolNo++)
353  {
354    var pool = selectedPools[poolNo];
355    pool.usedVolume = 10 / pool.count;
356  }
357 
358  if (debug) Main.debug(JSON.stringify(submitInfo));
359 
360  var url = '../FlowCell.servlet?ID=<%=ID%>&cmd=CreateFlowCells';
361 
362  var request = Ajax.getXmlHttpRequest();
363  try
364  {
365    showLoadingAnimation('Performing registration...');
366    request.open("POST", url, false);
367    request.send(JSON.stringify(submitInfo));
368  }
369  finally
370  {
371    hideLoadingAnimation();
372  }
373 
374  if (debug) Main.debug(request.responseText);
375  var response = JSON.parse(request.responseText);
376 
377  if (response.messages && response.messages.length > 0)
378  {
379    var msg = '<ul>';
380    for (var i = 0; i < response.messages.length; i++)
381    {
382      var msgLine = response.messages[i];
383      if (msgLine.indexOf('[Warning]') >= 0)
384      {
385        msg += '<li class="warning">' + msgLine.replace('[Warning]', '');
386      }
387      else
388      {
389        msg += '<li>' + msgLine;
390      }
391    }
392    msg += '</ul>';
393    setInnerHTML('messages', msg);
394    Main.show('messages');
395  }
396 
397  if (response.status != 'ok')
398  {
399    Main.addClass(document.getElementById('messages'), 'failure');
400    setFatalError(response.message);
401    return false;
402  }
403
404  Main.show('gorestart');
405
406 
407}
408
409var currentFcNo;
410var currentLaneNo;
411function selectPool(event, fcNo, laneNo)
412{
413  currentFcNo = fcNo;
414  currentLaneNo = laneNo;
415 
416  // Reset 'current' selection
417  var menu = document.getElementById('select-pool');
418  var selectAll = document.getElementById('select-pool-all');
419  for (var i = 0; i <  selectAll.childNodes.length; i++)
420  {
421    Main.removeClass(selectAll.childNodes[i], 'current');
422  }
423  menu.style.display = 'block';
424 
425  var currentPool = flowCells[fcNo].pools[laneNo];
426  if (currentPool) Main.addClass(document.getElementById('pool-'+currentPool.id), 'current');
427
428  var x = event.clientX-90;
429  var halfHeight = Math.floor(selectAll.offsetHeight/2)
430  var y = event.clientY+2; //-halfHeight;
431
432  var scroll = 0;
433 
434  // Position the selection div
435  selectAll.scrollTop = scroll;
436  menu.style.left = (x)+'px';
437  menu.style.top = (y)+'px';
438  event.stopPropagation();
439}
440
441function poolSelected(event)
442{
443  var index = event.target.getAttribute('data-index');
444  var pool = selectedPools[index];
445  flowCells[currentFcNo].pools[currentLaneNo] = pool;
446  setInnerHTML('lane.'+currentLaneNo+'.'+currentFcNo, pool ? pool.name : '');
447  checkFlowCells();
448}
449
450</script>
451<style>
452#numSelected
453{
454  font-style: italic;
455  margin-top: 0.25em;
456  margin-left: 1em;
457}
458
459.well
460{
461  height: 2em;
462  max-height: 2em;
463  min-height: 2em;
464  width: 10em;
465  max-width: 10em;
466  min-width: 10em;
467  font-size: 100%;
468  text-align: center;
469  vertical-align: middle;
470}
471
472.hide-fc-1 .col-1
473{
474  display: none;
475}
476
477#select-pool-all
478{
479  max-height: 20em;
480  overflow: auto;
481}
482
483#select-pool .menuitem
484{
485  padding-left: 16px;
486}
487
488#select-pool div.current
489{
490  font-weight: bold;
491  background-image: url('../images/selected.gif');
492  background-position: 2px 50%;
493  background-repeat: no-repeat;
494}
495
496#select-pool .menuitem:hover
497{
498  padding-left: 14px;
499  background-position: 0px 50%;
500}
501
502</style>
503</base:head>
504<base:body onload="init()">
505
506  <p:path><p:pathelement 
507    title="Reggie" href="<%="../index.jsp?ID="+ID%>" 
508    /><p:pathelement title="Create flow cells" 
509    /></p:path>
510
511  <div class="content" onclick="Main.hide('select-pool')">
512  <%
513  if (sc.getActiveProjectId() == 0)
514  {
515    %>
516    <div class="messagecontainer note" style="width: 950px; margin-left: 20px; margin-bottom: 20px; margin-right: 0px; font-weight: bold; color: #cc0000;">
517      No project has been selected. You may proceed with the registration but
518      created items will not be shared.
519    </div>
520    <%
521  }
522  %>
523 
524  <div id="select-pool" class="menu vertical" style="width: 150px; display: none;"
525    onclick="poolSelected(event)">
526    <div id="select-pool-all"></div>
527  </div>
528
529  <form name="reggie" onsubmit="return false;">
530 
531  <div id="step.1.section" style="display: none;">
532  <table class="stepform">
533  <tr>
534    <td rowspan="3" class="stepno">1</td>
535    <td class="steptitle">Select pools</td>
536  </tr>
537  <tr>
538    <td class="stepfields">
539      <table>
540      <tr valign="top">
541        <td class="prompt">Flow cells</td>
542        <td class="input">
543          <label><input type="radio" name="num_flowcells" value="1">1</label>
544          <label><input type="radio" name="num_flowcells" value="2" checked>2</label>
545        </td>
546        <td class="status" id="numFlowCells.status"></td>
547        <td class="help"><span id="numFlowCells.message" class="message" style="display: none;"></span>
548          Select how many flow cells to create.
549        </td>
550      </tr>
551      <tr valign="top">
552        <td class="prompt">Lanes/flow cell</td>
553        <td class="input" id="lanes">
554          <label><input type="radio" name="num_lanes" value="2">2</label>
555          <label><input type="radio" name="num_lanes" value="8" checked>8</label>
556        </td>
557        <td class="status" id="lanes.status"></td>
558        <td class="help"><span id="lanes.message" class="message" style="display: none;"></span>
559          Select the number of lanes on each flow cell.
560        </td>
561      </tr>
562      <tr valign="top">
563        <td class="prompt">Pools</td>
564        <td class="input"><select style="width:90%;" size="6" 
565            name="pools" id="pools" multiple onchange="poolsOnChange()"></select>
566          <div id="numSelected"></div>
567          <base:buttongroup style="margin-top: 0.5em;">
568            <base:button title="Select manually&hellip;" onclick="selectPools()" id="btnSelectPools" />
569          </base:buttongroup>
570        </td>
571        <td class="status" id="pools.status"></td>
572        <td class="help"><span id="pools.message" class="message" style="display: none;"></span>
573          Select the pools that should be used in the flow cells. The list contain pools that has
574          not yet been used (determined by comparing remaining and original quantity).
575        </td>
576      </tr>
577      </table>
578    </td>
579  </tr>
580  </table>
581  </div>
582 
583  <div id="step.2.section" style="display: none;">
584  <table class="stepform">
585  <tr>
586    <td rowspan="3" class="stepno">2</td>
587    <td class="steptitle">Flow cell layout</td>
588  </tr>
589  <tr>
590    <td class="stepfields">
591
592      <table>
593      <tr valign="top">
594        <td class="prompt"></td>
595        <td class="input">
596          <table class="plate" id="plate" style="margin: 1em 0 1em 0;">
597          <tr class="header">
598            <th>Lane</th>
599            <%
600            for (int fcNo = 0; fcNo < 2; fcNo++)
601            {
602              %>
603              <th class="col-<%=fcNo%>" id="fc.<%=fcNo%>">FlowCell<%=fcNo%></th>
604              <%
605            }
606            %>
607          </tr>
608          <tbody>
609          <%
610          for (int laneNo = 0; laneNo < 8; laneNo++)
611          {
612            %>
613            <tr class="row-<%=laneNo%>" id="lane.<%=laneNo%>">
614              <th><%=laneNo+1%></th>
615              <%
616              for (int fcNo = 0; fcNo < 2; fcNo++)
617              {
618                %>
619                <td class="well col-<%=fcNo%>" id="lane.<%=laneNo%>.<%=fcNo%>" 
620                  onclick="selectPool(event, <%=fcNo%>, <%=laneNo%>)"></td>
621                <%
622              }
623              %>
624            </tr>
625            <%
626          }
627          %>
628          </tbody>
629          </table>
630       
631        </td>
632        <td class="status" id="flowCells.status"></td>
633        <td class="help"><span id="flowCells.message" class="message" style="display: none;"></span>
634          Assign a pool to each flow cell lane.
635        </td>
636      </tr>
637      </table>
638    </td>
639  </tr>
640  </table> 
641  </div>
642 
643  <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>
644 
645  <div class="messagecontainer error" id="errorMessage" style="display: none; width: 950px; margin-left: 20px; margin-bottom: 0px;"></div>
646 
647  <div id="messages" class="success" style="display: none; width: 950px; margin-left: 20px; margin-top: 20px;"></div>
648
649  <table style="margin-left: 20px; margin-top: 10px; display: none;" class="navigation" id="navigation">
650    <tr>
651      <td><base:button id="gocancel" title="Cancel" onclick="goRestart(false)" style="display: none;"/></td>
652      <td><base:button id="gonext" title="Next" image="<%=home+"/images/gonext.png"%>" onclick="goNext(true)"/></td>
653      <td><base:button id="goregister" title="Register" image="<%=home+"/images/import.png"%>" onclick="goRegister()" style="display: none;"/></td>
654      <td><base:button id="gorestart" title="Restart" image="<%=home+"/images/goback.png"%>" onclick="goRestart(true)" style="display: none;"/></td>
655      <td id="gonext.message" class="message"></td>
656    </tr>
657  </table>
658 
659  </form>
660  </div>
661 
662</base:body>
663</base:page>
664<%
665}
666finally
667{
668  if (dc != null) dc.close();
669}
670%>
Note: See TracBrowser for help on using the repository browser.