1 use CatalystX
::GlobalContext
qw( $c );
10 use CXGN::Page::FormattingHelpers qw( info_section_html
12 hierarchical_selectboxes_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";
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";
40 $page->header(('ITAG Pipeline Status Viewer') x
2);
42 #now load styles and javascript specific to this script
45 div#loading_indicator {
53 div#loading_indicator > img {
65 border-top: 1px solid black;
70 span.depends,span.produces, span.tagname, span.owner {
71 font-family: monospace;
75 border: 1px solid #888;
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>
86 my @pipelines = $itag_feature->list_pipelines;
88 <table id="viewer" align="center" cellspacing="0" width="100%" ><tr><td style="padding: 0.3em; background: #ccc;">
89 <form name="batch_selector">
91 .hierarchical_selectboxes_html
(
92 parentsel
=> { label
=> '<b>Pipeline version: </b>',
93 choices
=> \
@pipelines,
95 params
=> {onchange
=> qq|updateStatusContents
()|,
99 childsel
=> { label
=> '<b>Batch: </b>',
101 params
=> {onchange
=> qq|updateStatusContents
()|,
107 my $p = $itag_feature->pipeline( version
=> $_ );
108 [sort {$b+0 <=> $a+0} $p->list_batches]
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>
117 <tr><td id="pipestatus_contents" style="border: 2px solid #bbb; padding: 0.5em;">
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) {
137 refresh_button.disabled = disabled;
139 refresh_button.style.background = null;
141 refresh_button.style.background = refresh_bg;
145 var set_loading = function(is_on) {
147 loading_ind.style.visibility = 'visible';
148 controls_disabled(true);
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';
163 if( !batchsel.options.length ) {
164 batchsel.disabled = refresh_button.disabled = true;
165 contentarea.innerHTML = 'no batches available in pipeline ' + pipesel.value
171 var set = function(req) {
172 contentarea.innerHTML = req.responseText;
175 var err = function() {
176 contentarea.innerHTML = 'Error retrieving pipeline status';
179 var res = MochiKit.Async.doSimpleXMLHttpRequest( "status_html.pl",
182 batch: batchsel.value,
186 res.addCallbacks(set,err);
190 updateStatusContents();
199 ###################### SUBROUTINES ######################
201 #given a pipeline version and batch number, return a bunch of html showing its status
203 my ( $pipe, $batchnum ) = @_;
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
213 my %already_processed;
216 foreach my $an (@analyses) {
218 my @existing_dependencies = grep $existing_analyses{$_}, $an->dependencies;
219 if( all
@already_processed{ @existing_dependencies } ) {
220 push @ans_this_level, $an;
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
236 my $statuses = columnar_table_html
( headings
=> ['Status','Analysis Tag','Owner','Produces',],
239 __tableattrs
=> 'width="100%" summary="" cellspacing="0" align="center"',
243 (($rowcount++) ?
([('<hr class="depgroup" />')x4
]) : ()),
246 my $st = $an->status($batchnum);
247 my %t = ( ready
=> 'inputs ready',
248 not_ready
=> 'not ready',
250 my %c = ( ready
=> '#6666ff',
253 running
=> '#00ffff',
254 validating
=> '#dd00dd',
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;
263 my ($valname,$filename) = /^(\S+) validation failed for file (\S+),/
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
});
277 tagname
=> $an->tagname,
278 owner
=> qq|$name $owner_info->{email
}|,
279 produces
=> join(', ', $an->output_files_specs ),
283 $_->status($batchnum) ne 'disabled'
291 info_section_html
( title
=> 'Errors',
295 "<b>$_</b>$errstrings{$_}"
296 } sort keys %errstrings
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">',
309 (link_identifier
($_)||$_).'<br />'
314 my $seq_cnt = scalar @seqlist;
316 <table align="center" style="margin-bottom: 0.5em">
318 <td><b>Sequences ($seq_cnt)</b> $seqlist_html</td>
326 ########## UTILITY FUNCTIONS
328 sub obfuscate_email
{
330 my ($emailuser,$emaildomain) = split /@/, $email;
331 $emaildomain =~ s/\./ /g;
332 return "$emailuser _ $emaildomain";
337 while(my ($class,$html) = splice @_,0,2) {
338 push @ret,qq|<span
class="$class">$html</span
>|;