From: Kohei Yoshino Date: Tue, 16 Jul 2019 22:01:16 +0000 (-0400) Subject: Bug 1546717 - Add the ability to search on count gt/lt/eq X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c65fadc9de07a0bde4a045a6ad130cd99b4d4315;p=thirdparty%2Fbugzilla.git Bug 1546717 - Add the ability to search on count gt/lt/eq --- diff --git a/Bugzilla/Bug.pm b/Bugzilla/Bug.pm index 30c9462d9..8ab96c1ee 100644 --- a/Bugzilla/Bug.pm +++ b/Bugzilla/Bug.pm @@ -4053,6 +4053,27 @@ sub comment_count { ); } +sub counts { + my ($self) = @_; + my $dbh = Bugzilla->dbh; + my $extra = !Bugzilla->user->is_insider ? 'AND isprivate = 0' : ''; + my $id = $self->id; + + $self->{counts} ||= $dbh->selectrow_hashref("SELECT + (SELECT COUNT(*) FROM attachments WHERE bug_id = ? $extra) AS attachments, + (SELECT COUNT(*) FROM cc WHERE bug_id = ?) AS cc, + (SELECT COUNT(*) FROM longdescs WHERE bug_id = ? $extra) AS comments, + (SELECT COUNT(*) FROM keywords WHERE bug_id = ?) AS keywords, + (SELECT COUNT(*) FROM dependencies WHERE blocked = ?) AS blocks, + (SELECT COUNT(*) FROM dependencies WHERE dependson = ?) AS depends_on, + (SELECT COUNT(*) FROM regressions WHERE regressed_by = ?) AS regressed_by, + (SELECT COUNT(*) FROM regressions WHERE regresses = ?) AS regressions, + (SELECT COUNT(*) FROM duplicates WHERE dupe_of = ?) AS duplicates + ", undef, $id, $id, $id, $id, $id, $id, $id, $id, $id); + + return $self->{counts}; +} + # This is needed by xt/search.t. sub percentage_complete { my $self = shift; diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index 5aedef21b..7d0351b06 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -242,6 +242,13 @@ use constant DEFAULT_FIELDS => ( type => FIELD_TYPE_KEYWORDS, buglist => 1 }, + { + name => 'keywords.count', + desc => 'Number of Keywords', + type => FIELD_TYPE_INTEGER, + buglist => 1, + is_numeric => 1, + }, { name => 'resolution', desc => 'Resolution', @@ -297,38 +304,82 @@ use constant DEFAULT_FIELDS => ( type => FIELD_TYPE_USERS, in_new_bugmail => 1, }, + { + name => 'cc_count', # Originated in BMO extension + desc => 'Number of CC', + type => FIELD_TYPE_INTEGER, + buglist => 1, + is_numeric => 1, + }, { name => 'dependson', desc => 'Depends on', type => FIELD_TYPE_BUG_LIST, in_new_bugmail => 1, - is_numeric => 1, buglist => 1 }, + { + name => 'dependson.count', + desc => 'Number of Depends on', + type => FIELD_TYPE_INTEGER, + buglist => 1, + is_numeric => 1, + }, { name => 'blocked', desc => 'Blocks', type => FIELD_TYPE_BUG_LIST, in_new_bugmail => 1, - is_numeric => 1, buglist => 1 }, + { + name => 'blocked.count', + desc => 'Number of Blocks', + type => FIELD_TYPE_INTEGER, + buglist => 1, + is_numeric => 1, + }, { name => 'regressed_by', desc => 'Regressed by', type => FIELD_TYPE_BUG_LIST, in_new_bugmail => 1, - is_numeric => 1, buglist => 1 }, + { + name => 'regressed_by.count', + desc => 'Number of Regressed by', + type => FIELD_TYPE_INTEGER, + buglist => 1, + is_numeric => 1, + }, { name => 'regresses', desc => 'Regressions', type => FIELD_TYPE_BUG_LIST, in_new_bugmail => 1, - is_numeric => 1, buglist => 1 }, + { + name => 'regresses.count', + desc => 'Number of Regressions', + type => FIELD_TYPE_INTEGER, + buglist => 1, + is_numeric => 1, + }, + { + name => 'dupe_count', # Originated in BMO extension + desc => 'Number of Duplicates', + type => FIELD_TYPE_INTEGER, + buglist => 1, + is_numeric => 1, + }, + { + name => 'duplicates', + desc => 'Duplicates', + type => FIELD_TYPE_BUG_ID, + buglist => 1, + }, { name => 'assignee_last_login', @@ -337,6 +388,13 @@ use constant DEFAULT_FIELDS => ( buglist => 1 }, + { + name => 'attachments.count', + desc => 'Number of Attachments', + type => FIELD_TYPE_INTEGER, + buglist => 1, + is_numeric => 1, + }, {name => 'attachments.description', desc => 'Attachment description'}, {name => 'attachments.filename', desc => 'Attachment filename'}, {name => 'attachments.mimetype', desc => 'Attachment mime type'}, diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index eb58602c2..e3e2a06e2 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -234,6 +234,16 @@ use constant MULTI_SELECT_OVERRIDE => { _non_changed => \&_multiselect_nonchanged, }; +use constant RELATION_COUNT_OVERRIDE => { + changedby => \&_relation_count_changed, + everchanged => \&_relation_count_changed, + changedbefore => \&_relation_count_changed, + changedafter => \&_relation_count_changed, + changedfrom => \&_invalid_combination, + changedto => \&_invalid_combination, + _default => \&_relation_count_default, +}; + use constant OPERATOR_FIELD_OVERRIDE => { # User fields @@ -273,15 +283,6 @@ use constant OPERATOR_FIELD_OVERRIDE => { changedafter => \&_long_desc_changedbefore_after, _non_changed => \&_long_desc_nonchanged, }, - 'longdescs.count' => { - changedby => \&_long_desc_changedby, - everchanged => \&_long_desc_everchanged, - changedbefore => \&_long_desc_changedbefore_after, - changedafter => \&_long_desc_changedbefore_after, - changedfrom => \&_invalid_combination, - changedto => \&_invalid_combination, - _default => \&_long_descs_count, - }, 'longdescs.isprivate' => MULTI_SELECT_OVERRIDE, owner_idle_time => { greaterthan => \&_owner_idle_time_greater_less, @@ -293,9 +294,29 @@ use constant OPERATOR_FIELD_OVERRIDE => { product => {_non_changed => \&_product_nonchanged,}, regressed_by => MULTI_SELECT_OVERRIDE, regresses => MULTI_SELECT_OVERRIDE, + duplicates => MULTI_SELECT_OVERRIDE, tag => MULTI_SELECT_OVERRIDE, comment_tag => MULTI_SELECT_OVERRIDE, + # Count Fields + 'attachments.count' => RELATION_COUNT_OVERRIDE, + 'cc_count' => RELATION_COUNT_OVERRIDE, + 'keywords.count' => RELATION_COUNT_OVERRIDE, + 'blocked.count' => RELATION_COUNT_OVERRIDE, + 'dependson.count' => RELATION_COUNT_OVERRIDE, + 'regressed_by.count' => RELATION_COUNT_OVERRIDE, + 'regresses.count' => RELATION_COUNT_OVERRIDE, + 'dupe_count' => RELATION_COUNT_OVERRIDE, + 'longdescs.count' => { + changedby => \&_long_desc_changedby, + everchanged => \&_long_desc_everchanged, + changedbefore => \&_long_desc_changedbefore_after, + changedafter => \&_long_desc_changedbefore_after, + changedfrom => \&_invalid_combination, + changedto => \&_invalid_combination, + _default => \&_relation_count_default, + }, + # Timetracking Fields deadline => {_non_changed => \&_deadline}, percentage_complete => {_non_changed => \&_percentage_complete,}, @@ -490,11 +511,20 @@ sub COLUMN_JOINS { to => 'id', }, }, - blocked => {table => 'dependencies', to => 'dependson',}, - dependson => {table => 'dependencies', to => 'blocked',}, - regresses => {table => 'regressions', to => 'regressed_by',}, - regressed_by => {table => 'regressions', to => 'regresses',}, - 'longdescs.count' => {table => 'longdescs', join => 'INNER',}, + 'attachments.count' => {table => 'attachments',}, + 'cc_count' => {table => 'cc',}, + 'keywords.count' => {table => 'keywords',}, + 'longdescs.count' => {table => 'longdescs', join => 'INNER',}, + 'blocked' => {table => 'dependencies', to => 'dependson',}, + 'blocked.count' => {table => 'dependencies', to => 'dependson',}, + 'dependson' => {table => 'dependencies', to => 'blocked',}, + 'dependson.count' => {table => 'dependencies', to => 'blocked',}, + 'regressed_by' => {table => 'regressions', to => 'regresses',}, + 'regressed_by.count' => {table => 'regressions', to => 'regresses',}, + 'regresses' => {table => 'regressions', to => 'regressed_by',}, + 'regresses.count' => {table => 'regressions', to => 'regressed_by',}, + 'dupe_count' => {table => 'duplicates', to => 'dupe_of',}, + 'duplicates' => {table => 'duplicates', to => 'dupe_of',}, last_visit_ts => { as => 'bug_user_last_visit', table => 'bug_user_last_visit', @@ -572,15 +602,23 @@ sub COLUMNS { 'DISTINCT ' . $dbh->sql_string_concat('map_flagtypes.name', 'map_flags.status') ), - 'keywords' => $dbh->sql_group_concat('DISTINCT map_keyworddefs.name'), + 'keywords' => $dbh->sql_group_concat('DISTINCT map_keyworddefs.name'), + 'blocked' => $dbh->sql_group_concat('DISTINCT map_blocked.blocked'), + 'dependson' => $dbh->sql_group_concat('DISTINCT map_dependson.dependson'), + 'regressed_by' => $dbh->sql_group_concat('DISTINCT map_regressed_by.regressed_by'), + 'regresses' => $dbh->sql_group_concat('DISTINCT map_regresses.regresses'), + 'duplicates' => $dbh->sql_group_concat('DISTINCT map_duplicates.dupe'), + + 'attachments.count' => 'COUNT(DISTINCT map_attachments_count.attach_id)', + 'cc_count' => 'COUNT(DISTINCT map_cc_count.who)', + 'keywords.count' => 'COUNT(DISTINCT map_keywords_count.keywordid)', + 'longdescs.count' => 'COUNT(DISTINCT map_longdescs_count.comment_id)', + 'blocked.count' => 'COUNT(DISTINCT map_blocked_count.blocked)', + 'dependson.count' => 'COUNT(DISTINCT map_dependson_count.dependson)', + 'regressed_by.count' => 'COUNT(DISTINCT map_regressed_by_count.regressed_by)', + 'regresses.count' => 'COUNT(DISTINCT map_regresses_count.regresses)', + 'dupe_count' => 'COUNT(DISTINCT map_dupe_count.dupe)', - blocked => $dbh->sql_group_concat('DISTINCT map_blocked.blocked'), - dependson => $dbh->sql_group_concat('DISTINCT map_dependson.dependson'), - - regresses => $dbh->sql_group_concat('DISTINCT map_regresses.regresses'), - regressed_by => $dbh->sql_group_concat('DISTINCT map_regressed_by.regressed_by'), - - 'longdescs.count' => 'COUNT(DISTINCT map_longdescs_count.comment_id)', last_visit_ts => 'bug_user_last_visit.last_visit_ts', bug_interest_ts => 'bug_interest.modification_time', assignee_last_login => 'assignee.last_seen_date', @@ -684,15 +722,24 @@ sub REPORT_COLUMNS { # is here because it *always* goes into the GROUP BY as the first item, # so it should be skipped when determining extra GROUP BY columns. use constant GROUP_BY_SKIP => qw( + attachments.count blocked + blocked.count bug_id + cc_count dependson + dependson.count + dupe_count + duplicates flagtypes.name keywords + keywords.count longdescs.count percentage_complete regressed_by + regressed_by.count regresses + regresses.count ); ############### @@ -2759,18 +2806,38 @@ sub _content_matches { $self->COLUMNS->{'relevance'}->{name} = $select_term; } -sub _long_descs_count { - my ($self, $args) = @_; - my ($chart_id, $joins) = @$args{qw(chart_id joins)}; - my $table = "longdescs_count_$chart_id"; - my $extra = $self->_user->is_insider ? "" : "WHERE isprivate = 0"; - my $join = { - table => "(SELECT bug_id, COUNT(*) AS num" - . " FROM longdescs $extra GROUP BY bug_id)", - as => $table, - }; - push(@$joins, $join); - $args->{full_field} = "${table}.num"; +sub _relation_count_changed { + my ($self, $args) = @_; + $args->{field} =~ /^(\w+)\.count$/; + $args->{field} = $args->{full_field} = $1; + $self->_do_operator_function($args); +} + +sub _relation_count_default { + my ($self, $args) = @_; + my ($chart_id, $field, $joins) = @$args{qw(chart_id field joins)}; + my $extra = !$self->_user->is_insider + && $field =~ /^(?:attachments|longdescs)\.count$/ ? 'WHERE isprivate = 0' : ''; + my ($table, $column, $other_column) + = $field eq 'attachments.count' ? ('attachments', 'attach_id', 'bug_id') + : $field eq 'cc_count' ? ('cc', 'cc', 'bug_id') + : $field eq 'keywords.count' ? ('keywords', 'keywords', 'bug_id') + : $field eq 'longdescs.count' ? ('longdescs', 'comment_id', 'bug_id') + : $field eq 'blocked.count' ? ('dependencies', 'blocked', 'dependson') + : $field eq 'dependson.count' ? ('dependencies', 'dependson', 'blocked') + : $field eq 'regressed_by.count' ? ('regressions', 'regressed_by', 'regresses') + : $field eq 'regresses.count' ? ('regressions', 'regresses', 'regressed_by') + : $field eq 'dupe_count' ? ('duplicates', 'dupe', 'dupe_of') + : undef; + my $alias = "${column}_count_${chart_id}"; + + push(@$joins, { + table => "(SELECT $other_column AS bug_id, COUNT(*) AS num" + . " FROM $table $extra GROUP BY $other_column)", + as => $alias, + }); + + $args->{full_field} = "COALESCE(${alias}.num, 0)"; } sub _work_time_changedby { @@ -3173,6 +3240,11 @@ sub _multiselect_table { $args->{full_field} = $field; return "regressions"; } + elsif ($field eq 'duplicates') { + $args->{_select_field} = 'dupe_of'; + $args->{full_field} = 'dupe'; + return "duplicates"; + } elsif ($field eq 'longdesc') { $args->{_extra_where} = " AND isprivate = 0" if !$self->_user->is_insider; $args->{full_field} = 'thetext'; @@ -3285,6 +3357,16 @@ sub _multiselect_isempty { }; return "regressions_$chart_id.$to IS $not NULL"; } + elsif ($field eq 'duplicates') { + push @$joins, + { + table => 'duplicates', + as => "duplicates_$chart_id", + from => 'bug_id', + to => 'dupe_of', + }; + return "duplicates_$chart_id.dupe_of IS $not NULL"; + } elsif ($field eq 'longdesc') { my @extra = ("longdescs_$chart_id.type != " . CMT_HAS_DUPE); push @extra, "longdescs_$chart_id.isprivate = 0" diff --git a/Bugzilla/Search/ClauseGroup.pm b/Bugzilla/Search/ClauseGroup.pm index f7f7b338b..a040442f5 100644 --- a/Bugzilla/Search/ClauseGroup.pm +++ b/Bugzilla/Search/ClauseGroup.pm @@ -18,12 +18,20 @@ use Bugzilla::Search::Condition qw(condition); use List::MoreUtils qw(uniq); use constant UNSUPPORTED_FIELDS => qw( + attachments.count + blocked.count + cc_count classification commenter component + dependson.count + dupe_count + keywords.count longdescs.count product owner_idle_time + regressed_by.count + regresses.count ); sub new { diff --git a/Bugzilla/WebService/Bug.pm b/Bugzilla/WebService/Bug.pm index 107313db6..a300bfaa5 100644 --- a/Bugzilla/WebService/Bug.pm +++ b/Bugzilla/WebService/Bug.pm @@ -1659,6 +1659,14 @@ sub _bug_to_hash { $item{'comment_count'} = $self->type('int', $bug->comment_count); } + if (filter_wants $params, 'counts', ['extra']) { + $item{'counts'} = {}; + + while (my ($key, $value) = each %{$bug->counts}) { + $item{'counts'}->{$key} = $self->type('int', $value); + } + } + return \%item; } @@ -2784,6 +2792,10 @@ members. To see the keys included in the user detail hash, see below. C The name of the current classification the bug is in. +=item C + +C The number of the comments left on this bug. + =item C C of hashes containing comment details of the bug. See the comments @@ -2796,6 +2808,17 @@ in C. C The name of the current component of this bug. +=item C + +B + +C A hash containing the numbers of the items in the following fields: +C, C, C, C, C, C, +C, C and C. + +This is an B field returned only by specifying C or C<_extra> in +C. + =item C C When the bug was created. @@ -3194,9 +3217,9 @@ and all custom fields. =item The C item was added to the C return value in Bugzilla B<4.4>. -=item The C, C, C, C, -C, C, C, C and C fields -were added in Bugzilla B<6.0>. +=item The C, C, C, C, +C, C, C, C, C, +C and C fields were added in Bugzilla B<6.0>. =back diff --git a/bugzilla.dtd b/bugzilla.dtd index 91678849d..88ebab14d 100644 --- a/bugzilla.dtd +++ b/bugzilla.dtd @@ -7,7 +7,7 @@ > + diff --git a/docs/en/rst/api/core/v1/bug.rst b/docs/en/rst/api/core/v1/bug.rst index 1596e3cd0..f09905483 100644 --- a/docs/en/rst/api/core/v1/bug.rst +++ b/docs/en/rst/api/core/v1/bug.rst @@ -256,6 +256,11 @@ attachments array Each array item is an Attachment object. See :ref:`rest_attachments` for details of the object. comments array Each array item is a Comment object. See :ref:`rest_comments` for details of the object. +counts object An object containing the numbers of the items in the + following fields: ``attachments``, ``cc``, + ``comments``, ``keywords``, ``blocks``, + ``depends_on``, ``regressed_by``, ``regressions`` + and ``duplicates``. description string The description (initial comment) of the bug. history array Each array item is a History object. See :ref:`rest_history` for details of the object. diff --git a/extensions/BMO/Extension.pm b/extensions/BMO/Extension.pm index aeeb5d07a..0f6a16134 100644 --- a/extensions/BMO/Extension.pm +++ b/extensions/BMO/Extension.pm @@ -2305,15 +2305,6 @@ sub _detect_content_type { sub buglist_columns { my ($self, $args) = @_; my $columns = $args->{columns}; - $columns->{'cc_count'} = { - name => '(SELECT COUNT(*) FROM cc WHERE cc.bug_id = bugs.bug_id)', - title => 'CC Count', - }; - $columns->{'dupe_count'} = { - name => - '(SELECT COUNT(*) FROM duplicates WHERE duplicates.dupe_of = bugs.bug_id)', - title => 'Duplicate Count', - }; $columns->{'attachments.ispatch'} = { # Return `1` if the bug has any regular patch or external review request, diff --git a/extensions/BMO/template/en/default/hook/global/field-descs-end.none.tmpl b/extensions/BMO/template/en/default/hook/global/field-descs-end.none.tmpl deleted file mode 100644 index 8c543b35d..000000000 --- a/extensions/BMO/template/en/default/hook/global/field-descs-end.none.tmpl +++ /dev/null @@ -1,12 +0,0 @@ -[%# This Source Code Form is subject to the terms of the Mozilla Public - # License, v. 2.0. If a copy of the MPL was not distributed with this - # file, You can obtain one at http://mozilla.org/MPL/2.0/. - # - # This Source Code Form is "Incompatible With Secondary Licenses", as - # defined by the Mozilla Public License, v. 2.0. - #%] - -[% IF in_template_var %] - [% vars.field_descs.cc_count = "CC Count" %] - [% vars.field_descs.dupe_count = "Duplicate Count" %] -[% END %] diff --git a/extensions/BugmailFilter/lib/Constants.pm b/extensions/BugmailFilter/lib/Constants.pm index bed8a37d3..655cd7fd6 100644 --- a/extensions/BugmailFilter/lib/Constants.pm +++ b/extensions/BugmailFilter/lib/Constants.pm @@ -35,18 +35,26 @@ use constant FAKE_FIELD_NAMES => [ use constant IGNORE_FIELDS => qw( assignee_last_login attach_data.thedata + attachments.count attachments.submitter + blocked.count + cc_count cf_last_resolved commenter comment_tag creation_ts days_elapsed delta_ts + dependson.count + dupe_count everconfirmed + keywords.count last_visit_ts longdesc longdescs.count owner_idle_time + regressed_by.count + regresses.count reporter reporter_accessible setters.login_name diff --git a/template/en/default/global/field-descs.none.tmpl b/template/en/default/global/field-descs.none.tmpl index 4a7bf48f6..e1186bb12 100644 --- a/template/en/default/global/field-descs.none.tmpl +++ b/template/en/default/global/field-descs.none.tmpl @@ -99,6 +99,7 @@ if ( $stash->get("in_template_var") ) { "assigned_to_realname" => "Assignee Real Name", "assignee_last_login" => "Assignee Last Login Date", "attach_data.thedata" => "Attachment data", + "attachments.count" => "Number of Attachments", "attachments.description" => "Attachment description", "attachments.filename" => "Attachment filename", "attachments.mimetype" => "Attachment mime type", @@ -107,6 +108,7 @@ if ( $stash->get("in_template_var") ) { "attachments.isprivate" => "Attachment is private", "attachments.submitter" => "Attachment creator", "blocked" => "Blocks", + "blocked.count" => "Number of Blocks", "bug_file_loc" => "URL", "bug_group" => "Group", "bug_id" => "$terms->{Bug} ID", @@ -115,6 +117,7 @@ if ( $stash->get("in_template_var") ) { "bug_type" => "Type", "changeddate" => "Updated", "cc" => "CC", + "cc_count" => "Number of CC", "classification" => "Classification", "cclist_accessible" => "CC list accessible", "commenter" => "Commenter", @@ -126,11 +129,15 @@ if ( $stash->get("in_template_var") ) { "deadline" => "Deadline", "delta_ts" => "Updated", "dependson" => "Depends on", - "dup_id" => "Duplicate", + "dependson.count" => "Number of Depends on", + "dup_id" => "Duplicate of", + "dupe_count" => "Number of Duplicates", + "duplicates" => "Duplicates", "estimated_time" => "Orig. Est.", "everconfirmed" => "Ever confirmed", "flagtypes.name" => "Flags", "keywords" => "Keywords", + "keywords.count" => "Number of Keywords", "last_visit_ts" => "Last Visit", "longdesc" => "Comment", "longdescs.count" => "Number of Comments", @@ -146,7 +153,9 @@ if ( $stash->get("in_template_var") ) { "qa_contact" => "QA Contact", "qa_contact_realname" => "QA Contact Real Name", "regressed_by" => "Regressed by", + "regressed_by.count" => "Number of Regressed by", "regresses" => "Regressions", + "regresses.count" => "Number of Regressions", "remaining_time" => "Hours Left", "rep_platform" => "Hardware", "reporter" => "Reporter", diff --git a/template/en/default/list/table.html.tmpl b/template/en/default/list/table.html.tmpl index 1d4e6f93c..78cef0f94 100644 --- a/template/en/default/list/table.html.tmpl +++ b/template/en/default/list/table.html.tmpl @@ -61,10 +61,19 @@ "short_short_desc" => { maxlength => 60 , ellipsis => "..." , wrap => 1 } , "status_whiteboard" => { maxlength => 0, title => "Whiteboard" , wrap => 1 } , "keywords" => { maxlength => 0, wrap => 1 } , + "keywords.count" => { maxlength => 0, title => "# Keywords" }, "dependson" => { maxlength => 0, wrap => 1 } , + "dependson.count" => { maxlength => 0, title => "# Depends on" }, "blocked" => { maxlength => 0, wrap => 1 } , + "blocked.count" => { maxlength => 0, title => "# Blocks" }, "regressed_by" => { maxlength => 0, wrap => 1 } , + "regressed_by.count" => { maxlength => 0, title => "# Regressed by" }, "regresses" => { maxlength => 0, wrap => 1 } , + "regresses.count" => { maxlength => 0, title => "# Regressions" }, + "dupe_count" => { maxlength => 0, title => "# Duplicates" }, + "duplicates" => { maxlength => 0, wrap => 1 } , + "attachments.count" => { maxlength => 0, title => "# Attachments" }, + "cc_count" => { maxlength => 0, title => "# CC" }, "flagtypes.name" => { maxlength => 0, wrap => 1 } , "component" => { maxlength => 8 , title => "Comp" } , "product" => { maxlength => 8 } , diff --git a/template/en/default/pages/bugzilla.dtd.tmpl b/template/en/default/pages/bugzilla.dtd.tmpl index e9619f788..59bc954fc 100644 --- a/template/en/default/pages/bugzilla.dtd.tmpl +++ b/template/en/default/pages/bugzilla.dtd.tmpl @@ -52,6 +52,7 @@ bug_status, resolution?, dup_id?, + duplicates*, see_also*, bug_file_loc?, status_whiteboard?, @@ -121,6 +122,7 @@ +