s/issue/bug/g + updated ncdc-share-report

This commit is contained in:
Yorhel 2012-03-30 13:50:56 +02:00
parent 05c36a1aef
commit d6865e7b42
5 changed files with 121 additions and 119 deletions

View file

@ -22,7 +22,7 @@
# TODO: Atom feed? # TODO: Atom feed?
package TUWF::Issue; package TUWF::Bug;
use TUWF ':html', 'html_escape'; use TUWF ':html', 'html_escape';
@ -100,21 +100,21 @@ sub dbSave {
# TODO: pagination / filtering # TODO: pagination / filtering
sub htmlListing { sub htmlListing {
my($s, $l, $lnk) = @_; my($s, $l, $lnk) = @_;
table class => 'issue_listing'; table class => 'bug_listing';
thead; Tr; thead; Tr;
td class => 'issue_col_id', 'Id'; td class => 'bug_col_id', 'Id';
td class => 'issue_col_type', 'Type'; td class => 'bug_col_type', 'Type';
td class => 'issue_col_status', 'Status'; td class => 'bug_col_status', 'Status';
td class => 'issue_col_date', 'Updated'; td class => 'bug_col_date', 'Updated';
td class => 'issue_col_summary','Summary'; td class => 'bug_col_summary','Summary';
end; end; end; end;
for(@$l) { for(@$l) {
Tr $_->{closed} ? (class => 'issue_closed') : (); Tr $_->{closed} ? (class => 'bug_closed') : ();
td class => 'issue_col_id', $_->{issue}; td class => 'bug_col_id', $_->{issue};
td class => 'issue_col_type', $_->{type}; td class => 'bug_col_type', $_->{type};
td class => 'issue_col_status', $_->{status}; td class => 'bug_col_status', $_->{status};
td class => 'issue_col_date', $_->{date}; td class => 'bug_col_date', $_->{date};
td class => 'issue_col_summary'; td class => 'bug_col_summary';
a href => $lnk->($_->{issue}), $_->{summary}; a href => $lnk->($_->{issue}), $_->{summary};
end; end;
end; end;
@ -138,16 +138,16 @@ sub _escape_url {
sub htmlItem { sub htmlItem {
my($s, $d) = @_; my($s, $d) = @_;
my $last = $d->[$#$d]; my $last = $d->[$#$d];
dl class => 'issue_status'; dl class => 'bug_status';
dt 'Id'; dd $last->{issue}; dt 'Id'; dd $last->{issue};
dt 'Messages'; dd $#$d+1; dt 'Messages'; dd $#$d+1;
dt 'Type'; dd $last->{type}; dt 'Type'; dd $last->{type};
dt 'Status'; dd $last->{status}; dt 'Status'; dd $last->{status};
end; end;
div class => 'issue_item'; div class => 'bug_item';
my $num = -1; my $num = -1;
for my $m (@$d) { for my $m (@$d) {
div class => 'issue_message'; div class => 'bug_message';
h1 !++$num ? 'Description' : "Reply $num"; h1 !++$num ? 'Description' : "Reply $num";
dl; dl;
dt !$num ? 'Created' : 'Added'; dd $m->{date}; dt !$num ? 'Created' : 'Added'; dd $m->{date};
@ -172,49 +172,49 @@ sub htmlItem {
sub htmlForm { sub htmlForm {
my($s, $l, $url) = @_; my($s, $l, $url) = @_;
# TODO: anti-spam JS # TODO: anti-spam JS
form class => 'issue_frm', action => $url, method => 'post'; form class => 'bug_frm', action => $url, method => 'post';
fieldset; fieldset;
input type => 'hidden', name => 'issue_id', value => $l ? $l->{issue} : 0; input type => 'hidden', name => 'bug_id', value => $l ? $l->{issue} : 0;
legend $l ? 'Reply' : 'Report a new issue'; legend $l ? 'Reply' : 'Report a new bug';
ul; ul;
li class => 'issue_frm_summary'; li class => 'bug_frm_summary';
label for => 'issue_summary', 'Summary'; label for => 'bug_summary', 'Summary';
input type => 'text', name => 'issue_summary', id => 'issue_summary', size => 45, value => $l?$l->{summary}:''; input type => 'text', name => 'bug_summary', id => 'bug_summary', size => 45, value => $l?$l->{summary}:'';
end; end;
li class => 'issue_frm_mail'; li class => 'bug_frm_mail';
label for => 'issue_email', 'Email'; label for => 'bug_email', 'Email';
input type => 'text', name => 'issue_email', id => 'issue_email', size => 20; input type => 'text', name => 'bug_email', id => 'bug_email', size => 20;
lit ' '; lit ' ';
txt 'Optional, only used for notifications.'; txt 'Optional, only used for notifications.';
end; end;
if($l) { if($l) {
li class => 'issue_frm_admin'; li class => 'bug_frm_admin';
label for => 'issue_type', 'Admin'; label for => 'bug_type', 'Admin';
Select name => 'issue_type'; Select name => 'bug_type';
option value => $_, $_ eq $l->{type} ? (selected => 'selected') : (), $_ for @{$s->{types}}; option value => $_, $_ eq $l->{type} ? (selected => 'selected') : (), $_ for @{$s->{types}};
end; end;
Select name => 'issue_status'; Select name => 'bug_status';
option value => $_, $_ eq $l->{status} ? (selected => 'selected') : (), $_ for @{$s->{statusses}}; option value => $_, $_ eq $l->{status} ? (selected => 'selected') : (), $_ for @{$s->{statusses}};
end; end;
Select name => 'issue_closed'; Select name => 'bug_closed';
option value => 0, !$l->{closed} ? (selected => 'selected') : (), 'Open'; option value => 0, !$l->{closed} ? (selected => 'selected') : (), 'Open';
option value => 1, $l->{closed} ? (selected => 'selected') : (), 'Closed'; option value => 1, $l->{closed} ? (selected => 'selected') : (), 'Closed';
end; end;
input type => 'password', name => 'issue_code', id => 'issue_code', size => 10, value => 'code'; input type => 'password', name => 'bug_code', id => 'bug_code', size => 10, value => 'code';
end; end;
} else { } else {
li class => 'issue_frm_type'; li class => 'bug_frm_type';
label for => 'issue_type', 'Type'; label for => 'bug_type', 'Type';
Select name => 'issue_type'; Select name => 'bug_type';
option value => $_, $_ eq $s->{default_type} ? (selected => 'selected') : (), $_ for @{$s->{types}}; option value => $_, $_ eq $s->{default_type} ? (selected => 'selected') : (), $_ for @{$s->{types}};
end; end;
end; end;
} }
li class => 'issue_frm_message'; li class => 'bug_frm_message';
textarea name => 'issue_message';end; br; textarea name => 'bug_message';end; br;
lit 'Please use a <a href="http://p.blicky.net/">pastebin</a> if you want to include large chunks of code or program output.'; lit 'Please use a <a href="http://p.blicky.net/">pastebin</a> if you want to include large chunks of code or program output.';
end; end;
li class => 'issue_frm_submit'; li class => 'bug_frm_submit';
input type => 'submit', value => 'Submit'; input type => 'submit', value => 'Submit';
end; end;
end 'ul'; end 'ul';
@ -226,60 +226,60 @@ sub htmlForm {
sub handleForm { sub handleForm {
my($s, $url) = @_; my($s, $url) = @_;
my $f = $TUWF::OBJ->formValidate( my $f = $TUWF::OBJ->formValidate(
{ post => 'issue_id', min => 0 }, { post => 'bug_id', min => 0 },
{ post => 'issue_summary', maxlength => 200, minlength => 2 }, { post => 'bug_summary', maxlength => 200, minlength => 2 },
{ post => 'issue_email', required => 0, regex => qr/^[^@<>]+@[^@.<>]+(?:\.[^@.<>]+)+$/ }, { post => 'bug_email', required => 0, regex => qr/^[^@<>]+@[^@.<>]+(?:\.[^@.<>]+)+$/ },
{ post => 'issue_code', required => 0, default => '' }, { post => 'bug_code', required => 0, default => '' },
{ post => 'issue_message', maxlength => 256*1024, minlength => 1 }, { post => 'bug_message', maxlength => 256*1024, minlength => 1 },
); );
return($f, undef) if $f->{_err}; return($f, undef) if $f->{_err};
my $l; my $l;
# Reply # Reply
if($f->{issue_id} > 0) { if($f->{bug_id} > 0) {
$l = $s->dbListing(id => $f->{issue_id})->[0]; $l = $s->dbListing(id => $f->{bug_id})->[0];
push @{$f->{_err}}, ['issue_id', 'db_check', ''] and return($f, undef) if !$l; push @{$f->{_err}}, ['bug_id', 'db_check', ''] and return($f, undef) if !$l;
# Check admin things # Check admin things
if(grep $_ eq $f->{issue_code}, @{$s->{admins}}) { if(grep $_ eq $f->{bug_code}, @{$s->{admins}}) {
my $fa = $TUWF::OBJ->formValidate( my $fa = $TUWF::OBJ->formValidate(
{ post => 'issue_type', enum => $s->{types} }, { post => 'bug_type', enum => $s->{types} },
{ post => 'issue_status', enum => $s->{statusses} }, { post => 'bug_status', enum => $s->{statusses} },
{ post => 'issue_closed', enum => [0,1] }, { post => 'bug_closed', enum => [0,1] },
); );
$f = { %$f, %$fa }; $f = { %$f, %$fa };
return($f, $l) if $f->{_err}; return($f, $l) if $f->{_err};
} else { } else {
$f->{issue_type} = $l->{type}; $f->{bug_type} = $l->{type};
$f->{issue_status} = $l->{status}; $f->{bug_status} = $l->{status};
$f->{issue_closed} = $l->{closed}; $f->{bug_closed} = $l->{closed};
} }
# New issue # New bug
} else { } else {
$f->{issue_status} = $s->{default_status}; $f->{bug_status} = $s->{default_status};
$f->{issue_closed} = 0; $f->{bug_closed} = 0;
my $fa = $TUWF::OBJ->formValidate({ post => 'issue_type', enum => $s->{types} }); my $fa = $TUWF::OBJ->formValidate({ post => 'bug_type', enum => $s->{types} });
$f = { %$f, %$fa }; $f = { %$f, %$fa };
return($f, $l) if $f->{_err}; return($f, $l) if $f->{_err};
} }
# No errors? Save! # No errors? Save!
my $id = $s->dbSave(map $f->{"issue_$_"}, qw|id closed summary email type status message|); my $id = $s->dbSave(map $f->{"bug_$_"}, qw|id closed summary email type status message|);
# For replies, send out notification emails # For replies, send out notification emails
if($l) { if($l) {
my $mails = $s->dbEmails($id); my $mails = $s->dbEmails($id);
my $u = $url->($id); my $u = $url->($id);
for(grep $_ ne $f->{issue_email}, @$mails) { for(grep $_ ne $f->{bug_email}, @$mails) {
$TUWF::OBJ->mail( $TUWF::OBJ->mail(
"Hello!\n\n". "Hello!\n\n".
"A new reply has been posted to an issue you have previously shown\n". "A new reply has been posted to an bug you have previously shown\n".
"an interest in. You can view the reply at the following URL:\n". "an interest in. You can view the reply at the following URL:\n".
" $u\n\n". " $u\n\n".
"If you do not wish to receive any more notifications for this (and\n". "If you do not wish to receive any more notifications for this (and\n".
"perhaps other) issues, please reply to this email stating your intent.", "perhaps other) bugs, please reply to this email stating your intent.",
Subject => "Reply to $f->{issue_summary}", Subject => "Reply to $f->{bug_summary}",
To => "$_", To => "$_",
); );
} }

View file

@ -59,5 +59,5 @@ it. L<source|http://p.blicky.net/agolr>
December 2011. Playing around with the Go programming language, I wrote another December 2011. Playing around with the Go programming language, I wrote another
transfer log parser and statistics generator for ncdc. transfer log parser and statistics generator for ncdc.
L<source|http://p.blicky.net/6yx2d> (L<older L<0.3|http://p.blicky.net/h25z8>
version|http://p.blicky.net/ab4lm>). (L<0.2|http://p.blicky.net/6yx2d>, L<0.1|http://p.blicky.net/ab4lm>).

View file

@ -157,5 +157,5 @@ myself, though. I just run ncdc directly on my router. :-)
Nothing like that is included in the release yet, but there is a simple Perl Nothing like that is included in the release yet, but there is a simple Perl
script available: L<ncdc-transfer-stats|http://p.blicky.net/agolr>, and a short script available: L<ncdc-transfer-stats|http://p.blicky.net/agolr>, and a short
Go program: L<ncdc-share-report|http://p.blicky.net/6yx2d>. Go program: L<ncdc-share-report|http://p.blicky.net/h25z8>.

View file

@ -12,8 +12,9 @@ BEGIN { ($ROOT = abs_path $0) =~ s{index\.cgi$}{}; }
my @changes = ( my @changes = (
[ '2012-03-24', '/ncdu/issue', 'Moved issue tracker from sourceforge to this site' ], [ '2012-03-30', '/dump', 'Updated ncdc-share-report for Go 1' ],
[ '2012-03-17', '/ncdc/issue', 'Wrote a small issue tracker for ncdc' ], [ '2012-03-24', '/ncdu/bug', 'Moved ncdu bug tracker from sourceforge to this site' ],
[ '2012-03-17', '/ncdc/bug', 'Wrote a small bug tracker for ncdc' ],
[ '2012-03-14', '/ncdc', 'ncdc 1.9 released.' ], [ '2012-03-14', '/ncdc', 'ncdc 1.9 released.' ],
[ '2012-02-15', '/doc/commvis', 'Added an article on my new communication system.' ], [ '2012-02-15', '/doc/commvis', 'Added an article on my new communication system.' ],
[ '2012-02-13', '/ncdc', 'ncdc 1.8 released.' ], [ '2012-02-13', '/ncdc', 'ncdc 1.8 released.' ],
@ -76,16 +77,16 @@ TUWF::register(
qr{dump/grenamr} => sub { podpage(shift, 'dump-grenamr', 'dump', 'grenamr', 'GTK+ Mass File Renamer') }, qr{dump/grenamr} => sub { podpage(shift, 'dump-grenamr', 'dump', 'grenamr', 'GTK+ Mass File Renamer') },
qr{dump/nccolour} => sub { podpage(shift, 'dump-nccolour', 'dump', 'nccolour', 'Colours in NCurses') }, qr{dump/nccolour} => sub { podpage(shift, 'dump-nccolour', 'dump', 'nccolour', 'Colours in NCurses') },
qr{feed\.atom} => \&atom, qr{feed\.atom} => \&atom,
qr{(ncdc|ncdu)/issue} => \&issue_list, qr{(ncdc|ncdu)/bug} => \&bug_list,
qr{(ncdc|ncdu)/issue/post} => \&issue_post, qr{(ncdc|ncdu)/bug/post} => \&bug_post,
qr{(ncdc|ncdu)/issue/new} => \&issue_new, qr{(ncdc|ncdu)/bug/new} => \&bug_new,
qr{(ncdc|ncdu)/issue/([1-9][0-9]*)} => \&issue_item, qr{(ncdc|ncdu)/bug/([1-9][0-9]*)} => \&bug_item,
); );
TUWF::set( TUWF::set(
logfile => '/www/err.log', logfile => '/www/err.log',
error_404_handler => \&notfound, error_404_handler => \&notfound,
mail_from => 'Yorhel\'s issue tracker <projects@yorhel.nl>', mail_from => 'Yorhel\'s Bug Tracker <projects@yorhel.nl>',
# this is a fairly static site, allow some aggressive caching # this is a fairly static site, allow some aggressive caching
pre_request_handler => sub { $_[0]->resHeader('Cache-Control', 's-max-age=86400, max-age=3600'); 1; }, pre_request_handler => sub { $_[0]->resHeader('Cache-Control', 's-max-age=86400, max-age=3600'); 1; },
); );
@ -189,6 +190,7 @@ sub notfound {
[ 'dump/grenamr', '/dump/grenamr' ], [ 'dump/grenamr', '/dump/grenamr' ],
); );
return $s->resRedirect("/$u", 'perm') if $u =~ s/\/$//; return $s->resRedirect("/$u", 'perm') if $u =~ s/\/$//;
return $s->resRedirect("/$1/bug$2", 'perm') if $u =~ /^(ncd[uc])\/issue(.*)$/;
$s->resStatus(404); $s->resStatus(404);
$s->htmlHeader(title => '404', page => '404'); $s->htmlHeader(title => '404', page => '404');
txt 'Sorry, there is no page at this URI. Try one of the links from the menu to find the page you are looking for.'; txt 'Sorry, there is no page at this URI. Try one of the links from the menu to find the page you are looking for.';
@ -198,69 +200,69 @@ sub notfound {
# Issue handling # Bug tracker
sub _issue_init { sub _bug_init {
require "$ROOT/Issue.pm"; require "$ROOT/Bug.pm";
my($s, $p) = @_; my($s, $p) = @_;
$s->resHeader('Cache-Control', 'no-cache'); $s->resHeader('Cache-Control', 'no-cache');
$s->_load_module('TUWF::DB'); $s->_load_module('TUWF::DB');
$s->{_TUWF}{db_login} = [ undef, undef, undef ]; $s->{_TUWF}{db_login} = [ undef, undef, undef ];
$s->dbInit; $s->dbInit;
return TUWF::Issue->new(prefix => $p.'_', admins => [ $ENV{ISSUE_CODE} ]); return TUWF::Bug->new(prefix => $p.'_', admins => [ $ENV{ISSUE_CODE} ]);
} }
sub issue_list { sub bug_list {
my($s, $p) = @_; my($s, $p) = @_;
my $is = _issue_init(@_); my $is = _bug_init(@_);
$s->htmlHeader(title => "\u$p Issue tracker", page => $p, sec => 'issue'); $s->htmlHeader(title => "\u$p Bug tracker", page => $p, sec => 'bug');
br; a href => "/$p/issue/new", 'Report new issue'; br; br; br; a href => "/$p/bug/new", 'Report new bug'; br; br;
$is->htmlListing((scalar $is->dbListing()), sub { "/$p/issue/".shift }); $is->htmlListing((scalar $is->dbListing()), sub { "/$p/bug/".shift });
br; a href => "/$p/issue/new", 'Report new issue'; br; br; br; a href => "/$p/bug/new", 'Report new bug'; br; br;
$s->htmlFooter; $s->htmlFooter;
} }
sub issue_new { sub bug_new {
my($s, $p) = @_; my($s, $p) = @_;
my $is = _issue_init(@_); my $is = _bug_init(@_);
$s->htmlHeader(title => "\u$p: Report new issue", page => $p, sec => 'issue'); $s->htmlHeader(title => "\u$p: Report new bug", page => $p, sec => 'bug');
br; a href => "/$p/issue", 'Back to the issue index'; br; br; br; a href => "/$p/bug", 'Back to the bug index'; br; br;
$is->htmlForm(undef, "/$p/issue/post"); $is->htmlForm(undef, "/$p/bug/post");
$s->htmlFooter; $s->htmlFooter;
} }
sub issue_post { sub bug_post {
my($s, $p) = @_; my($s, $p) = @_;
return $s->resNotFound if $s->reqMethod() ne 'POST'; return $s->resNotFound if $s->reqMethod() ne 'POST';
my $is = _issue_init($s, $p); my $is = _bug_init($s, $p);
my($f, $l) = $is->handleForm(sub { "http://dev.yorhel.nl/$p/issue/".shift }); my($f, $l) = $is->handleForm(sub { "http://dev.yorhel.nl/$p/bug/".shift });
if($f->{_err}) { if($f->{_err}) {
$s->htmlHeader(title => 'Error creating message', page => $p, sec => 'issue'); $s->htmlHeader(title => 'Error creating message', page => $p, sec => 'bug');
p 'There was an error in the form. Please use the \'back\' button of your p 'There was an error in the form. Please use the \'back\' button of your
browser to go back to the form (hopefully) without losing your message. browser to go back to the form (hopefully) without losing your message.
There was an error in the following fields: '.join(', ', map {(my$f=$_->[0])=~s/issue_// ;"\u$f"} @{$f->{_err}}).'.'; There was an error in the following fields: '.join(', ', map {(my$f=$_->[0])=~s/bug_// ;"\u$f"} @{$f->{_err}}).'.';
return $s->htmlFooter; return $s->htmlFooter;
} }
$s->resRedirect("/$p/issue/$l->{issue}", 'post'); $s->resRedirect("/$p/bug/$l->{bug}", 'post');
} }
sub issue_item { sub bug_item {
my($s, $p, $i) = @_; my($s, $p, $i) = @_;
my $is = _issue_init($s, $p); my $is = _bug_init($s, $p);
my $item = $is->dbItem($i); my $item = $is->dbItem($i);
return $s->resNotFound if !@$item; return $s->resNotFound if !@$item;
my $last = $item->[$#$item]; my $last = $item->[$#$item];
$s->htmlHeader(title => "\u$p: $last->{summary}", page => $p, sec => 'issue'); $s->htmlHeader(title => "\u$p: $last->{summary}", page => $p, sec => 'bug');
br; a href => "/$p/issue", 'Back to the issue index'; br; br; br; a href => "/$p/bug", 'Back to the bug index'; br; br;
$is->htmlItem($item); $is->htmlItem($item);
$is->htmlForm($last, "/$p/issue/post") if !$last->{closed}; $is->htmlForm($last, "/$p/bug/post") if !$last->{closed};
br; a href => "/$p/issue", 'Back to the issue index'; br; br; br; a href => "/$p/bug", 'Back to the bug index'; br; br;
$s->htmlFooter; $s->htmlFooter;
} }
@ -404,7 +406,7 @@ sub htmlMenu {
$m->('/ncdu/man', 'Manual', $o{sec} eq 'man'); $m->('/ncdu/man', 'Manual', $o{sec} eq 'man');
$m->('/ncdu/changes', 'Changelog', $o{sec} eq 'changes'); $m->('/ncdu/changes', 'Changelog', $o{sec} eq 'changes');
$m->('/ncdu/scr', 'Screenshots', $o{sec} eq 'scr'); $m->('/ncdu/scr', 'Screenshots', $o{sec} eq 'scr');
$m->('/ncdu/issue', 'Issue tracker', $o{sec} eq 'issue'); $m->('/ncdu/bug', 'Bug tracker', $o{sec} eq 'bug');
}); });
$m->('/ncdc', 'Ncdc', $o{page} eq 'ncdc', sub { $m->('/ncdc', 'Ncdc', $o{page} eq 'ncdc', sub {
$m->('/ncdc', 'Info', !$o{sec}); $m->('/ncdc', 'Info', !$o{sec});
@ -412,7 +414,7 @@ sub htmlMenu {
$m->('/ncdc/man', 'Manual', $o{sec} eq 'man'); $m->('/ncdc/man', 'Manual', $o{sec} eq 'man');
$m->('/ncdc/changes', 'Changelog', $o{sec} eq 'changes'); $m->('/ncdc/changes', 'Changelog', $o{sec} eq 'changes');
$m->('/ncdc/scr', 'Screenshots', $o{sec} eq 'scr'); $m->('/ncdc/scr', 'Screenshots', $o{sec} eq 'scr');
$m->('/ncdc/issue', 'Issue tracker', $o{sec} eq 'issue'); $m->('/ncdc/bug', 'Bug tracker', $o{sec} eq 'bug');
}); });
$m->('/tuwf', 'Tuwf', $o{page} eq 'tuwf', sub { $m->('/tuwf', 'Tuwf', $o{page} eq 'tuwf', sub {
$m->('/tuwf', 'Info', !$o{sec}); $m->('/tuwf', 'Info', !$o{sec});

View file

@ -65,23 +65,23 @@ textarea:focus, input:focus { background: #fff }
table { border-collapse: collapse } table { border-collapse: collapse }
table td { padding: 0 2px } table td { padding: 0 2px }
table thead td { font-weight: bold } table thead td { font-weight: bold }
.issue_listing tbody tr:nth-child(odd) { background-color: #f4f4f4 } .bug_listing tbody tr:nth-child(odd) { background-color: #f4f4f4 }
.issue_listing { width: 95% } .bug_listing { width: 95% }
.issue_col_id, .issue_col_type, .issue_col_status, .issue_col_date { white-space: nowrap } .bug_col_id, .bug_col_type, .bug_col_status, .bug_col_date { white-space: nowrap }
.issue_closed td { text-decoration: line-through } .bug_closed td { text-decoration: line-through }
.issue_status { display: block; height: 20px } .bug_status { display: block; height: 20px }
.issue_status dt { float: left; font-weight: bold } .bug_status dt { float: left; font-weight: bold }
.issue_status dd { float: left; } .bug_status dd { float: left; }
.issue_item h1 { margin-top: 30px } .bug_item h1 { margin-top: 30px }
.issue_item dt { clear: left; float: left; font-weight: bold; width: 60px } .bug_item dt { clear: left; float: left; font-weight: bold; width: 60px }
.issue_item dd { float: left; padding-right: 20px } .bug_item dd { float: left; padding-right: 20px }
.issue_item p { clear: left; padding-top: 5px } .bug_item p { clear: left; padding-top: 5px }
.issue_frm fieldset { border: 0; margin-top: 40px } .bug_frm fieldset { border: 0; margin-top: 40px }
.issue_frm legend { font-size: 19px; color: #000; } .bug_frm legend { font-size: 19px; color: #000; }
.issue_frm li { list-style-type: none; margin-left: 10px; clear: left; padding-top: 5px } .bug_frm li { list-style-type: none; margin-left: 10px; clear: left; padding-top: 5px }
.issue_frm label { display: block; width: 80px; float: left } .bug_frm label { display: block; width: 80px; float: left }
.issue_frm input, .issue_frm select { float: left } .bug_frm input, .bug_frm select { float: left }
.issue_frm textarea { width: 100%; height: 200px } .bug_frm textarea { width: 100%; height: 200px }
.issue_frm_submit input { float: right; width: 200px } .bug_frm_submit input { float: right; width: 200px }
.issue_status dt::after, .issue_item dt::after, .issue_frm label::after { content: ":" } .bug_status dt::after, .bug_item dt::after, .bug_frm label::after { content: ":" }