fix bp selenium test and brapi add program
[sgn.git] / cgi-bin / sequencing / itag / status_html.pl
blobf5540ad01f4be74c96071e4db121be7cd8e42743
1 use CatalystX::GlobalContext qw( $c );
2 use strict;
3 use warnings;
5 use File::Basename;
7 use JSON;
9 use CXGN::Page;
10 use CXGN::Page::FormattingHelpers qw( info_section_html
11 modesel
12 hierarchical_selectboxes_html
13 columnar_table_html
14 info_table_html
16 use CXGN::Tools::Identifiers qw/link_identifier/;
17 use CXGN::ITAG::Pipeline;
18 use CXGN::Tools::List qw/all/;
20 my $itag_feature = $c->enabled_feature('itag')
21 or $c->forward_to_mason_view('/itag/not_enabled.mas');
23 my $page = CXGN::Page->new('ITAG Pipeline Status Viewer','Robert Buels');
24 $page->jsan_use('MochiKit.Base','MochiKit.Async');
26 my ($mode,$pipe,$batch) = $page->get_encoded_arguments(qw( mode pipe batch ));
27 if( $mode && $mode eq 'async' ) {
28 $ENV{CXGNITAGPIPELINEANALYSISTESTING}=1 unless $c->get_conf('production_server');
29 my $pipe_obj = $itag_feature->pipeline( version => $pipe );
30 my $s = get_status( $pipe_obj, $batch+0 );
31 print "Content-type: text/html\n\n$s";
32 exit;
33 } elsif( $mode && $mode eq 'async_ainfo' ) {
34 my ($aname) = $page->get_encoded_arguments('aname');
35 my $ainfo = get_analysis_info($pipe,$aname);
36 print "Content-type: text/html\n\n$ainfo";
37 exit;
40 $page->header(('ITAG Pipeline Status Viewer') x 2);
42 #now load styles and javascript specific to this script
43 print <<EOHTML;
44 <style>
45 div#loading_indicator {
46 background: #eee;
47 font-weight: bold;
48 color: black;
49 padding: 3px;
50 display: inline;
51 visibility: hidden;
53 div#loading_indicator > img {
54 position: relative;
55 top: 2px;
58 ul.errlist {
59 margin-top: 0.1em;
60 max-height: 12em;
61 overflow: auto;
63 hr.depgroup {
64 border: 0;
65 border-top: 1px solid black;
67 span.owner {
68 white-space: nowrap;
70 span.depends,span.produces, span.tagname, span.owner {
71 font-family: monospace;
74 #viewer {
75 border: 1px solid #888;
78 </style>
79 EOHTML
81 print <<EOHTML;
82 <div style="margin-bottom: 1.5em;">This page provides continuously updated information on the running status of the <a href="http://www.ab.wur.nl/TomatoWiki">ITAG Distributed Annotation Pipeline</a>.</div>
83 EOHTML
86 my @pipelines = $itag_feature->list_pipelines;
87 print <<EOH
88 <table id="viewer" align="center" cellspacing="0" width="100%" ><tr><td style="padding: 0.3em; background: #ccc;">
89 <form name="batch_selector">
90 EOH
91 .hierarchical_selectboxes_html(
92 parentsel => { label => '<b>Pipeline version: </b>',
93 choices => \@pipelines,
94 name => 'pipever',
95 params => {onchange => qq|updateStatusContents()|,
97 selected => $pipe,
99 childsel => { label => '<b>Batch: </b>',
100 name => 'batchnum',
101 params => {onchange => qq|updateStatusContents()|,
103 selected => $batch,
105 childchoices => [
106 map {
107 my $p = $itag_feature->pipeline( version => $_ );
108 [sort {$b+0 <=> $a+0} $p->list_batches]
109 } @pipelines
112 .<<EOH
113 <input type="button" style="background: url(/documents/img/refresh.png); width: 22px; height: 21px" name="refresh" value="" onclick="this.blur(); updateStatusContents()" />
114 <div id="loading_indicator">Loading... <img src="/documents/img/spinner.gif" /></div>
115 </form>
116 </td></tr>
117 <tr><td id="pipestatus_contents" style="border: 2px solid #bbb; padding: 0.5em;">
118 </td></tr>
119 </table>
123 print <<EOS;
124 <script type="text/javascript">
125 var refresh_bg = document.batch_selector.refresh.style.background;
127 var updateStatusContents = function() {
128 var loading_ind = document.getElementById('loading_indicator');
130 var pipesel = document.batch_selector.pipever;
131 var batchsel = document.batch_selector.batchnum;
132 var refresh_button = document.batch_selector.refresh
134 var controls_disabled = function(disabled) {
135 pipesel.disabled =
136 batchsel.disabled =
137 refresh_button.disabled = disabled;
138 if( disabled ) {
139 refresh_button.style.background = null;
140 } else {
141 refresh_button.style.background = refresh_bg;
145 var set_loading = function(is_on) {
146 if(is_on) {
147 loading_ind.style.visibility = 'visible';
148 controls_disabled(true);
149 } else {
150 loading_ind.style.visibility = 'hidden';
151 controls_disabled(false);
155 var contentarea = document.getElementById('pipestatus_contents');
157 // don't update if we don't have any pipeline or batches
158 if( !pipesel.options.length ) {
159 controls_disabled(true);
160 contentarea.innerHTML = 'no pipelines available';
161 return;
163 if( !batchsel.options.length ) {
164 batchsel.disabled = refresh_button.disabled = true;
165 contentarea.innerHTML = 'no batches available in pipeline ' + pipesel.value
166 return;
169 set_loading(true);
171 var set = function(req) {
172 contentarea.innerHTML = req.responseText;
173 set_loading(false);
175 var err = function() {
176 contentarea.innerHTML = 'Error retrieving pipeline status';
177 set_loading(false);
179 var res = MochiKit.Async.doSimpleXMLHttpRequest( "status_html.pl",
180 { mode: 'async',
181 pipe: pipesel.value,
182 batch: batchsel.value,
183 t: Math.random()
186 res.addCallbacks(set,err);
190 updateStatusContents();
191 </script>
194 $page->footer;
199 ###################### SUBROUTINES ######################
201 #given a pipeline version and batch number, return a bunch of html showing its status
202 sub get_status {
203 my ( $pipe, $batchnum ) = @_;
205 my $retstring;
206 my $batch = $pipe->batch($batchnum);
207 my %errstrings; #< hash of tag name => error message
209 my @analyses = map { $pipe->analysis($_) } $pipe->list_analyses;
210 my %existing_analyses = map {$_->tagname =>1} @analyses;
211 #now sort the analyses by their dependencies
212 my @sorted_analyses;
213 my %already_processed;
214 while( @analyses ) {
215 my @ans_this_level;
216 foreach my $an (@analyses) {
217 next unless $an;
218 my @existing_dependencies = grep $existing_analyses{$_}, $an->dependencies;
219 if( all @already_processed{ @existing_dependencies } ) {
220 push @ans_this_level, $an;
221 $an = undef;
224 last unless @ans_this_level;
225 $already_processed{$_} = 1 foreach map {$_->tagname} @ans_this_level;
226 push @sorted_analyses,\@ans_this_level;
228 if( my @other_analyses = grep $_,@analyses ) {
229 push @sorted_analyses,\@other_analyses;
232 #now sorted_analyses is an array like ( [an,an,...], [an,an,...] ),
233 #where each set of analyses is dependent on the ones before it
235 my $rowcount = 0;
236 my $statuses = columnar_table_html( headings => ['Status','Analysis Tag','Owner','Produces',],
237 __alt_freq => 2,
238 #__align => 'cl',
239 __tableattrs => 'width="100%" summary="" cellspacing="0" align="center"',
240 data =>
242 map {
243 (($rowcount++) ? ([('<hr class="depgroup" />')x4]) : ()),
244 map {
245 my $an = $_;
246 my $st = $an->status($batchnum);
247 my %t = ( ready => 'inputs ready',
248 not_ready => 'not ready',
250 my %c = ( ready => '#6666ff',
251 error => '#ff0000',
252 done => '#00ff00',
253 running => '#00ffff',
254 validating => '#dd00dd',
256 my $c = $c{$st};
257 my $t = $t{$st} || $st;
258 if ($st eq 'error') {
259 my @errors = $an->errors($batchnum);
260 #TODO: MAKE THIS NOT BE SUCH A HACK
261 my $atag = $an->tagname;
262 foreach (@errors) {
263 my ($valname,$filename) = /^(\S+) validation failed for file (\S+),/
264 or next;
265 $_ =~ s|\[report file\]|<a href="report_download.pl?pipe=&batch=$batchnum&atag=$atag&filename=$filename&valname=$valname">report file</a>|;
267 $errstrings{$atag} = join '',map "<li>$_</li>",@errors;
268 $errstrings{$atag} &&= '<ul class="errlist">'.$errstrings{$atag}.'</ul>';
270 $st = $c ? qq|<div style="background: $c; padding: 2px 2em 2px 2em;">$t</div>| : $t;
271 my $owner_info = $an->owner_info;
272 my $name = $owner_info->{contact_name};
273 $name .= ',' if $name;
274 $owner_info->{email} = obfuscate_email($owner_info->{email});
275 [ mkspans(
276 status => $st,
277 tagname => $an->tagname,
278 owner => qq|$name $owner_info->{email}|,
279 produces => join(', ', $an->output_files_specs ),
282 } grep {
283 $_->status($batchnum) ne 'disabled'
284 } @$_
285 } @sorted_analyses
289 my $errs = do {
290 if(%errstrings) {
291 info_section_html( title => 'Errors',
292 contents =>
293 join('',
294 map {
295 "<b>$_</b>$errstrings{$_}"
296 } sort keys %errstrings
298 is_subsection => 1,
300 } else {
305 my @seqlist = sort $batch->seqlist;
306 my $seqlist_html = join('',
307 '<div style="height: 20em; width: 10em; overflow: auto; border: 1px solid #cccccc; padding: 6px">',
308 ( map {
309 (link_identifier($_)||$_).'<br />'
310 } @seqlist
312 '</div>',
314 my $seq_cnt = scalar @seqlist;
315 return <<EOH;
316 <table align="center" style="margin-bottom: 0.5em">
317 <tr>
318 <td><b>Sequences ($seq_cnt)</b> $seqlist_html</td>
319 <td>$statuses</td>
320 </tr>
321 </table>
322 $errs
326 ########## UTILITY FUNCTIONS
328 sub obfuscate_email {
329 my $email = shift;
330 my ($emailuser,$emaildomain) = split /@/, $email;
331 $emaildomain =~ s/\./ /g;
332 return "$emailuser _ $emaildomain";
335 sub mkspans(@) {
336 my @ret;
337 while(my ($class,$html) = splice @_,0,2) {
338 push @ret,qq|<span class="$class">$html</span>|;
340 return @ret;