Parent Directory
|
Revision Log
Revision 1.4 - (view) (download) (as text)
1 : | jared | 1.1 | package PRAST::WebPage::Jobs; |
2 : | |||
3 : | use strict; | ||
4 : | use warnings; | ||
5 : | |||
6 : | use base qw( WebPage ); | ||
7 : | |||
8 : | use WebComponent::WebGD; | ||
9 : | use RAST::MGRAST; | ||
10 : | use WebConfig; | ||
11 : | use Data::Dumper; | ||
12 : | |||
13 : | 1; | ||
14 : | |||
15 : | |||
16 : | =pod | ||
17 : | |||
18 : | =head1 NAME | ||
19 : | |||
20 : | Jobs - an instance of WebPage which displays an overview over all jobs | ||
21 : | |||
22 : | =head1 DESCRIPTION | ||
23 : | |||
24 : | Job overview page | ||
25 : | |||
26 : | =head1 METHODS | ||
27 : | |||
28 : | =over 4 | ||
29 : | |||
30 : | =item * B<init> () | ||
31 : | |||
32 : | Called when the web page is instanciated. | ||
33 : | |||
34 : | =cut | ||
35 : | |||
36 : | sub init { | ||
37 : | my $self = shift; | ||
38 : | |||
39 : | $self->title("Jobs Overview"); | ||
40 : | $self->application->register_component('Table', 'Jobs'); | ||
41 : | |||
42 : | |||
43 : | } | ||
44 : | |||
45 : | |||
46 : | =item * B<output> () | ||
47 : | |||
48 : | Returns the html output of the page. | ||
49 : | |||
50 : | =cut | ||
51 : | |||
52 : | sub output { | ||
53 : | my ($self) = @_; | ||
54 : | |||
55 : | my $content = '<h1>Jobs Overview</h1>'; | ||
56 : | |||
57 : | jared | 1.3 | $content .= '<p>The overview below list all genomes currently processed and the progress on the annotation. '. |
58 : | 'To get a more detailed report on an annotation job, please click on the progress bar graphic in the overview.</p>'; | ||
59 : | $content .= '<p>In case of questions or problems using this service, please contact: '.(($WebConfig::RAST_TYPE eq 'metagenome') ? '<a href="mailto:mg-rast@mcs.anl.gov">mg-rast@mcs.anl.gov</a>' : '<a href="mailto:rast@mcs.anl.gov">rast@mcs.anl.gov</a>').'.</p>'; | ||
60 : | jared | 1.1 | |
61 : | $content .= $self->get_color_key(); | ||
62 : | |||
63 : | $content .= '<h2>Jobs you have access to :</h2>'; | ||
64 : | |||
65 : | my $data = []; | ||
66 : | my @job_list; | ||
67 : | my $users; | ||
68 : | my $pjobs; | ||
69 : | my %admins; | ||
70 : | |||
71 : | eval { | ||
72 : | |||
73 : | @job_list = $self->app->data_handle('RAST')->Job->get_jobs_for_user_fast($self->application->session->user); | ||
74 : | |||
75 : | # | ||
76 : | # Gather the user ids from the job list, and query for them. | ||
77 : | # | ||
78 : | |||
79 : | my $udbh = $self->application->session->user->_master->db_handle; | ||
80 : | |||
81 : | my %users = map { $_->{owner} => 1 } @job_list; | ||
82 : | |||
83 : | if (scalar(keys(%users))) { | ||
84 : | my $user_cond = join(", ", keys %users); | ||
85 : | $users = $udbh->selectall_hashref(qq(SELECT _id, firstname, lastname, email | ||
86 : | FROM User | ||
87 : | WHERE _id IN ($user_cond)), '_id'); | ||
88 : | |||
89 : | # | ||
90 : | # Create display names for users, with email addresses if we're an admin. | ||
91 : | # | ||
92 : | |||
93 : | my $user = $self->app->session->user; | ||
94 : | my $app = $self->application->backend; | ||
95 : | |||
96 : | for my $val (values (%$users)) | ||
97 : | { | ||
98 : | if ( $val->{email} and $user and $user->is_admin($app) ) | ||
99 : | { | ||
100 : | $val->{name_display} = qq(<a href="mailto:$val->{email}, mg-rast\@mcs.anl.gov">$val->{lastname}, $val->{firstname}</a>); | ||
101 : | } else { | ||
102 : | $val->{name_display} = "$val->{lastname}, $val->{firstname}"; | ||
103 : | |||
104 : | } | ||
105 : | } | ||
106 : | |||
107 : | if ($WebConfig::RAST_TYPE eq 'metagenome'){ | ||
108 : | $pjobs = RAST::MGRAST::get_public_metagenomes($self->application->dbmaster); | ||
109 : | } | ||
110 : | } else { | ||
111 : | @job_list = (); | ||
112 : | } | ||
113 : | }; | ||
114 : | |||
115 : | if (ref $pjobs and scalar (@$pjobs) ){ | ||
116 : | $content .= "<p>You currently have access to ".scalar @$pjobs." public jobs.</p>"; | ||
117 : | } | ||
118 : | elsif ($WebConfig::RAST_TYPE eq 'metagenome'){ | ||
119 : | $content .= "<p>There are no public jobs.</p>"; | ||
120 : | } | ||
121 : | |||
122 : | my $user = $self->app->session->user->_id; | ||
123 : | my $is_admin = $admins{$user}; | ||
124 : | |||
125 : | if (scalar(@job_list)) { | ||
126 : | @job_list = sort { $b->{id} <=> $a->{id} } @job_list; | ||
127 : | foreach my $job (@job_list) { | ||
128 : | push @$data, $self->genome_entry_fast($job, $users, $is_admin); | ||
129 : | } | ||
130 : | # create table | ||
131 : | my $table = $self->application->component('Jobs'); | ||
132 : | $table->width(800); | ||
133 : | if (scalar(@$data) > 50) { | ||
134 : | $table->show_top_browse(1); | ||
135 : | $table->show_bottom_browse(1); | ||
136 : | $table->items_per_page(50); | ||
137 : | $table->show_select_items_per_page(1); | ||
138 : | } | ||
139 : | $table->columns([ { name => 'Job', filter => 1, sortable => 1 }, | ||
140 : | paczian | 1.4 | { name => 'Owner', filter => 1, sortable => 1 }, |
141 : | { name => 'ID', filter => 1, sortable => 1 }, | ||
142 : | { name => 'Name', filter => 1, sortable => 1 }, | ||
143 : | { name => 'Num contigs', sortable => 1 }, | ||
144 : | { name => 'Size (bp)', sortable => 1 }, | ||
145 : | { name => 'Creation Date' }, | ||
146 : | { name => 'Annotation Progress' }, | ||
147 : | { name => 'Current Stage', filter => 1, operator => 'combobox' } | ||
148 : | ]); | ||
149 : | jared | 1.1 | $table->data($data); |
150 : | $content .= $table->output(); | ||
151 : | } | ||
152 : | else { | ||
153 : | $content .= "<p>You currently have no jobs.</p>"; | ||
154 : | $content .= "<p> » <a href='?page=Upload'>Upload a new genome</a></p>"; | ||
155 : | } | ||
156 : | |||
157 : | return $content; | ||
158 : | } | ||
159 : | |||
160 : | sub output_old { | ||
161 : | my ($self) = @_; | ||
162 : | |||
163 : | my $content = '<h1>Jobs Overview</h1>'; | ||
164 : | |||
165 : | $content .= '<p>The overview below list all genomes currently processed and the progress on the annotation. '. | ||
166 : | 'To get a more detailed report on an annotation job, please click on the progress bar graphic in the overview.</p>'; | ||
167 : | $content .= '<p>In case of questions or problems using this service, please contact: '.(($WebConfig::RAST_TYPE eq 'metagenome') ? '<a href="mailto:mg-rast@mcs.anl.gov">mg-rast@mcs.anl.gov</a>' : '<a href="mailto:rast@mcs.anl.gov">rast@mcs.anl.gov</a>').'.</p>'; | ||
168 : | |||
169 : | $content .= $self->get_color_key(); | ||
170 : | |||
171 : | $content .= '<h2>Jobs you have access to :</h2>'; | ||
172 : | |||
173 : | my $data = []; | ||
174 : | my $jobs; | ||
175 : | my $pjobs; | ||
176 : | eval { | ||
177 : | $jobs = $self->app->data_handle('RAST')->Job->get_jobs_for_user($self->application->session->user); | ||
178 : | if ($WebConfig::RAST_TYPE eq 'metagenome'){ | ||
179 : | $pjobs = RAST::MGRAST::get_public_metagenomes($self->application->dbmaster); | ||
180 : | } | ||
181 : | }; | ||
182 : | unless (defined $jobs) { | ||
183 : | $self->app->error("Unable to retrieve the job overview."); | ||
184 : | return ''; | ||
185 : | } | ||
186 : | if (ref $pjobs and scalar (@$pjobs) ){ | ||
187 : | $content .= "<p>You currently have access to ".scalar @$pjobs." public jobs.</p>"; | ||
188 : | } | ||
189 : | elsif ($WebConfig::RAST_TYPE eq 'metagenome'){ | ||
190 : | $content .= "<p>There are no public jobs.</p>"; | ||
191 : | } | ||
192 : | |||
193 : | if (scalar(@$jobs)) { | ||
194 : | $jobs->[0]->resolve('owner', $jobs); | ||
195 : | @$jobs = sort { $b->id <=> $a->id } @$jobs; | ||
196 : | foreach my $job (@$jobs) { | ||
197 : | push @$data, $self->genome_entry($job); | ||
198 : | } | ||
199 : | # create table | ||
200 : | my $table = $self->application->component('Jobs'); | ||
201 : | $table->width(800); | ||
202 : | if (scalar(@$data) > 50) { | ||
203 : | $table->show_top_browse(1); | ||
204 : | $table->show_bottom_browse(1); | ||
205 : | $table->items_per_page(50); | ||
206 : | $table->show_select_items_per_page(1); | ||
207 : | } | ||
208 : | $table->columns([ { name => 'Job', filter => 1, sortable => 1 }, | ||
209 : | { name => 'Owner', filter => 1, }, | ||
210 : | { name => 'ID', filter => 1 }, | ||
211 : | { name => 'Name', filter => 1 }, | ||
212 : | { name => 'Size (bp)', sortable => 1 }, | ||
213 : | { name => 'Creation Date' }, | ||
214 : | { name => 'Annotation Progress' }, | ||
215 : | ]); | ||
216 : | $table->data($data); | ||
217 : | $content .= $table->output(); | ||
218 : | } | ||
219 : | else { | ||
220 : | $content .= "<p>You currently have no jobs.</p>"; | ||
221 : | $content .= "<p> » <a href='?page=Upload'>Upload a new genome</a></p>"; | ||
222 : | } | ||
223 : | |||
224 : | return $content; | ||
225 : | } | ||
226 : | |||
227 : | |||
228 : | =pod | ||
229 : | |||
230 : | =item * B<genome_entry> (I<job>) | ||
231 : | |||
232 : | Returns one entry row for the overview table, containing job id, user, | ||
233 : | genome info and the progress bar graphic. I<job> has to be the reference | ||
234 : | to a RAST::Job object. | ||
235 : | |||
236 : | =cut | ||
237 : | |||
238 : | sub genome_entry_fast { | ||
239 : | my ($self, $job, $users, $is_admin) = @_; | ||
240 : | |||
241 : | my $stages; | ||
242 : | if ($job->{type} eq 'Metagenome') | ||
243 : | { | ||
244 : | $stages = $job->{server_version} == 1 ? RAST::Job::stages_for_mgrast_1() : RAST::Job::stages_for_mgrast_(); | ||
245 : | } | ||
246 : | else | ||
247 : | { | ||
248 : | jared | 1.3 | print STDERR "attempting PRAST::Job::stages_for_prast()\n"; |
249 : | arodri7 | 1.2 | $stages = PRAST::Job::stages_for_prast(); |
250 : | jared | 1.1 | } |
251 : | |||
252 : | # create a new image | ||
253 : | my $height = 14; my $box_width = 12; | ||
254 : | my $image = WebGD->new(scalar(@$stages)*$box_width,$height); | ||
255 : | |||
256 : | # allocate some colors | ||
257 : | my $colors = $self->get_colors($image); | ||
258 : | |||
259 : | # make the background transparent and interlaced | ||
260 : | $image->transparent($colors->{'white'}); | ||
261 : | $image->interlaced('true'); | ||
262 : | my $info = ''; | ||
263 : | |||
264 : | my $index = 0; | ||
265 : | paczian | 1.4 | my $cs = ''; |
266 : | jared | 1.1 | foreach my $stage (@$stages) |
267 : | { | ||
268 : | my $s = $job->{status}->{$stage}; | ||
269 : | my $status = $s ne '' ? $s : 'not_started'; | ||
270 : | if (exists($colors->{$status})) { | ||
271 : | $image->filledRectangle($index*$box_width,0,10+$index*$box_width,$height,$colors->{$status}); | ||
272 : | } | ||
273 : | else { | ||
274 : | die "Found unknown status for stage '$stage' in job ".$job->{id}."\n"; | ||
275 : | } | ||
276 : | |||
277 : | if ($status ne 'not_started') { | ||
278 : | $status =~ s/_/ /g; | ||
279 : | paczian | 1.4 | $cs = $status; |
280 : | jared | 1.1 | my $steps = $index + 1; |
281 : | $info = "$steps of ".scalar(@$stages)." steps, current step: $status "; | ||
282 : | } | ||
283 : | $index++; | ||
284 : | } | ||
285 : | |||
286 : | my $id = $job->{id}; | ||
287 : | my $progress = '<img style="border: none;" src="'.$image->image_src.'"/>'; | ||
288 : | my $link_img = "<a title='$info' href='?page=JobDetails&job=".$id."'>$progress</a>"; | ||
289 : | my $link_text = "[ <a href='?page=JobDetails&job=".$id."'><em> view details </em></a> ]"; | ||
290 : | |||
291 : | my $owner = $users->{$job->{owner}}; | ||
292 : | |||
293 : | my $creation_date = $job->{created_on}; | ||
294 : | #my $size = $job->metaxml->get_metadata('preprocess.count_raw.total') || 0; | ||
295 : | my $size = $job->{bp_count}; | ||
296 : | |||
297 : | return [ $job->{id}, $owner->{name_display}, $job->{genome_id}, $job->{genome_name}, | ||
298 : | paczian | 1.4 | $job->{contig_count}, $size, $creation_date, $link_img.'<br/>'.$link_text, $cs ]; |
299 : | jared | 1.1 | } |
300 : | |||
301 : | sub genome_entry { | ||
302 : | my ($self, $job) = @_; | ||
303 : | |||
304 : | # create a new image | ||
305 : | my $height = 14; my $box_width = 12; | ||
306 : | my $image = WebGD->new(scalar(@{$job->stages})*$box_width,$height); | ||
307 : | |||
308 : | # allocate some colors | ||
309 : | my $colors = $self->get_colors($image); | ||
310 : | |||
311 : | # make the background transparent and interlaced | ||
312 : | $image->transparent($colors->{'white'}); | ||
313 : | $image->interlaced('true'); | ||
314 : | my $info = ''; | ||
315 : | |||
316 : | my $index = 0; | ||
317 : | foreach my $stage (@{$job->stages}) { | ||
318 : | my $s = $job->status($stage); | ||
319 : | my $status = (ref $s) ? $s->status : 'not_started'; | ||
320 : | if (exists($colors->{$status})) { | ||
321 : | $image->filledRectangle($index*$box_width,0,10+$index*$box_width,$height,$colors->{$status}); | ||
322 : | } | ||
323 : | else { | ||
324 : | die "Found unknown status for stage '$stage' in job ".$job->id."\n"; | ||
325 : | } | ||
326 : | |||
327 : | if ($status ne 'not_started') { | ||
328 : | $status =~ s/_/ /g; | ||
329 : | my $steps = $index + 1; | ||
330 : | $info = "$steps of ".scalar(@{$job->stages})." steps, current step: $status "; | ||
331 : | } | ||
332 : | $index++; | ||
333 : | } | ||
334 : | |||
335 : | my $progress = '<img style="border: none;" src="'.$image->image_src.'"/>'; | ||
336 : | my $link_img = "<a title='$info' href='?page=JobDetails&job=".$job->id."'>$progress</a>"; | ||
337 : | my $link_text = "[ <a href='?page=JobDetails&job=".$job->id."'><em> view details </em></a> ]"; | ||
338 : | my $email = $job->owner->email if (ref $job->owner); | ||
339 : | my $firstname = $job->owner->firstname if (ref $job->owner); | ||
340 : | my $lastname = $job->owner->lastname if (ref $job->owner); | ||
341 : | |||
342 : | my $name_display; | ||
343 : | |||
344 : | my $user = $self->app->session->user; | ||
345 : | my $app = $self->application->backend; | ||
346 : | |||
347 : | if ( $firstname and $lastname ) { | ||
348 : | if ( $email and $user and $user->is_admin($app) ) { | ||
349 : | $name_display = qq(<a href="mailto:$email, mg-rast\@mcs.anl.gov">$lastname, $firstname</a>); | ||
350 : | } else { | ||
351 : | $name_display = "$lastname, $firstname"; | ||
352 : | } | ||
353 : | } else { | ||
354 : | $name_display = 'unknown'; | ||
355 : | } | ||
356 : | |||
357 : | my $creation_date = $job->created_on; | ||
358 : | my $size = 0; | ||
359 : | if ($WebConfig::RAST_TYPE eq 'metagenome') | ||
360 : | { | ||
361 : | $size = $job->metaxml->get_metadata('preprocess.count_raw.total') || 0; | ||
362 : | } | ||
363 : | |||
364 : | return [ $job->id, $name_display, $job->genome_id, $job->genome_name, $size, $creation_date, $link_img.'<br/>'.$link_text ]; | ||
365 : | } | ||
366 : | |||
367 : | =pod | ||
368 : | |||
369 : | =item * B<get_color_key> () | ||
370 : | |||
371 : | Returns the html of the color key used in the progress bars. | ||
372 : | |||
373 : | =cut | ||
374 : | |||
375 : | sub get_color_key { | ||
376 : | my ($self) = @_; | ||
377 : | |||
378 : | my $keys = [ [ 'not_started', 'not started' ], | ||
379 : | [ 'queued', 'queued for computation' ], | ||
380 : | [ 'in_progress', 'in progress' ], | ||
381 : | [ 'requires_intervention' => 'requires user input' ], | ||
382 : | [ 'error', 'failed with an error' ], | ||
383 : | [ 'complete', 'successfully completed' ] ]; | ||
384 : | |||
385 : | my $html = "<h4>Progress bar color key:</h4>"; | ||
386 : | foreach my $k (@$keys) { | ||
387 : | |||
388 : | my $image = WebGD->new(10, 14); | ||
389 : | my $colors = $self->get_colors($image); | ||
390 : | $image->filledRectangle(0,0,10,14,$colors->{$k->[0]}); | ||
391 : | $html .= '<img style="border: none;" src="'.$image->image_src.'"/> '.$k->[1].'<br>'; | ||
392 : | |||
393 : | } | ||
394 : | |||
395 : | return $html; | ||
396 : | } | ||
397 : | |||
398 : | |||
399 : | =pod | ||
400 : | |||
401 : | =item * B<get_colors> (I<gd_image>) | ||
402 : | |||
403 : | Returns the reference to the hash of allocated colors. I<gd_image> is mandatory and | ||
404 : | has to be a GD Image object reference. | ||
405 : | |||
406 : | =cut | ||
407 : | |||
408 : | sub get_colors { | ||
409 : | my ($self, $image) = @_; | ||
410 : | return { 'white' => $image->colorResolve(255,255,255), | ||
411 : | 'black' => $image->colorResolve(0,0,0), | ||
412 : | 'not_started' => $image->colorResolve(185,185,185), | ||
413 : | 'queued' => $image->colorResolve(30,120,220), | ||
414 : | 'in_progress' => $image->colorResolve(255,190,30), | ||
415 : | 'requires_intervention' => $image->colorResolve(255,30,30), | ||
416 : | 'error' => $image->colorResolve(175,45,45), | ||
417 : | 'complete' => $image->colorResolve(60,165,60), | ||
418 : | }; | ||
419 : | } | ||
420 : | |||
421 : | |||
422 : | =pod | ||
423 : | |||
424 : | =item * B<required_rights>() | ||
425 : | |||
426 : | Returns a reference to the array of required rights | ||
427 : | |||
428 : | =cut | ||
429 : | |||
430 : | sub required_rights { | ||
431 : | return [ [ 'login' ], | ||
432 : | ]; | ||
433 : | } |
MCS Webmaster | ViewVC Help |
Powered by ViewVC 1.0.3 |