c776c82746c3fc8660039ba4a747b12c5824930a
[clearscm.git] / clearadm / lib / ClearadmWeb.pm
1 =pod
2
3 =head1 NAME $RCSfile: ClearadmWeb.pm,v $
4
5 Common routines for the web portion of Clearadm
6
7 =head1 VERSION
8
9 =over
10
11 =item Author
12
13 Andrew DeFaria <Andrew@ClearSCM.com>
14
15 =item Revision
16
17 $Revision: 1.46 $
18
19 =item Created
20
21 Sat Dec 18 08:43:27 EST 2010
22
23 =item Modified
24
25 $Date: 2011/12/26 19:00:58 $
26
27 =back
28
29 =head1 SYNOPSIS
30
31 This module holds common web routines for the web portion of Clearadm.
32
33 =head1 DESCRIPTION
34
35 To be filled out.
36
37 =head1 ROUTINES
38
39 The following routines are exported:
40
41 =cut
42
43 package ClearadmWeb;
44
45 use warnings;
46 use strict;
47
48 use base 'Exporter';
49
50 use CGI qw (
51   :standard
52    start_a
53    end_a
54    start_div
55    end_div
56    start_li
57    end_li
58    start_table
59    end_table
60    start_td
61    end_td
62    start_Tr
63    end_Tr
64    start_ul
65    end_ul
66 );
67
68 use Carp;
69 use File::Basename;
70
71 use FindBin;
72
73 use lib "$FindBin::Bin/../../lib";
74
75 use Clearadm;
76 use Clearcase::Vobs;
77 use Clearcase::Views;
78 use DateUtils;
79 use Display;
80 use Utils;
81
82 my $clearadm = Clearadm->new;
83
84 our $APPNAME= 'Clearadm';
85 our $VERSION  = '$Revision: 1.46 $';
86    ($VERSION) = ($VERSION =~ /\$Revision: (.*) /);
87
88 our @EXPORT = qw (
89   autoScale
90   displayError
91   displayAlert
92   displayAlertlog
93   displayFilesystem
94   displayNotification
95   displayRunlog
96   displaySchedule
97   displaySystem
98   displayTask
99   dbug
100   dumpVars
101   editAlert
102   editFilesystem
103   editNotification
104   editSchedule
105   editSystem
106   editTask
107   footing
108   graphError
109   heading
110   makeAlertDropdown
111   makeFilesystemDropdown
112   makeIntervalDropdown
113   makeNotificationDropdown
114   makeStoragePoolDropdown
115   makeSystemDropdown
116   makeTagsDropdown
117   makeTimeDropdown
118   makeTaskDropdown
119   setField
120   setFields
121 );
122
123 our @PREDEFINED_ALERTS = (
124   'Email admin',
125 );
126
127 our @PREDEFINED_NOTIFICATIONS = (
128   'Clearcase Storage',
129   'Heartbeat',
130   'Loadavg',
131   'Filesystem',
132   'Scrub',
133   'System checkin',
134   'Update systems',
135 );
136
137 our @PREDEFINED_TASKS = (
138   'Clearcase Storage',
139   'Filesystem',
140   'Loadavg',
141   'Scrub',
142   'System checkin',
143   'Update systems',
144 );
145
146 our @PREDEFINED_SCHEDULES = (
147   'Clearcase Storage',
148   'Filesystem',
149   'Loadavg',
150   'Scrub',
151   'Update systems',
152 );
153
154 our @PREDEFINED_NOTMORETHAN = (
155   'Once an hour',
156   'Once a day',
157   'Once a week',
158   'Once a month',
159 );
160
161 our @PREDEFINED_MULTIPLIERS = (
162   'Seconds',
163   'Minutes',
164   'Hours',
165   'Days',
166 );
167
168 sub dbug ($) {
169   my ($msg) = @_;
170
171   display font ({-class => 'error'}, '<br>DEBUG: '). $msg;
172
173   return;
174 } # dbug
175
176 sub displayError ($) {
177   my ($msg) = @_;
178
179   display font ({-class => 'error'}, 'Error: ') . $msg;
180
181   return
182 } # displayError;
183
184 sub setField ($;$) {
185   my ($field, $label) = @_;
186
187   $label ||= 'Unknown';
188
189   my $undef = font {-class => 'unknown'}, $label;
190
191   return defined $field ? $field : $undef;
192 } # setField
193
194 sub setFields ($%) {
195   my ($label, %rec) = @_;
196
197   $rec{$_} = setField ($rec{$_}, $label)
198     for keys %rec;
199
200   return %rec;
201 } # setFields;
202
203 sub dumpVars (%) {
204   my (%vars) = @_;
205
206   for (keys %vars) {
207     dbug "$_: $vars{$_}";
208   } # for
209
210   return;
211 } # dumpVars
212
213 sub graphError ($) {
214   my ($msg) = @_;
215
216   use GD;
217
218   # Make the image fit the message. It seems that characters are ~ 7px wide.
219   my $imageLength = length ($msg) * 7;
220
221   my $errorImage = GD::Image->new ($imageLength, 20);
222
223   # Allocate some colors
224   my $white = $errorImage->colorAllocate (255, 255, 255);
225   my $red   = $errorImage->colorAllocate (255, 0, 0);
226
227   # Allow the text to shine through
228   $errorImage->transparent($white);
229   $errorImage->interlaced('true');
230
231   # Now put out the message
232   $errorImage->string (gdMediumBoldFont, 0, 0, $msg, $red);
233
234   # And return it
235   print "Content-type: image/png\n\n";
236   print $errorImage->png;
237
238   # Since we've "returned" the error in the form of an image, there's nothing
239   # left for us to do so we can exit
240   exit;
241 } # graphError
242
243 sub autoScale ($) {
244   my ($amount) = @_;
245
246   my $kbyte = 1024;
247   my $meg   = (1024 * $kbyte);
248   my $gig   = (1024 * $meg);
249
250   my $size = $amount > $gig
251            ? sprintf ('%.2f Gig',   $amount / $gig)
252            : $amount > $meg
253            ? sprintf ('%.2f Meg',   $amount / $meg)
254            : sprintf ('%.2f Kbyte', $amount / $kbyte);
255
256   return $size;
257 } # autoScale
258
259 sub _makeAlertlogSelection ($$) {
260   my ($name, $default) = @_;
261
262   $default ||= 'All';
263
264   my %values;
265
266   $values{All} = 'All';
267
268   $values{$$_{$name}} = $$_{$name}
269     for ($clearadm->FindAlertlog);
270
271   my $dropdown = popup_menu {
272     name    => $name,
273     class   => 'dropdown',
274     values  => [sort keys %values],
275     default => $default,
276   };
277
278   return $dropdown;
279 } # _makeAlertlogSelection
280
281 sub _makeRunlogSelection ($$) {
282   my ($name, $default) = @_;
283
284   $default ||= 'All';
285
286   my @values = sort $clearadm->GetUniqueList ('runlog', $name);
287
288   unshift @values, 'All';
289
290   my %values;
291
292   for (@values) {
293      unless ($_ eq '') {
294        $values{$_} = $_;
295      } else {
296        $values{NULL} = '<NULL>';
297      } #if
298   } # for
299
300   my $dropdown = popup_menu {
301     name    => $name,
302     class   => 'dropdown',
303     values  => \@values,
304     default => $default,
305     labels  => \%values,
306   };
307
308   return $dropdown;
309 } # _makeRunlogSelection
310
311 sub _makeRunlogSelectionNumeric ($$) {
312   my ($name, $default) = @_;
313
314   $default ||= 'All';
315
316   my @values = sort {$a <=> $b} $clearadm->GetUniqueList ('runlog', $name);
317
318   unshift @values, 'All';
319
320   my $dropdown = popup_menu {
321     name    => $name,
322     class   => 'dropdown',
323     values  => [@values],
324     default => $default,
325   };
326
327   return $dropdown;
328 } # _makeRunlogSelection
329
330 sub makeAlertDropdown (;$$) {
331   my ($label, $default) = @_;
332
333   $label ||= '';
334
335   my @values;
336
337   push @values, $$_{name}
338     for ($clearadm->FindAlert);
339
340   my $dropdown  = "$label ";
341      $dropdown .= popup_menu {
342     name    => 'alert',
343     class   => 'dropdown',
344     values  => [sort @values],
345     default => $default,
346   };
347
348   return $dropdown;
349 } # makeAlertDropdown
350
351 sub makeMultiplierDropdown (;$$) {
352   my ($label, $default) = @_;
353
354   $label ||= '';
355
356   my $dropdown  = "$label ";
357      $dropdown .= popup_menu {
358     name    => 'multiplier',
359     class   => 'dropdown',
360     values  => [sort @PREDEFINED_MULTIPLIERS],
361     default => $default,
362   };
363
364   return $dropdown;
365 } # makeMultiplierDropdown
366
367 sub makeNoMoreThanDropdown (;$$) {
368   my ($label, $default) = @_;
369
370   $label ||= '';
371
372   my $dropdown  = "$label ";
373      $dropdown .= popup_menu {
374     name    => 'nomorethan',
375     class   => 'dropdown',
376     values  => [sort @PREDEFINED_NOTMORETHAN],
377     default => $default,
378   };
379
380   return $dropdown;
381 } # makeNoMorThanDropdown
382
383 sub makeTagsDropdown($$) {
384   my ($type, $tag) = @_;
385
386   my $dropdown = ucfirst $type . ' ';
387
388   if ($type eq 'vob') {
389     my $vobs = Clearcase::Vobs->new;
390
391     $dropdown .= popup_menu {
392       name    => 'tag',
393       class   => 'dropdown',
394       values  => [sort $vobs->vobs],
395       default => $tag,
396     }; 
397   } else {
398     my $views = Clearcase::Views->new;
399
400     $dropdown .= popup_menu {
401       name    => 'tag',
402       class   => 'dropdown',
403       values  => [sort $views->views],
404       default => $tag,
405     };
406   } # if
407       
408   return span {id => $type}, $dropdown;
409 } # makeTagsDropdown
410
411 sub makeStoragePoolDropdown($$) {
412   my ($type, $tag) = @_;
413
414   my @values;
415
416   my $dropdown = 'Storage pool  ';
417     
418   if ($type eq 'vob') {
419     push @values, qw(admin db cleartext derivedobj source total);
420   } else {
421     push @values, qw(admin db private total);
422   } # if
423
424   $dropdown .= popup_menu {
425     name    => 'storage',
426     class   => 'dropdown',
427     values  => \@values,
428     default => $tag,
429   };
430
431   return span {id => $type}, $dropdown;
432 } # makeStoragePoolsDropdown
433     
434 sub makeFilesystemDropdown ($;$$$) {
435   my ($system, $label, $default, $onchange) = @_;
436
437   $label ||= '';
438
439   my %filesystems;
440
441   for ($clearadm->FindFilesystem ($system)) {
442     my %filesystem = %{$_};
443
444     my $value = "$filesystem{filesystem} ($filesystem{mount})";
445
446     $filesystems{$filesystem{filesystem}} = $value;
447   } # for
448
449   my $dropdown .= "$label ";
450      $dropdown .= popup_menu {
451     name     => 'filesystem',
452     class    => 'dropdown',
453     values   => [sort keys %filesystems],
454     labels   => \%filesystems,
455     onChange => ($onchange) ? $onchange : '',
456     default  => $default,
457   };
458
459   return span {id => 'filesystems'}, $dropdown;
460 } # makeFilesystemDropdown
461
462 sub makeIntervalDropdown (;$$$) {
463   my ($label, $default, $onchange) = @_;
464
465   $label ||= '';
466
467   my @intervals = (
468     'Minute',
469     'Hour',
470     'Day',
471     'Month',
472   );
473
474   $default = ucfirst lc $default
475     if $default;
476
477   my $dropdown  = "$label ";
478      $dropdown .= popup_menu {
479     name     => 'scaling',
480     id       => 'scalingFactor',
481     class    => 'dropdown',
482     values   => [@intervals],
483     default  => $default,
484     onchange => $onchange,
485   };
486
487    return span {id => 'scaling'}, $dropdown;
488 } # makeIntervalDropdown;
489
490 sub makeNotificationDropdown (;$$) {
491   my ($label, $default) = @_;
492
493   $label ||= '';
494
495   my @values;
496
497   push @values, $$_{name}
498     for ($clearadm->FindNotification);
499
500   my $dropdown  = "$label ";
501      $dropdown .= popup_menu {
502     name    => 'notification',
503     class   => 'dropdown',
504     values  => [sort @values],
505     default => $default,
506   };
507
508   return $dropdown;
509 } # makeNotificationDropdown
510
511 sub makeRestartableDropdown (;$$) {
512   my ($label, $default) = @_;
513
514   $label ||= '';
515
516   my @values = (
517     'true',
518     'false',
519   );
520
521   my $dropdown  = "$label ";
522      $dropdown .= popup_menu {
523     name    => 'restartable',
524     class   => 'dropdown',
525     values  => [@values],
526     default => $default,
527   };
528
529   return $dropdown;
530 } # makeRestartableDropdown
531
532 sub makeSystemDropdown (;$$$%) {
533   my ($label, $default, $onchange, %systems) = @_;
534
535   $label ||= '';
536
537   for ($clearadm->FindSystem) {
538     my %system = %{$_};
539
540     my $value  = $system{name};
541        $value .= $system{alias} ? " ($system{alias})" : '';
542
543     $systems{$system{name}} = $value;
544   } # for
545
546   my $systemDropdown .= "$label ";
547      $systemDropdown .= popup_menu {
548        name     => 'system',
549        class    => 'dropdown',
550        values   => [sort keys %systems],
551        labels   => \%systems,
552        onchange => ($onchange) ? $onchange : '',
553        default  => $default,
554     };
555
556   return span {id => 'systems'}, $systemDropdown;
557 } # makeSystemDropdown
558
559 sub makeTaskDropdown (;$$) {
560   my ($label, $default) = @_;
561
562   $label ||= '';
563
564   my @values;
565
566   push @values, $$_{name}
567     for ($clearadm->FindTask);
568
569   my $taskDropdown  = "$label ";
570      $taskDropdown .= popup_menu {
571     name    => 'task',
572     class   => 'dropdown',
573     values  => [sort @values],
574     default => $default,
575   };
576
577   return $taskDropdown;
578 } # makeTaskDropdown
579
580 sub makeTimeDropdown ($$$;$$$$$) {
581   my (
582     $table,
583     $elementID,
584     $system,
585     $filesystem,
586     $label,
587     $default,
588     $interval,
589     $name,
590   ) = @_;
591
592   $label ||= '';
593
594   my @times;
595
596   $name ||= lc $label;
597
598   push @times, 'Earliest';
599
600   if ($table =~ /loadavg/i) {
601     push @times, $$_{timestamp}
602       for ($clearadm->GetLoadavg ($system, undef, undef, undef, $interval));
603   } elsif ($table =~ /filesystem/i) {
604     push @times, $$_{timestamp}
605       for ($clearadm->GetFS ($system, $filesystem, undef, undef, undef, $interval));
606   } # if
607
608   push @times, 'Latest';
609
610   unless ($default) {
611     $default = $name eq 'start' ? 'Earliest' : 'Latest';
612   } # unless
613
614   my $timeDropdown = "$label ";
615      $timeDropdown .= span {id => $elementID}, popup_menu {
616     name    => $name,
617     class   => 'dropdown',
618     values  => [@times],
619     default => $default,
620   };
621
622   return $timeDropdown;
623 } # makeTimeDropdown
624
625 sub heading (;$$) {
626   my ($title, $type) = @_;
627
628   if ($title) {
629     $title = "$APPNAME: $title";
630   } else {
631     $title = $APPNAME;
632   } # if
633
634   display header;
635   display start_html {
636     -title  => $title,
637     -author => 'Andrew DeFaria <Andrew@ClearSCM.com>',
638     -meta   => {
639       keywords  => 'ClearSCM Clearadm',
640       copyright => 'Copyright (c) ClearSCM, Inc. 2010, All rights reserved',
641   },
642     -script => [{
643       -language => 'JavaScript',
644       -src      => 'clearadm.js',
645     }],
646     -style   => ['clearadm.css', 'clearmenu.css'],
647   }, $title;
648
649   return if $type;
650
651   my $ieTableWrapStart = '<!--[if gt IE 6]><!--></a><!--<![endif]--><!--'
652                        . '[if lt IE 7]><table border="0" cellpadding="0" '
653                        . 'cellspacing="0"><tr><td><![endif]-->';
654   my $ieTableWrapEnd   = '<!--[if lte IE 6]></td></tr></table></a><![endif]-->';
655
656   # Menubar
657   display div {id=>'mastheadlogo'}, h1 {class => 'title'}, $APPNAME;
658   display start_div {class => 'menu'};
659
660   # Home
661   display ul li a {href => '/clearadm'}, 'Home';
662
663   my @allSystems = $clearadm->FindSystem;
664
665   # Systems
666   display start_ul;
667     display start_li;
668       display a {href => 'systems.cgi'}, "Systems$ieTableWrapStart";
669         display start_ul;
670           for (sort @allSystems) {
671             my %system = %{$_};
672             my $sysName  = ucfirst $system{name};
673                $sysName .= " ($system{alias})"
674                  if $system{alias};
675
676             display li a {
677               href => "systemdetails.cgi?system=$system{name}"
678             }, ucfirst "&nbsp;$sysName";
679           } # for
680         display end_ul;
681         display $ieTableWrapEnd;
682         display end_li;
683     display end_li;
684   display end_ul;
685
686   # Filesystems
687   display start_ul;
688     display start_li;
689       display a {href => 'filesystems.cgi'}, "Filesystems$ieTableWrapStart";
690         display start_ul;
691           for (@allSystems) {
692             my %system = %{$_};
693             my $sysName  = ucfirst $system{name};
694                $sysName .= " ($system{alias})"
695                  if $system{alias};
696
697             display li a {
698               href => "filesystems.cgi?system=$system{name}"
699             }, ucfirst "&nbsp;$sysName";
700           } # for
701         display end_ul;
702         display $ieTableWrapEnd;
703     display end_li;
704   display end_ul;
705
706   # Vobs
707   display start_ul;
708     display start_li;
709       display a {href => 'vobservers.cgi'}, "&nbsp;&nbsp;&nbsp;VOBs$ieTableWrapStart";
710       display $ieTableWrapEnd;
711     display end_li;
712   display end_ul;
713
714   # Views
715   display start_ul;
716     display start_li;
717       display a {href => 'viewager.cgi'}, "Views$ieTableWrapStart";
718       display $ieTableWrapEnd;
719     display end_li;
720   display end_ul;
721
722   # Configure
723   display start_ul;
724     display start_li;
725       display a {href => '#'}, "Configure$ieTableWrapStart";
726       display start_ul;
727         display li a {href => 'alerts.cgi'},        '&nbsp;Alerts';
728         display li a {href => 'notifications.cgi'}, '&nbsp;Notifications';
729         display li a {href => 'schedule.cgi'},      '&nbsp;Schedule';
730         display li a {href => 'tasks.cgi'},         '&nbsp;Tasks';
731       display end_ul;
732       display $ieTableWrapEnd;
733     display end_li;
734   display end_ul;
735
736   # Logs
737   display start_ul;
738     display start_li;
739       display a {href => '#'}, "Logs$ieTableWrapStart";
740       display start_ul;
741         display li a {href => 'alertlog.cgi'}, '&nbsp;Alert';
742         display li a {href => 'runlog.cgi'},   '&nbsp;Run';
743       display end_ul;
744       display $ieTableWrapEnd;
745     display end_li;
746   display end_ul;
747
748   # Help
749   display start_ul;
750     display start_li;
751       display a {href => '#'}, "Help$ieTableWrapStart";
752       display start_ul {class => 'rightmenu'};
753         display li a {href => 'readme.cgi'}, "&nbsp;About: $APPNAME $VERSION";
754       display end_ul;
755       display $ieTableWrapEnd;
756     display end_li;
757   display end_ul;
758   display end_div;
759
760   display start_div {class => 'page'};
761
762   return;
763 } # heading
764
765 sub displayAlert (;$) {
766   my ($alert) = @_;
767
768   display start_table {cellspacing => 1};
769
770   display start_Tr;
771     display th {class => 'labelCentered'}, 'Actions';
772     display th {class => 'labelCentered'}, 'Name';
773     display th {class => 'labelCentered'}, 'Type';
774     display th {class => 'labelCentered'}, 'Who';
775     display th {class => 'labelCentered'}, 'Category';
776   display end_Tr;
777
778   for ($clearadm->FindAlert ($alert)) {
779     my %alert = %{$_};
780
781     $alert{who} = setField $alert{who}, 'System Administrator';
782
783     display start_Tr;
784       my $areYouSure = "Are you sure you want to delete the $alert{name} alert?";
785
786       my $actions = start_form {
787         method => 'post',
788         action => 'processalert.cgi',
789       };
790
791       $actions .= input {
792         name   => 'name',
793         type   => 'hidden',
794         value  => $alert{name},
795       };
796
797       if (InArray $alert{name}, @PREDEFINED_ALERTS) {
798         $actions .= input {
799           name     => 'delete',
800           disabled => 'true',
801           type     => 'image',
802           src      => 'delete.png',
803           alt      => 'Delete',
804           value    => 'Delete',
805           title    => 'Cannot delete predefined alert',
806         };
807         $actions .= input {
808           name     => 'edit',
809           disabled => 'true',
810           type     => 'image',
811           src      => 'edit.png',
812           alt      => 'Edit',
813           value    => 'Edit',
814           title    => 'Cannot edit predefined alert',
815         };
816       } else {
817         $actions .= input {
818           name    => 'delete',
819           type    => 'image',
820           src     => 'delete.png',
821           alt     => 'Delete',
822           value   => 'Delete',
823           title   => 'Delete',
824           onclick => "return AreYouSure ('$areYouSure');",
825         };
826         $actions .= input {
827           name    => 'edit',
828           type    => 'image',
829           src     => 'edit.png',
830           alt     => 'Edit',
831           value   => 'Edit',
832           title   => 'Edit',
833         };
834       } # if
835
836       display end_form;
837
838       my $who = $alert{who};
839
840       if ($who =~ /^([a-zA-Z0-9._-]+)@([a-zA-Z0-9.-]+\.[a-zA-Z]{2,4})$/) {
841         $who = a {href => "mailto:$1\@$2"}, $who;
842       } # if
843
844       display td {class => 'dataCentered'}, $actions;
845       display td {class => 'data'},         $alert{name};
846       display td {class => 'data'},         $alert{type};
847       display td {class => 'data'},         $who;
848       display td {class => 'data'},
849         (InArray $alert{name}, @PREDEFINED_ALERTS) ? 'Predefined' : 'User Defined';
850     display end_Tr;
851   } # for
852
853   display end_table;
854
855   display p {class => 'center'}, a {
856     href => 'processalert.cgi?action=Add',
857   }, 'New alert ', img {
858     src    => 'add.png',
859     border => 0,
860   };
861
862   return;
863 } # DisplayAlerts
864
865 sub displayAlertlog (%) {
866   my (%opts) = @_;
867
868   my $optsChanged;
869
870   unless (($opts{oldalert}        and $opts{alert}         and
871            $opts{oldalert}        eq  $opts{alert})        and
872           ($opts{oldsystem}       and $opts{system}        and
873            $opts{oldsystem}       eq  $opts{system})       and
874           ($opts{oldnotification} and $opts{notification}  and
875            $opts{oldnotification} eq  $opts{notification})) {
876     $optsChanged = 1;
877   } # unless
878
879   my $condition;
880
881   unless ($opts{id}) {
882     $condition  = "alert like '%";
883     $condition .= $opts{alert} ? $opts{alert} : '';
884     $condition .= "%'";
885     $condition .= ' and ';
886     $condition .= "system like '%";
887     $condition .= $opts{system} ? $opts{system} : '';
888     $condition .= "%'";
889     $condition .= ' and ';
890     $condition .= "notification like '%";
891     $condition .= $opts{notification} ? $opts{notification} : '';
892     $condition .= "%'";
893   } # unless
894
895   my $total = $clearadm->Count ('alertlog', $condition);
896
897   if ($opts{'nextArrow.x'}) {
898     $opts{start} = $opts{next};
899   } elsif ($opts{'prevArrow.x'}) {
900     $opts{start} = $opts{prev};
901   } else {
902     $opts{start} = 0;
903   } # if
904
905   my $next = $opts{start} + $opts{page} < $total
906            ? $opts{start} + $opts{page}
907            : $opts{start};
908   my $prev = $opts{start} - $opts{page} >= 0
909            ? $opts{start} - $opts{page}
910            : $opts{start};
911
912   my $opts  = $opts{start} + 1;
913      $opts .= '-';
914      $opts .= $opts{start} + $opts{page} < $total
915             ? $opts{start} + $opts{page}
916             : $total;
917      $opts .= " of $total";
918
919   display start_form {
920     method => 'post',
921     action => 'alertlog.cgi'
922   };
923
924   # Hidden fields to pass along
925   display input {name  => 'prev', type  => 'hidden', value => $prev};
926   display input {name  => 'next', type  => 'hidden', value => $next};
927
928   display input {
929     name  => 'oldalert',
930     type  => 'hidden',
931     value => $opts{alert},
932   };
933   display input {
934     name  => 'oldsystem',
935     type  => 'hidden',
936     value => $opts{system},
937   };
938   display input {
939     name  => 'oldnotification',
940     type  => 'hidden',
941     value => $opts{notification},
942   };
943
944   my $caption = start_table {
945     class       => 'caption',
946     cellspacing => 1,
947     width       => '100%',
948   };
949
950   $caption .= start_Tr;
951
952     unless ($opts{id}) {
953       $caption .= td {align => 'left'}, input {
954         name     => 'prevArrow',
955         type     => 'image',
956         src      => 'left.png',
957         alt      => 'Previous',
958         value    => 'prev',
959       };
960     } else {
961       $caption .= td {align => 'left'}, img {
962         src      => 'left.png',
963         disabled => 'disabled',
964       };
965     } # unless
966
967     $caption .= td {align => 'center'}, $opts;
968
969     unless ($opts{id}) {
970       $caption .= td {align => 'right'}, input {
971         name     => 'nextArrow',
972         type     => 'image',
973         src      => 'right.png',
974         alt      => 'Next',
975         value    => 'next',
976       };
977     } else {
978       $caption .= td {align => 'right'}, img {
979         src      => 'right.png',
980         disabled => 'disabled',
981       };
982     } # unless
983
984   $caption .= end_Tr;
985
986   $caption .= end_table;
987
988   display start_table {cellspacing => 1, width => '98%'};
989
990   display caption $caption;
991
992   display start_Tr;
993     display th {class => 'labelCentered'}, '#';
994     display th {class => 'labelCentered'}, 'Delete';
995     display th {class => 'labelCentered'}, 'Name';
996     display th {class => 'labelCentered'}, 'System';
997     display th {class => 'labelCentered'}, 'Notification';
998     display th {class => 'labelCentered'}, 'Date/Time';
999     display th {class => 'labelCentered'}, 'Runlog';
1000     display th {class => 'labelCentered'}, 'Message';
1001   display end_Tr;
1002
1003   display start_Tr;
1004     display td {
1005       class   => 'filter',
1006       align   => 'right',
1007       colspan => 2,
1008     }, b 'Filter:';
1009     display td {
1010       class => 'filter'
1011     }, _makeAlertlogSelection ('alert', $opts{alert});
1012     display td {
1013       class => 'filter'
1014     }, _makeAlertlogSelection ('system', $opts{system});
1015     display td {
1016       class => 'filter'
1017     }, _makeAlertlogSelection ('notification', $opts{notification});
1018     display td {
1019       class => 'filter',
1020     }, input {
1021       type  => 'submit',
1022       value => 'Update',
1023     };
1024     display end_form;
1025     display td {
1026       class   => 'filter',
1027       align   => 'center',
1028       colspan => 2,
1029     # TODO: Would like to have Clear All Alerts be Clear Alerts and for it to
1030     # clear only the alerts that have been filtered.
1031     }, a {
1032         href => 'deletealertlog.cgi?alertlogid=all'
1033     }, input {
1034       type    => 'button',
1035       value   => 'Clear All Events',
1036       onclick => "return AreYouSure('Are you sure you want to delete all alerts?');",
1037     };
1038   display end_Tr;
1039
1040   my $i = $opts{start};
1041
1042   for ($clearadm->FindAlertlog (
1043     $opts{alert},
1044     $opts{system},
1045     $opts{notification},
1046     $opts{start},
1047     $opts{page},
1048     )) {
1049     my %alertlog = setFields 'N/A', %{$_};
1050
1051     display start_Tr;
1052       my %system = $clearadm->GetSystem ($alertlog{system});
1053
1054       display td {class => 'dataCentered'}, ++$i;
1055       display td {class => 'dataCentered'}, a {
1056         href => "deletealertlog.cgi?alertlogid=$alertlog{id}"
1057       }, img {
1058         src => 'delete.png',
1059         alt     => 'Delete',
1060         title   => 'Delete',
1061         border  => 0,
1062         onclick => "return AreYouSure ('Are you sure you wish to delete this alertlog entry?');",
1063       };
1064       display td {class => 'data'}, a {
1065         href => "alerts.cgi?alert=$alertlog{alert}"
1066       }, $alertlog{alert};
1067       display td {class => 'data'}, a {
1068         href => "systemdetails.cgi?system=$alertlog{system}"
1069       }, $alertlog{system};
1070       display td {class => 'data'}, a {
1071         href => "notifications.cgi?notification=$alertlog{notification}"
1072       }, $alertlog{notification};
1073       display td {class => 'data'},         $alertlog{timestamp};
1074       display td {class => 'dataCentered'}, a {
1075         href => "runlog.cgi?id=$alertlog{runlog}"
1076       }, $alertlog{runlog};
1077       display td {class => 'data'},         $alertlog{message};
1078     display end_Tr;
1079   } # for
1080
1081   display end_form;
1082
1083   display end_table;
1084
1085   return;
1086 } # displayAlertlog
1087
1088 sub displayFilesystem ($) {
1089   my ($systemName) = @_;
1090
1091   display start_table {cellspacing => 1, width => '98%'};
1092
1093   display start_Tr;
1094     display th {class => 'labelCentered'}, 'Action';
1095     display th {class => 'labelCentered'}, 'Name';
1096     display th {class => 'labelCentered'}, 'Alias';
1097     display th {class => 'labelCentered'}, 'Admin';
1098     display th {class => 'labelCentered'}, 'Filesystem';
1099     display th {class => 'labelCentered'}, 'Mount';
1100     display th {class => 'labelCentered'}, 'Type';
1101     display th {class => 'labelCentered'}, 'History';
1102     display th {class => 'labelCentered'}, 'Used';
1103     display th {class => 'labelCentered'}, 'Threshold';
1104     display th {class => 'labelCentered'}, 'Usage';
1105   display end_Tr;
1106
1107   for (sort { $a->{mount} cmp $b->{mount} } $clearadm->FindSystem ($systemName)) {
1108     my %system = %{$_};
1109
1110     %system = setFields ('N/A', %system);
1111
1112     my $admin = ($system{email} !~ 'N/A')
1113               ? a {-href => "mailto:$system{email}"}, $system{admin}
1114               : $system{admin};
1115
1116     for ($clearadm->FindFilesystem ($system{name})) {
1117       my %filesystem = %{$_};
1118
1119       my %fs = $clearadm->GetLatestFS ($system{name}, $filesystem{filesystem});
1120
1121       my $size = autoScale $fs{size};
1122       my $used = autoScale $fs{used};
1123       my $free = autoScale $fs{free};
1124
1125       # TODO: Note that this percentages does not agree with df output. I'm not
1126       # sure why.
1127       my $usedPct = $fs{size} == 0 ? 0
1128                   : sprintf ('%.0f',
1129                      (($fs{reserve} + $fs{used}) / $fs{size} * 100));
1130
1131       my $alias = ($system{alias} !~ 'N/A')
1132                 ? a {
1133                     href => "systemdetails.cgi?system=$system{name}"
1134                   }, $system{alias}
1135                 : $system{alias};
1136
1137       my $class         = $usedPct < $filesystem{threshold}
1138                         ? 'data'
1139                         : 'dataAlert';
1140       my $classRight    = $usedPct < $filesystem{threshold}
1141                         ? 'dataRight'
1142                         : 'dataRightAlert';
1143       my $classCentered = $usedPct < $filesystem{threshold}
1144                         ? 'dataCentered'
1145                         : 'dataCenteredAlert';
1146       my $classRightTop = $usedPct < $filesystem{threshold}
1147                         ? 'dataRightTop'
1148                         : 'dataRightAlertTop';
1149
1150       display start_Tr;
1151         display start_td {class => 'dataCentered'};
1152
1153         my $areYouSure = 'Are you sure you want to delete '
1154                        . "$system{name}:$filesystem{filesystem}?" . '\n'
1155                        . 'Doing so will remove all records related to this\n'
1156                        . 'filesystem and its history.';
1157
1158         display start_form {
1159           method => 'post',
1160           action => "processfilesystem.cgi",
1161         };
1162
1163         display input {
1164           type  => 'hidden',
1165           name  => 'system',
1166           value => $system{name},
1167         };
1168         display input {
1169           type  => 'hidden',
1170           name  => 'filesystem',
1171           value => $filesystem{filesystem},
1172         };
1173
1174         display input {
1175           name    => 'delete',
1176           type    => 'image',
1177           src     => 'delete.png',
1178           alt     => 'Delete',
1179           value   => 'Delete',
1180           title   => 'Delete',
1181           onclick => "return AreYouSure ('$areYouSure');"
1182         };
1183         display input {
1184           name    => 'edit',
1185           type    => 'image',
1186           src     => 'edit.png',
1187           alt     => 'Edit',
1188           value   => 'Edit',
1189           title   => 'Edit',
1190         };
1191
1192         if ($filesystem{notification}) {
1193           display a {
1194             href => "alertlog.cgi?system=$filesystem{system}"}, img {
1195             src    => 'alert.png',
1196             border => 0,
1197             alt    => 'Alert!',
1198             title  => 'This filesystem has alerts',
1199           };
1200         } # if
1201
1202         display end_form;
1203
1204         display end_td;
1205         display td {class => $class},
1206           a {-href => "systemdetails.cgi?system=$system{name}"}, $system{name};
1207         display td {class => $class}, $alias;
1208         display td {class => $class}, $admin;
1209         display td {class => $class}, $filesystem{filesystem};
1210         display td {class => $class}, $filesystem{mount};
1211         display td {class => $class}, $filesystem{fstype};
1212         display td {class => $classCentered}, $filesystem{filesystemHist};
1213         display td {class => $classRightTop}, "$used ($usedPct%)<br>",
1214           font {class => 'unknown'}, "$fs{timestamp}";
1215         display td {class => $classRightTop}, "$filesystem{threshold}%";
1216
1217         my $image = $filesystem{fssmall}
1218           ? "data:image/png;base64,$filesystem{fssmall}"
1219           : "plotfs.cgi?system=$system{name}&filesystem=$filesystem{filesystem}&tiny=1";
1220
1221         display td {class => $class},
1222           a {href =>
1223             "plot.cgi?type=filesystem&system=$system{name}"
1224           . "&filesystem=$filesystem{filesystem}&scaling=Day&points=7"
1225           }, img {
1226             src    => $image,
1227             border => 0,
1228           };
1229       display end_Tr;
1230     } # for
1231   } # for
1232
1233   display end_table;
1234
1235   return;
1236 } # displayFilesystem
1237
1238 sub displayNotification (;$) {
1239   my ($notification) = @_;
1240
1241   display start_table {cellspacing => 1};
1242
1243   display start_Tr;
1244     display th {class => 'labelCentered'}, 'Actions';
1245     display th {class => 'labelCentered'}, 'Name';
1246     display th {class => 'labelCentered'}, 'Alert';
1247     display th {class => 'labelCentered'}, 'Condition';
1248     display th {class => 'labelCentered'}, 'Not More Than';
1249     display th {class => 'labelCentered'}, 'Category';
1250   display end_Tr;
1251
1252   for ($clearadm->FindNotification ($notification)) {
1253     my %notification= setFields 'N/A', %{$_};
1254
1255     display start_Tr;
1256     my $areYouSure = "Are you sure you want to delete the $notification{name} "
1257                    . 'notification?';
1258
1259     my $actions = start_form {
1260       method => 'post',
1261       action => 'processnotification.cgi',
1262     };
1263
1264     $actions .= input {
1265       name   => 'name',
1266       type   => 'hidden',
1267       value  => $notification{name},
1268     };
1269
1270     if (InArray $notification{name}, @PREDEFINED_NOTIFICATIONS) {
1271       $actions .= input {
1272         name     => 'delete',
1273         disabled => 'true',
1274         type     => 'image',
1275         src      => 'delete.png',
1276         alt      => 'Delete',
1277         value    => 'Delete',
1278         title    => 'Cannot delete predefined notification',
1279       };
1280       $actions .= input {
1281         name     => 'edit',
1282         disabled => 'true',
1283         type     => 'image',
1284         src      => 'edit.png',
1285         alt      => 'Edit',
1286         value    => 'Edit',
1287         title    => 'Cannot edit predefined notification',
1288       };
1289     } else {
1290       $actions .= input {
1291         name    => 'delete',
1292         type    => 'image',
1293         src     => 'delete.png',
1294         alt     => 'Delete',
1295         value   => 'Delete',
1296         title   => 'Delete',
1297         onclick => "return AreYouSure ('$areYouSure');",
1298       };
1299       $actions .= input {
1300         name    => 'edit',
1301         type    => 'image',
1302         src     => 'edit.png',
1303         alt     => 'Edit',
1304         value   => 'Edit',
1305         title   => 'Edit',
1306       };
1307     } # if
1308
1309     display end_form;
1310
1311     display td {class => 'dataCentered'}, $actions;
1312     display td {class => 'data'},         $notification{name};
1313     display td {class => 'data'},         a {
1314       href => "alerts.cgi?alert=$notification{alert}"
1315     }, $notification{alert};
1316     display td {class => 'data'},         $notification{cond};
1317     display td {class => 'data'},         $notification{nomorethan};
1318     display td {class => 'data'},
1319       (InArray $notification{name}, @PREDEFINED_NOTIFICATIONS)
1320       ? 'Predefined'
1321       : 'User Defined';
1322
1323     display end_Tr;
1324   } # for
1325
1326   display end_table;
1327
1328   display p {class => 'center'}, a {
1329     href => 'processnotification.cgi?action=Add',
1330   }, 'New notification', img {
1331     src    => 'add.png',
1332     border => 0,
1333   };
1334
1335   return;
1336 } # displayNotification
1337
1338 sub displayRunlog (%) {
1339   my (%opts) = @_;
1340
1341   my $optsChanged;
1342
1343   for (qw(task system not status)) {
1344     my $old = "old$_";
1345     if (($opts{$old} and $opts{$_}) and ($opts{$old} ne $opts{$_})) {
1346       $optsChanged = 1;
1347       last;
1348     } # if
1349   } # for
1350
1351   my $condition = '';
1352
1353   unless ($opts{id}) {
1354     if ($opts{task} !~ /all/i) {
1355       $condition  = "task like '%";
1356       $condition .= $opts{task} ? $opts{task} : '';
1357       $condition .= "%'";
1358     } # if
1359
1360     if ($opts{system} !~ /all/i) {
1361       if ($opts{system} eq '<NULL>') {
1362         $condition .= ' and system is null';
1363         undef $opts{system}
1364       } elsif ($opts{system} ne 'All') {
1365         $condition .= " and system like '%$opts{system}%'";;
1366       } # if
1367     } # if
1368
1369     if ($opts{status} !~ /all/i) {
1370       $condition .= ' and ';
1371       unless ($opts{not}) {
1372         $condition .= "status=$opts{status}";
1373       } else {
1374         $condition .= "status<>$opts{status}";
1375       } # unless
1376     } # if
1377   } # unless
1378
1379   my $total = $clearadm->Count ('runlog', $condition);
1380
1381   $opts{start} = $opts{'nextArrow.x'} ? $opts{next} : $opts{prev};
1382   $opts{start} ||= 0;
1383   $opts{start} = 0
1384     if $optsChanged;
1385
1386   my $next = $opts{start} + $opts{page} < $total
1387            ? $opts{start} + $opts{page}
1388            : $opts{start};
1389   my $prev = $opts{start} - $opts{page} >= 0
1390            ? $opts{start} - $opts{page}
1391            : $opts{start};
1392
1393   my $opts  = $opts{'nextArrow.x'} ? $opts{next} + 1 : $opts{prev} + 1;
1394      $opts .= '-';
1395      $opts .= $opts{start} + $opts{page} < $total
1396             ? $opts{start} + $opts{page}
1397             : $total;
1398      $opts .= " of $total";
1399
1400   display start_form {
1401     method => 'post',
1402     action => 'runlog.cgi'
1403   };
1404
1405   # Hidden fields to pass along
1406   display input {name => 'prev',      type => 'hidden', value => $prev};
1407   display input {name => 'next',      type => 'hidden', value => $next};
1408   display input {name => 'oldtask',   type => 'hidden', value => $opts{task}};
1409   display input {name => 'oldsystem', type => 'hidden', value => $opts{system}};
1410   display input {name => 'oldnot',    type => 'hidden', value => $opts{not}};
1411   display input {name => 'oldstatus', type => 'hidden', value => $opts{status}};
1412
1413   my $caption = start_table {
1414     class       => 'caption',
1415     cellspacing => 1,
1416     width       => '100%',
1417   };
1418
1419   $caption .= start_Tr;
1420
1421   unless ($opts{id}) {
1422     $caption .= td {align => 'left'}, input {
1423       name     => 'prevArrow',
1424       type     => 'image',
1425       src      => 'left.png',
1426       alt      => 'Previous',
1427       value    => 'prev',
1428     };
1429   } else {
1430     $caption .= td {align => 'left'}, img {
1431       src      => 'left.png',
1432       disabled => 'disabled',
1433     };
1434   } # unless
1435
1436   $caption .= td {align => 'center'}, $opts;
1437
1438   unless ($opts{id}) {
1439     $caption .= td {align => 'right'}, input {
1440       name     => 'nextArrow',
1441       type     => 'image',
1442       src      => 'right.png',
1443       alt      => 'Next',
1444       value    => 'next',
1445     };
1446   } else {
1447     $caption .= td {align => 'right'}, img {
1448       src      => 'right.png',
1449       disabled => 'disabled',
1450     };
1451   } # unless
1452
1453   $caption .= end_Tr;
1454
1455   $caption .= end_table;
1456
1457   display start_table {cellspacing => 1, width => '98%'};
1458
1459   display caption $caption;
1460
1461   display start_Tr;
1462     display th {class => 'labelCentered'}, '#';
1463     display th {class => 'labelCentered'}, 'ID';
1464     display th {class => 'labelCentered'}, 'Task';
1465     display th {class => 'labelCentered'}, 'System';
1466     display th {class => 'labelCentered'}, 'Started';
1467     display th {class => 'labelCentered'}, 'Ended';
1468     display th {class => 'labelCentered'}, 'Status';
1469     display th {class => 'labelCentered'}, 'Message';
1470   display end_Tr;
1471
1472   display start_Tr;
1473     $opts{not} ||= 'false';
1474
1475     display start_form {
1476       method => 'post',
1477       action => 'runlog.cgi'
1478     };
1479     display td {
1480       class   => 'filter',
1481       align   => 'right',
1482       colspan => 2,
1483     }, b 'Filter:';
1484     display td {
1485       class => 'filter'
1486     }, _makeRunlogSelection ('task', $opts{task});
1487     display td {
1488       class => 'filter'
1489     }, _makeRunlogSelection ('system', $opts{system});
1490     display td {class => 'filter'}, '&nbsp;';
1491     display td {
1492       class => 'filter',
1493       align => 'right',
1494     }, "Not: ", checkbox {
1495       name    => 'not',
1496       value   => 'true',
1497       checked => $opts{not} eq 'true' ? 1 : 0,
1498       label   => '',
1499     };
1500     display td {
1501       class => 'filter'
1502     }, _makeRunlogSelectionNumeric ('status', $opts{status});
1503     display td {
1504       class => 'filter',
1505     }, input {
1506       type  => 'submit',
1507       value => 'Update',
1508     };
1509
1510     display end_form;
1511   display end_Tr;
1512
1513   my $i = $opts{start};
1514
1515   my $status;
1516
1517   if ($opts{status}) {
1518     if ($opts{status} !~ /all/i) {
1519       $status = $opts{not} ne 'true' ? $opts{status} : "!$opts{status}";
1520     } # if
1521   } # if
1522
1523   for ($clearadm->FindRunlog (
1524     $opts{task},
1525     $opts{system},
1526     $status,
1527     $opts{id},
1528     $opts{start},
1529     $opts{page},
1530     )) {
1531     my %runlog = setFields 'N/A', %{$_};
1532
1533     my $class         = $runlog{status} == 0
1534                       ? 'data'
1535                       : 'dataAlert';
1536     my $classCentered = $runlog{status} == 0
1537                       ? 'dataCentered'
1538                       : 'dataAlertCentered';
1539     my $classRight    = $runlog{status} == 0
1540                       ? 'dataRight'
1541                       : 'dataAlertRight';
1542
1543     display start_Tr;
1544       display td {class => 'dataCentered'}, ++$i;
1545       display td {class => 'dataCentered'}, $runlog{id};
1546       display td {class => 'data'},         a {
1547         href => "tasks.cgi?task=$runlog{task}"
1548       }, $runlog{task};
1549       display td {class => 'data'}, $runlog{system} eq 'localhost'
1550         ? $runlog{system}
1551         : a {
1552         href => "systemdetails.cgi?system=$runlog{system}"
1553       }, $runlog{system};
1554       display td {class => 'dataCentered'}, $runlog{started};
1555       display td {class => 'dataCentered'}, $runlog{ended};
1556       display td {class => $classRight},    $runlog{status};
1557
1558       my $message = $runlog{message};
1559          $message =~ s/\r\n/<br>/g;
1560
1561       display td {class => $class, width => '50%'},         $message;
1562     display end_Tr;
1563   } # for
1564
1565   display end_table;
1566
1567   return;
1568 } # displayRunlog
1569
1570 sub displaySchedule () {
1571   display start_table {cellspacing => 1};
1572
1573   display start_Tr;
1574     display th {class => 'labelCentered'}, 'Actions';
1575     display th {class => 'labelCentered'}, 'Active';
1576     display th {class => 'labelCentered'}, 'Name';
1577     display th {class => 'labelCentered'}, 'Task';
1578     display th {class => 'labelCentered'}, 'Notification';
1579     display th {class => 'labelCentered'}, 'Frequency';
1580     display th {class => 'labelCentered'}, 'Category';
1581   display end_Tr;
1582
1583   for ($clearadm->FindSchedule) {
1584     my %schedule = setFields 'N/A', %{$_};
1585
1586     display start_Tr;
1587     my $areYouSure = "Are you sure you want to delete the $schedule{name} "
1588                    . "schedule?";
1589
1590     my $actions = start_form {
1591       method => 'post',
1592       action => 'processschedule.cgi',
1593     };
1594
1595     $actions .= input {
1596       name   => 'name',
1597       type   => 'hidden',
1598       value  => $schedule{name},
1599     };
1600
1601     if (InArray $schedule{name}, @PREDEFINED_SCHEDULES) {
1602       $actions .= input {
1603         name     => 'delete',
1604         disabled => 'true',
1605         type     => 'image',
1606         src      => 'delete.png',
1607         alt      => 'Delete',
1608         value    => 'Delete',
1609         title    => 'Cannot delete predefined schedule',
1610       };
1611       $actions .= input {
1612         name     => 'edit',
1613         disabled => 'true',
1614         type     => 'image',
1615         src      => 'edit.png',
1616         alt      => 'Edit',
1617         value    => 'Edit',
1618         title    => 'Cannot edit predefined schedule',
1619       };
1620     } else {
1621       $actions .= input {
1622         name    => 'delete',
1623         type    => 'image',
1624         src     => 'delete.png',
1625         alt     => 'Delete',
1626         value   => 'Delete',
1627         title   => 'Delete',
1628         onclick => "return AreYouSure ('$areYouSure');",
1629       };
1630       $actions .= input {
1631         name    => 'edit',
1632         type    => 'image',
1633         src     => 'edit.png',
1634         alt     => 'Edit',
1635         value   => 'Edit',
1636         title   => 'Edit',
1637       };
1638     } # if
1639
1640     display end_form;
1641
1642     display td {class => 'dataCentered'}, $actions;
1643     display td {class => 'dataCentered'}, checkbox {
1644       disabled => 'disabled',
1645       checked  => $schedule{active} eq 'true' ? 1 : 0,
1646     };
1647     display td {class => 'data'},         $schedule{name};
1648     display td {class => 'data'},         a {
1649       href => "tasks.cgi?task=$schedule{task}"
1650     }, $schedule{task};
1651     display td {class => 'data'},         a {
1652       href => "notifications.cgi?notification=$schedule{notification}"
1653     }, $schedule{notification};
1654     display td {class => 'data'},         $schedule{frequency};
1655     display td {class => 'data'},
1656       (InArray $schedule{name}, @PREDEFINED_SCHEDULES)
1657         ? 'Predefined'
1658         : 'User Defined';
1659
1660     display end_Tr;
1661   } # for
1662
1663   display end_table;
1664
1665   display p {class => 'center'}, a {
1666     href => 'processschedule.cgi?action=Add',
1667   }, 'New schedule', img {
1668     src    => 'add.png',
1669     border => 0,
1670   };
1671
1672   return;
1673 } # displaySchedule
1674
1675 sub displaySystem ($) {
1676   my ($systemName) = @_;
1677
1678   my %system = $clearadm->GetSystem ($systemName);
1679
1680   unless (%system) {
1681     displayError "Nothing known about system $systemName";
1682     return;
1683   } # unless
1684
1685   my $lastheardfromClass = 'dataCentered';
1686   my $lastheardfromData  = $system{lastheardfrom};
1687
1688   my %load = $clearadm->GetLatestLoadavg ($systemName);
1689
1690   unless ($clearadm->SystemAlive (%system)) {
1691     $lastheardfromClass = 'dataCenteredAlert';
1692     $lastheardfromData  = a {
1693       href  => "alertlog.cgi?system=$system{name}",
1694       class => 'alert',
1695       title => "Have not heard from $system{name} for a while"
1696     }, $system{lastheardfrom};
1697     $system{notification} = 'Heartbeat';
1698   } # unless
1699
1700   my $admin = ($system{email})
1701             ? a {-href => "mailto:$system{email}"}, $system{admin}
1702             : $system{admin};
1703
1704   $system{alias}  = setField $system{alias},  'N/A';
1705   $system{region} = setField $system{region}, 'N/A';
1706
1707   display start_table {cellspacing => 1};
1708
1709   display start_Tr;
1710     my $areYouSure = 'Are you sure you want to delete this system?\n'
1711                    . "Doing so will remove all records related to $system{name}"
1712                    . '\nincluding filesystem records and history as well as '
1713                    . 'loadavg history.';
1714
1715     my $actions = start_form {
1716       method => 'post',
1717       action => 'processsystem.cgi',
1718     };
1719
1720     $actions .= input {
1721       name   => 'name',
1722       type   => 'hidden',
1723       value  => $system{name},
1724     };
1725
1726     $actions .= input {
1727       name    => 'delete',
1728       type    => 'image',
1729       src     => 'delete.png',
1730       alt     => 'Delete',
1731       value   => 'Delete',
1732       title   => 'Delete',
1733       onclick => "return AreYouSure ('$areYouSure');",
1734     };
1735     $actions .= input {
1736       name    => 'edit',
1737       type    => 'image',
1738       src     => 'edit.png',
1739       alt     => 'Edit',
1740       value   => 'Edit',
1741       title   => 'Edit',
1742     };
1743     $actions .= checkbox {
1744       disabled => 'disabled',
1745       checked  => $system{active} eq 'true' ? 1 : 0,
1746     };
1747
1748     if ($system{notification}) {
1749       $actions .= a {
1750         href => "alertlog.cgi?system=$system{name}"}, img {
1751         src    => 'alert.png',
1752         border => 0,
1753         alt    => 'Alert!',
1754         title  => 'This system has alerts',
1755       };
1756     } # if
1757
1758     display th {class => 'label'},                      "$actions Name:";
1759     display end_form;
1760     display td {class => 'dataCentered', colspan => 2}, $system{name};
1761     display th {class => 'label'},                      'Alias:';
1762     display td {class => 'dataCentered'},               $system{alias};
1763     display th {class => 'label'},                      'Admin:';
1764     display td {class => 'dataCentered', colspan => 2}, $admin;
1765     display th {class => 'label', colspan => 2},        'Type:';
1766     display td {class => 'dataCentered'},               $system{type};
1767   display end_Tr;
1768
1769   display start_Tr;
1770     display th {class => 'label'},               'OS Version:';
1771     display td {class => 'data', colspan => 10}, $system{os};
1772   display end_Tr;
1773
1774   display start_Tr;
1775     display th {class => 'label'}, 'Last Contacted:';
1776     display td {
1777       class => $lastheardfromClass,
1778       colspan => 2
1779     }, "$lastheardfromData ",
1780       font {class => 'dim' }, "<br>Up: $load{uptime}";
1781     display th {class => 'label'},        'Port:';
1782     display td {class => 'dataCentered'}, $system{port};
1783     display th {class => 'label'},        'Threshold:';
1784     display td {class => 'dataCentered'}, $system{loadavgThreshold};
1785     display th {class => 'label'},        'History:';
1786     display td {class => 'dataCentered'}, $system{loadavgHist};
1787     display th {class => 'label'},        'Load Avg:';
1788     display td {class => 'data'},
1789       a {href =>
1790         "plot.cgi?type=loadavg&system=$system{name}&scaling=Hour&points=24"
1791         }, img {
1792           src    => "data:image/png;base64,$system{loadavgsmall}",
1793           border => 0,
1794       };
1795
1796   my $description = $system{description};
1797   $description =~ s/\r\n/<br>/g;
1798
1799   display start_Tr;
1800     display th {class => 'label'},               'Description:';
1801     display td {class => 'data', colSpan => 10}, $description;
1802   display end_Tr;
1803
1804   display end_table;
1805
1806   display p {class => 'center'}, a {
1807     href => 'processsystem.cgi?action=Add',
1808   }, 'New system', img {
1809     src    => 'add.png',
1810     border => 0,
1811   };
1812
1813   display h1 {class => 'center'},
1814     'Filesystem Details: ' . ucfirst $system{name};
1815
1816   display start_table {cellspacing => 1};
1817
1818   display start_Tr;
1819     display th {class => 'labelCentered'}, 'Action';
1820     display th {class => 'labelCentered'}, 'Filesystem';
1821     display th {class => 'labelCentered'}, 'Type';
1822     display th {class => 'labelCentered'}, 'Mount';
1823     display th {class => 'labelCentered'}, 'Size';
1824     display th {class => 'labelCentered'}, 'Used';
1825     display th {class => 'labelCentered'}, 'Free';
1826     display th {class => 'labelCentered'}, 'Used %';
1827     display th {class => 'labelCentered'}, 'Threshold';
1828     display th {class => 'labelCentered'}, 'History';
1829     display th {class => 'labelCentered'}, 'Usage';
1830   display end_Tr;
1831
1832   for ($clearadm->FindFilesystem ($system{name})) {
1833     my %filesystem = %{$_};
1834
1835     my %fs = $clearadm->GetLatestFS (
1836       $filesystem{system},
1837       $filesystem{filesystem}
1838     );
1839
1840     my $size = autoScale $fs{size};
1841     my $used = autoScale $fs{used};
1842     my $free = autoScale $fs{free};
1843
1844     # TODO: Note that this percentages does not agree with df output. I'm not
1845     # sure why.
1846     my $usedPct = $fs{size} == 0 ? 0
1847                 : sprintf ('%.0f',
1848                    (($fs{reserve} + $fs{used}) / $fs{size} * 100));
1849
1850     my $class         = $usedPct < $filesystem{threshold}
1851                       ? 'data'
1852                       : 'dataAlert';
1853     my $classCentered = $class . 'Centered';
1854     my $classRight    = $class . 'Right';
1855
1856     display start_Tr;
1857       display start_td {class => 'data'};
1858
1859       my $areYouSure = 'Are you sure you want to delete '
1860                      . "$system{name}:$filesystem{filesystem}?" . '\n'
1861                      . 'Doing so will remove all records related to this\n'
1862                      . 'filesystem and its history.';
1863
1864       display start_form {
1865         method => 'post',
1866         action => 'processfilesystem.cgi',
1867       };
1868
1869       display input {
1870         type  => 'hidden',
1871         name  => 'system',
1872         value => $system{name},
1873       };
1874       display input {
1875         type  => 'hidden',
1876         name  => 'filesystem',
1877         value => $filesystem{filesystem},
1878       };
1879
1880       display input {
1881         name    => 'delete',
1882         type    => 'image',
1883         src     => 'delete.png',
1884         alt     => 'Delete',
1885         value   => 'Delete',
1886         title   => 'Delete',
1887         onclick => "return AreYouSure ('$areYouSure');"
1888       };
1889       display input {
1890         name    => 'edit',
1891         type    => 'image',
1892         src     => 'edit.png',
1893         alt     => 'Edit',
1894         value   => 'Edit',
1895         title   => 'Edit',
1896       };
1897
1898       if ($filesystem{notification}) {
1899         display a {
1900           href => "alertlog.cgi?system=$filesystem{system}"}, img {
1901           src    => 'alert.png',
1902           border => 0,
1903           alt    => 'Alert!',
1904           title  => 'This filesystem has alerts',
1905         };
1906       } # if
1907
1908       display end_form;
1909
1910       display td {class => $class},         $filesystem{filesystem};
1911       display td {class => $classCentered}, $filesystem{fstype};
1912       display td {class => $class},         $filesystem{mount};
1913       display td {class => $classRight},    $size;
1914       display td {class => $classRight},    $used;
1915       display td {class => $classRight},    $free;
1916       display td {class => $classRight},    "$usedPct%";
1917       display td {class => $classRight},    "$filesystem{threshold}%";
1918       display td {class => $classCentered}, $filesystem{filesystemHist};
1919       display td {class => $classCentered},
1920         a {href =>
1921           "plot.cgi?type=filesystem&system=$system{name}"
1922         . "&filesystem=$filesystem{filesystem}"
1923         . "&scaling=Day&points=7"
1924         }, img {
1925           src    => "data:image/png;base64,$filesystem{fssmall}",
1926           border => 0,
1927         };
1928     display end_Tr;
1929   } # for
1930
1931   display end_table;
1932
1933   return;
1934 } # displaySystem
1935
1936 sub displayTask (;$) {
1937   my ($task) = @_;
1938
1939   display start_table {cellspacing => 1, width => '98%'};
1940
1941   display start_Tr;
1942     display th {class => 'labelCentered'}, 'Actions';
1943     display th {class => 'labelCentered'}, 'Name';
1944     display th {class => 'labelCentered'}, 'System';
1945     display th {class => 'labelCentered'}, 'Description';
1946     display th {class => 'labelCentered'}, 'Command';
1947     display th {class => 'labelCentered'}, 'Restartable';
1948     display th {class => 'labelCentered'}, 'Category';
1949   display end_Tr;
1950
1951   for ($clearadm->FindTask ($task)) {
1952     my %task = %{$_};
1953
1954     $task{system} = 'All Systems'
1955       unless $task{system};
1956
1957     display start_Tr;
1958       my $areYouSure = "Are you sure you want to delete the $task{name} task?";
1959
1960       my $actions = start_form {
1961         method => 'post',
1962         action => 'processtask.cgi',
1963       };
1964
1965       $actions .= input {
1966         name   => 'name',
1967         type   => 'hidden',
1968         value  => $task{name},
1969       };
1970
1971       if (InArray $task{name}, @PREDEFINED_TASKS) {
1972         $actions .= input {
1973           name     => 'delete',
1974           disabled => 'true',
1975           type     => 'image',
1976           src      => 'delete.png',
1977           alt      => 'Delete',
1978           value    => 'Delete',
1979           title    => 'Cannot delete predefined task',
1980         };
1981         $actions .= input {
1982           name     => 'edit',
1983           disabled => 'true',
1984           type     => 'image',
1985           src      => 'edit.png',
1986           alt      => 'Edit',
1987           value    => 'Edit',
1988           title    => 'Cannot edit predefined task',
1989         };
1990       } else {
1991         $actions .= input {
1992           name    => 'delete',
1993           type    => 'image',
1994           src     => 'delete.png',
1995           alt     => 'Delete',
1996           value   => 'Delete',
1997           title   => 'Delete',
1998           onclick => "return AreYouSure ('$areYouSure');",
1999         };
2000         $actions .= input {
2001           name    => 'edit',
2002           type    => 'image',
2003           src     => 'edit.png',
2004           alt     => 'Edit',
2005           value   => 'Edit',
2006           title   => 'Edit',
2007         };
2008       } # if
2009
2010       display end_form;
2011
2012       display td {class => 'dataCentered'}, $actions;
2013       display td {class => 'data'},         $task{name};
2014       display td {class => 'data'},         $task{system};
2015       display td {class => 'data'},         $task{description};
2016       display td {class => 'data'},         $task{command};
2017       display td {class => 'dataCentered'}, $task{restartable};
2018       display td {class => 'data'},
2019         (InArray $task{name}, @PREDEFINED_TASKS) ? 'Predefined' : 'User Defined';
2020     display end_Tr;
2021   } # for
2022
2023   display end_table;
2024
2025   display p {class => 'center'}, a {
2026     href => 'processtask.cgi?action=Add',
2027   }, 'New task', img {
2028     src    => 'add.png',
2029     border => 0,
2030   };
2031
2032   return;
2033 } # DisplayAlerts
2034
2035 sub editAlert (;$) {
2036   my ($alert) = @_;
2037
2038   display start_form (
2039     -method   => 'post',
2040     -action   => 'processalert.cgi',
2041     -onsubmit => 'return validateAlert (this);',
2042   );
2043
2044   my %alert;
2045
2046   if ($alert) {
2047     %alert = $clearadm->GetAlert ($alert);
2048
2049     return
2050       unless %alert;
2051
2052     display input {
2053       name  => 'oldname',
2054       type  => 'hidden',
2055       value => $alert,
2056     };
2057   } else {
2058     $alert= '';
2059   } # if
2060
2061   display input {
2062     name  => 'action',
2063     type  => 'hidden',
2064     value => 'Post',
2065   };
2066
2067   display start_table {cellspacing => 1};
2068
2069   display start_Tr;
2070     display th {class => 'labelCentered'}, 'Name';
2071     display th {class => 'labelCentered'}, 'Type';
2072     display th {class => 'labelCentered'}, 'Who';
2073   display end_Tr;
2074
2075   display start_Tr;
2076     display td {
2077       class => 'data',
2078     }, input {
2079       class     => 'inputfield',
2080       maxlength => 255,
2081       name      => 'name',
2082       size      => 20,
2083       type      => 'text',
2084       value     => $alert ? $alert{name} : '',
2085     };
2086     display td {
2087       class => 'dataCentered',
2088     }, popup_menu {
2089       name    => 'type',
2090       class   => 'dropdown',
2091       values  => [ 'email', 'page', 'im' ],
2092       default => $alert ? $alert{type} : 'email',
2093     };
2094     display td {
2095       class => 'data',
2096     }, input {
2097       class     => 'inputfield',
2098       maxlength => 255,
2099       name      => 'who',
2100       size      => 20,
2101       type      => 'text',
2102       value     => $alert ? $alert{who} : '',
2103     };
2104   display end_Tr;
2105   display end_table;
2106
2107   display '<center>';
2108   display p submit ({value => $alert ? 'Update' : 'Add'}),  reset;
2109   display '</center>';
2110
2111   display end_form;
2112
2113   return;
2114 } # editAlert
2115
2116 sub editFilesystem ($$) {
2117   my ($system, $filesystem) = @_;
2118
2119   display start_form (
2120     -method => 'post',
2121     -action => 'processfilesystem.cgi',
2122   );
2123
2124   display start_table {width => '800px', cellspacing => 1};
2125
2126   display start_Tr;
2127     display th {class => 'labelCentered'}, 'Filesystem';
2128     display th {class => 'labelCentered'}, 'Type';
2129     display th {class => 'labelCentered'}, 'Mount';
2130     display th {class => 'labelCentered'}, 'Size';
2131     display th {class => 'labelCentered'}, 'Used';
2132     display th {class => 'labelCentered'}, 'Free';
2133     display th {class => 'labelCentered'}, 'Used %';
2134     display th {class => 'labelCentered'}, 'History';
2135     display th {class => 'labelCentered'}, 'Threshold';
2136   display end_Tr;
2137
2138   my %filesystem = $clearadm->GetFilesystem ($system, $filesystem);
2139   my %fs         = $clearadm->GetLatestFS   ($system, $filesystem);
2140
2141   display input {
2142     name  => 'action',
2143     type  => 'hidden',
2144     value => 'Post',
2145   };
2146   display input {
2147     name  => 'system',
2148     type  => 'hidden',
2149     value => $filesystem{system},
2150   };
2151   display input {
2152     name  => 'filesystem',
2153     type  => 'hidden',
2154     value => $filesystem{filesystem},
2155   } ;
2156
2157   my $size = autoScale $fs{size};
2158   my $used = autoScale $fs{used};
2159   my $free = autoScale $fs{free};
2160
2161   display start_Tr;
2162     display td {class => 'data'},         $filesystem{filesystem};
2163     display td {class => 'dataCentered'}, $filesystem{fstype};
2164     display td {class => 'data'},         $filesystem{mount};
2165     display td {class => 'dataRight'},    $size;
2166     display td {class => 'dataRight'},    $used;
2167     display td {class => 'dataRight'},    $free;
2168     # TODO: Note that this percentages does not agree with df output. I'm not
2169     # sure why.
2170     display td {class => 'dataCentered'},
2171       sprintf ('%.0f%%', (($fs{reserve} + $fs{used}) / $fs{size} * 100));
2172
2173     my $historyDropdown = popup_menu {
2174       name    => 'filesystemHist',
2175       class   => 'dropdown',
2176       values  => [
2177         '1 month',
2178         '2 months',
2179         '3 months',
2180         '4 months',
2181         '5 months',
2182         '6 months',
2183         '7 months',
2184         '8 months',
2185         '9 months',
2186         '10 months',
2187         '11 months',
2188         '1 year',
2189       ],
2190       default => $system ? $filesystem{filesystemHist} : '6 months',
2191     };
2192
2193     display td {
2194       class => 'dataRight',
2195     }, $historyDropdown;
2196
2197     my $thresholdDropdown = popup_menu {
2198       name    => 'threshold',
2199       class   => 'dropdown',
2200       values  => [1 .. 100],
2201       default => $filesystem{threshold},
2202     };
2203     display td {class => 'dataCentered'}, $thresholdDropdown . '%';
2204   display end_Tr;
2205
2206   display end_table;
2207
2208   display '<center>';
2209   display p submit ({value => 'Update'}),  reset;
2210   display '</center>';
2211
2212   display end_form;
2213
2214   return;
2215 } # editFilesytem
2216
2217 sub editNotification (;$) {
2218   my ($notification) = @_;
2219
2220   display start_form (
2221     -method   => 'post',
2222     -action   => 'processnotification.cgi',
2223     -onsubmit => 'return validateNotification (this);',
2224   );
2225
2226   my %notification;
2227
2228   if ($notification) {
2229     %notification = $clearadm->GetNotification ($notification);
2230
2231     return
2232       unless %notification;
2233
2234     display input {
2235       name  => 'oldname',
2236       type  => 'hidden',
2237       value => $notification,
2238     };
2239   } else {
2240     $notification = '';
2241   } # if
2242
2243   display input {
2244     name  => 'action',
2245     type  => 'hidden',
2246     value => 'Post',
2247   };
2248
2249   display start_table {cellspacing => 1};
2250
2251   display start_Tr;
2252     display th {class => 'labelCentered'}, 'Name';
2253     display th {class => 'labelCentered'}, 'Alert';
2254     display th {class => 'labelCentered'}, 'Condition';
2255     display th {class => 'labelCentered'}, 'Not More Than';
2256   display end_Tr;
2257
2258   display start_Tr;
2259     display td {
2260       class => 'data',
2261     }, input {
2262       class     => 'inputfield',
2263       maxlength => 255,
2264       name      => 'name',
2265       size      => 20,
2266       type      => 'text',
2267       value     => $notification ? $notification{name} : '',
2268     };
2269
2270     display td {
2271       class => 'dataCentered',
2272     }, makeAlertDropdown undef, $notification{alert}
2273        ? $notification{alert}
2274        : 'Email admin';
2275
2276     display td {
2277       class => 'data',
2278     }, input {
2279       class     => 'inputfield',
2280       maxlength => 255,
2281       name      => 'cond',
2282       size      => 20,
2283       type      => 'text',
2284       value     => $notification ? $notification{cond} : '',
2285     };
2286     display td {
2287       class => 'dataCentered',
2288     }, makeNoMoreThanDropdown undef, $notification{nomorethan};
2289
2290   display end_Tr;
2291   display end_table;
2292
2293   display '<center>';
2294   display p submit ({value => $notification ? 'Update' : 'Add'}),  reset;
2295   display '</center>';
2296
2297   display end_form;
2298
2299   return;
2300 } # editNotification
2301
2302 sub editSchedule (;$) {
2303   my ($schedule) = @_;
2304
2305   display start_form (
2306     -method   => 'post',
2307     -action   => 'processschedule.cgi',
2308     -onsubmit => 'return validateSchedule (this);',
2309   );
2310
2311   my %schedule;
2312
2313   if ($schedule) {
2314     %schedule = $clearadm->GetSchedule ($schedule);
2315
2316     return
2317       unless %schedule;
2318
2319     display input {
2320       name  => 'oldname',
2321       type  => 'hidden',
2322       value => $schedule,
2323     };
2324   } else {
2325     $schedule = '';
2326   } # if
2327
2328   display input {
2329     name  => 'action',
2330     type  => 'hidden',
2331     value => 'Post',
2332   };
2333
2334   display start_table {cellspacing => 1};
2335
2336   display start_Tr;
2337     display th {class => 'labelCentered'}, 'Active';
2338     display th {class => 'labelCentered'}, 'Name';
2339     display th {class => 'labelCentered'}, 'Task';
2340     display th {class => 'labelCentered'}, 'Notification';
2341     display th {class => 'labelCentered'}, 'Frequency';
2342   display end_Tr;
2343
2344   display start_Tr;
2345     display td {
2346       class => 'dataCentered',
2347     }, checkbox {
2348       name    => 'active',
2349       value   => 'true',
2350       checked => $schedule{active} eq 'false' ? 0 : 1,
2351       label   => '',
2352     };
2353     display td {
2354       class => 'data',
2355     }, input {
2356       class     => 'inputfield',
2357       maxlength => 255,
2358       name      => 'name',
2359       size      => 20,
2360       type      => 'text',
2361       value     => $schedule ? $schedule{name} : '',
2362     };
2363     display td {
2364       class => 'dataCentered',
2365     }, makeTaskDropdown undef, $schedule{task};
2366     display td {
2367       class => 'dataCentered',
2368     }, makeNotificationDropdown undef, $schedule{notification};
2369
2370     my $nbr        = 5;
2371     my $multiplier = 'minutes';
2372
2373     if ($schedule{frequency} =~ /(\d+)\s(\S+)/ ) {
2374       $nbr        = $1;
2375       $multiplier = $2;
2376
2377       $multiplier .= 's' if $nbr == 1;
2378     } # if
2379
2380     display td {
2381       class => 'data',
2382     }, input {
2383       class     => 'inputfieldRight',
2384       maxlength => 3,
2385       name      => 'nbr',
2386       size      => 1,
2387       type      => 'text',
2388       value     => $nbr,
2389     },
2390       ' ',
2391       makeMultiplierDropdown undef, $multiplier;
2392
2393   display end_Tr;
2394   display end_table;
2395
2396   display '<center>';
2397   display p submit ({value => $schedule ? 'Update' : 'Add'}),  reset;
2398   display '</center>';
2399
2400   display end_form;
2401
2402   return;
2403 } # editSchedule
2404
2405 sub editSystem (;$) {
2406   my ($system) = @_;
2407
2408   display start_form (
2409     -method   => 'post',
2410     -action   => 'processsystem.cgi',
2411     -onsubmit => 'return validateSystem (this);',
2412   );
2413
2414   my %system;
2415
2416   if ($system) {
2417     %system = $clearadm->GetSystem ($system);
2418
2419     return
2420       unless %system;
2421
2422     display input {
2423       name  => 'name',
2424       type  => 'hidden',
2425       value => $system,
2426     };
2427   } else {
2428     $system = '';
2429   } # if
2430
2431   display input {
2432     name  => 'action',
2433     type  => 'hidden',
2434     value => 'Post',
2435   };
2436
2437   display start_table {cellspacing => 1};
2438
2439   display start_Tr;
2440     display th {class => 'label'}, checkbox ({
2441       name    => 'active',
2442       value   => 'true',
2443       checked => $system{active} eq 'false' ? 0 : 1,
2444       label   => '',
2445     }) . ' Name: ';
2446
2447     if ($system) {
2448       display td {class => 'data'},  $system{name};
2449     } else {
2450       display td {
2451         class => 'data',
2452       }, input {
2453         class     => 'inputfield',
2454         maxlength => 255,
2455         name      => 'name',
2456         size      => 20,
2457         type      => 'text',
2458       };
2459     } # if
2460
2461     display th {class => 'label'}, 'Alias:';
2462     display td {
2463       class => 'data',
2464     }, input {
2465       class     => 'inputfield',
2466       maxlength => 255,
2467       name      => 'alias',
2468       size      => 20,
2469       type      => 'text',
2470       value     => $system ? $system{alias} : '',
2471     };
2472
2473     display th {class => 'label'}, 'Port:';
2474     display td {
2475       class => 'dataRight',
2476     }, input {
2477       class     => 'inputfieldRight',
2478       maxlength => 6,
2479       name      => 'port',
2480       size      => 4,
2481       type      => 'text',
2482       value     => $system
2483                  ? $system{port}
2484                  : $Clearadm::CLEAROPTS{CLEARADM_PORT},
2485     };
2486
2487     my $systemTypeDropdown = popup_menu {
2488       name    => 'type',
2489       class   => 'dropdown',
2490       values  => ['Unix', 'Linux', 'Windows'],
2491       default => $system ? $system{type} : 'Linux',
2492     };
2493
2494     display th {class => 'label'}, 'Type:';
2495     display td {
2496       class   => 'dataRight',
2497     },  $systemTypeDropdown;
2498   display end_Tr;
2499
2500   display start_Tr;
2501     display th {class => 'label'}, 'Admin:';
2502     display td {
2503       class => 'data',
2504     }, input {
2505       class     => 'inputfield',
2506       maxlength => 255,
2507       name      => 'admin',
2508       size      => 20,
2509       type      => 'text',
2510       value     => $system ? $system{admin} : '',
2511     };
2512     display th {class => 'label'}, 'Admin Email:';
2513     display td {
2514       class => 'data',
2515     }, input {
2516       class     => 'inputfield',
2517       maxlength => 255,
2518       name      => 'email',
2519       size      => 20,
2520       type      => 'text',
2521       value     => $system ? $system{email} : '',
2522     };
2523
2524     display th {class => 'label'}, 'Threshold:';
2525     display td {
2526       class => 'dataRight',
2527     }, input {
2528       class     => 'inputfieldRight',
2529       maxlength => 5,
2530       name      => 'loadavgThreshold',
2531       size      => 3,
2532       type      => 'text',
2533       value     => $system
2534                  ? $system{loadavgThreshold}
2535                  : $Clearadm::CLEAROPTS{CLEARADM_LOADAVG_THRESHOLD},
2536     };
2537
2538     my $historyDropdown = popup_menu {
2539       name    => 'loadavgHist',
2540       class   => 'dropdown',
2541       values  => [
2542         '1 month',
2543         '2 months',
2544         '3 months',
2545         '4 months',
2546         '5 months',
2547         '6 months',
2548         '7 months',
2549         '8 months',
2550         '9 months',
2551         '10 months',
2552         '11 months',
2553         '1 year',
2554       ],
2555       default => $system ? $system{loadavgHist} : '6 months',
2556     };
2557
2558     display th {class => 'label'}, 'History:';
2559     display td {
2560       class => 'dataRight',
2561     }, $historyDropdown;
2562
2563   my $description = $system ? $system{description} : '';
2564      $description =~ s/\r\n/<br>/g;
2565
2566   display start_Tr;
2567     display th {class => 'label'}, 'Description:';
2568     display td {
2569       class   => 'data',
2570       colspan => 7,
2571     }, textarea {
2572       class   => 'inputfield',
2573       cols    => 103,
2574       name    => 'description',
2575       rows    => 3,
2576       value   => $description,
2577     };
2578   display end_Tr;
2579   display end_table;
2580
2581   display '<center>';
2582   display p submit ({value => $system ? 'Update' : 'Add'}),  reset;
2583   display '</center>';
2584
2585   display end_form;
2586
2587   return;
2588 } # editSystem
2589
2590 sub editTask (;$) {
2591   my ($task) = @_;
2592
2593   display start_form (
2594     -method   => 'post',
2595     -action   => 'processtask.cgi',
2596     -onsubmit => 'return validateTask (this);',
2597   );
2598
2599   my %task;
2600
2601   if ($task) {
2602     %task = $clearadm->GetTask ($task);
2603
2604     return
2605       unless %task;
2606
2607     display input {
2608       name  => 'oldname',
2609       type  => 'hidden',
2610       value => $task,
2611     };
2612   } else {
2613     $task = '';
2614   } # if
2615
2616   display input {
2617     name  => 'action',
2618     type  => 'hidden',
2619     value => 'Post',
2620   };
2621
2622   display start_table {cellspacing => 1};
2623
2624   display start_Tr;
2625     display th {class => 'labelCentered'}, 'Name';
2626     display th {class => 'labelCentered'}, 'System';
2627     display th {class => 'labelCentered'}, 'Description';
2628     display th {class => 'labelCentered'}, 'Command';
2629     display th {class => 'labelCentered'}, 'Restartable';
2630   display end_Tr;
2631
2632   display start_Tr;
2633     display td {
2634       class => 'data',
2635     }, input {
2636       class     => 'inputfield',
2637       maxlength => 255,
2638       name      => 'name',
2639       size      => 15,
2640       type      => 'text',
2641       value     => $task ? $task{name} : '',
2642     };
2643     my $systemDropdown = makeSystemDropdown (
2644       undef,
2645       $task{system} ? $task{system} : 'localhost',
2646       undef, (
2647         'localhost' => 'localhost',
2648       ),
2649     );
2650
2651     display td {class => 'data'}, $systemDropdown;
2652
2653     display td {
2654       class => 'data',
2655     }, input {
2656       class     => 'inputfield',
2657       maxlength => 255,
2658       name      => 'description',
2659       size      => 30,
2660       type      => 'text',
2661       value     => $task ? $task{description} : '',
2662     };
2663
2664     display td {
2665       class => 'data',
2666     }, input {
2667       class     => 'inputfield',
2668       maxlength => 255,
2669       name      => 'command',
2670       size      => 40,
2671       type      => 'text',
2672       value     => $task ? $task{command} : '',
2673     };
2674
2675     display td {
2676       class => 'dataCentered',
2677     }, makeRestartableDropdown undef, $task{restartable};
2678
2679   display end_Tr;
2680   display end_table;
2681
2682   display '<center>';
2683   display p submit ({value => $task ? 'Update' : 'Add'}),  reset;
2684   display '</center>';
2685
2686   display end_form;
2687
2688   return;
2689 } # editTask
2690
2691 sub footing () {
2692   my $clearscm = a {-href => 'http://clearscm.com'}, 'ClearSCM, Inc.';
2693
2694   # Figure out which script by using CLEARADM_BASE.
2695   my $script = basename (url {-absolute => 1});
2696      $script = 'index.cgi'
2697        if $script eq 'clearadm';
2698
2699   my $scriptFullPath = "$Clearadm::CLEAROPTS{CLEARADM_BASE}/$script";
2700
2701   my ($year, $mon, $mday, $hour, $min, $sec) =
2702     ymdhms ((stat ($scriptFullPath))[9]);
2703
2704   my $dateModified = "$mon/$mday/$year @ $hour:$min";
2705
2706   $script = a {
2707     -href => "http://clearscm.com/php/scm_man.php?file=clearadm/$script"
2708   }, $script;
2709
2710   display end_div;
2711
2712   display start_div {-class => 'copyright'};
2713     display "$script: Last modified: $dateModified";
2714     display br "Copyright &copy; $year, $clearscm - All rights reserved";
2715   display end_div;
2716
2717   print end_html;
2718
2719   return;
2720 } # footing
2721
2722 1;
2723
2724 =pod
2725
2726 =head1 CONFIGURATION AND ENVIRONMENT
2727
2728 DEBUG: If set then $debug is set to this level.
2729
2730 VERBOSE: If set then $verbose is set to this level.
2731
2732 TRACE: If set then $trace is set to this level.
2733
2734 =head1 DEPENDENCIES
2735
2736 =head2 Perl Modules
2737
2738 L<Carp>
2739
2740 L<CGI>
2741
2742 L<File::Basename|File::Basename>
2743
2744 L<FindBin>
2745
2746 L<GD>
2747
2748 =head2 ClearSCM Perl Modules
2749
2750 =begin man
2751
2752  Clearadm
2753  DateUtils
2754  Display
2755  Utils
2756
2757 =end man
2758
2759 =begin html
2760
2761 <blockquote>
2762 <a href="http://clearscm.com/php/scm_man.php?file=lib/Clearadm.pm">Clearadm</a><br>
2763 <a href="http://clearscm.com/php/scm_man.php?file=lib/DateUtils.pm">DateUtils</a><br>
2764 <a href="http://clearscm.com/php/scm_man.php?file=lib/Display.pm">Display</a><br>
2765 <a href="http://clearscm.com/php/scm_man.php?file=lib/Utils.pm">Utils</a><br>
2766 </blockquote>
2767
2768 =end html
2769
2770 =head1 BUGS AND LIMITATIONS
2771
2772 There are no known bugs in this module.
2773
2774 Please report problems to Andrew DeFaria <Andrew@ClearSCM.com>.
2775
2776 =head1 LICENSE AND COPYRIGHT
2777
2778 Copyright (c) 2010, ClearSCM, Inc. All rights reserved.
2779
2780 =cut