From bef573942a961cf6a74abd0f47448e24cf278061 Mon Sep 17 00:00:00 2001 From: Kohei Yoshino Date: Tue, 16 Jul 2019 16:06:41 -0400 Subject: [PATCH] Bug 1533717 - Add a search keyword "Whatever" --- Bugzilla/Field.pm | 3 + Bugzilla/Search.pm | 92 +++++++++++-------- js/advanced-search.js | 19 ++++ .../en/default/global/field-descs.none.tmpl | 1 + 4 files changed, 77 insertions(+), 38 deletions(-) diff --git a/Bugzilla/Field.pm b/Bugzilla/Field.pm index a12cf2e86..5aedef21b 100644 --- a/Bugzilla/Field.pm +++ b/Bugzilla/Field.pm @@ -487,6 +487,9 @@ use constant DEFAULT_FIELDS => ( type => FIELD_TYPE_USER, buglist => 1, }, + + # Special field that allows to search everything with Custom Search queries + {name => 'anything', desc => 'Any field'}, ); ################ diff --git a/Bugzilla/Search.pm b/Bugzilla/Search.pm index e85683819..eb58602c2 100644 --- a/Bugzilla/Search.pm +++ b/Bugzilla/Search.pm @@ -3476,30 +3476,34 @@ sub _changedbefore_changedafter { = @$args{qw(chart_id joins field operator value)}; my $dbh = Bugzilla->dbh; - my $field_object = $self->_chart_fields->{$field} - || ThrowCodeError("invalid_field_name", {field => $field}); + my $table; + my $join = {table => 'bugs_activity', extra => []}; - # Asking when creation_ts changed is just asking when the bug was created. - if ($field_object->name eq 'creation_ts') { - $args->{operator} - = $operator eq 'changedbefore' ? 'lessthaneq' : 'greaterthaneq'; - return $self->_do_operator_function($args); - } + if ($field eq 'anything') { + # Handle special field name to find changes in any field + $table = $join->{as} = "act_x_$chart_id"; + } else { + my $field_object = $self->_chart_fields->{$field} + || ThrowCodeError("invalid_field_name", {field => $field}); + + # Asking when creation_ts changed is just asking when the bug was created. + if ($field_object->name eq 'creation_ts') { + $args->{operator} + = $operator eq 'changedbefore' ? 'lessthaneq' : 'greaterthaneq'; + return $self->_do_operator_function($args); + } - my $sql_operator = ($operator =~ /before/) ? '<=' : '>='; - my $field_id = $field_object->id; + my $field_id = $field_object->id; - # Charts on changed* fields need to be field-specific. Otherwise, - # OR chart rows make no sense if they contain multiple fields. - my $table = "act_${field_id}_$chart_id"; + # Charts on changed* fields need to be field-specific. Otherwise, + # OR chart rows make no sense if they contain multiple fields. + $table = $join->{as} = "act_${field_id}_$chart_id"; + push(@{$join->{extra}}, "$table.fieldid = $field_id"); + } + my $sql_operator = ($operator =~ /before/) ? '<=' : '>='; my $sql_date = $dbh->quote(SqlifyDate($value)); - my $join = { - table => 'bugs_activity', - as => $table, - extra => - ["$table.fieldid = $field_id", "$table.bug_when $sql_operator $sql_date"], - }; + push(@{$join->{extra}}, "$table.bug_when $sql_operator $sql_date"); $args->{term} = "$table.bug_when IS NOT NULL"; $self->_changed_security_check($args, $join); @@ -3511,16 +3515,22 @@ sub _changedfrom_changedto { my ($chart_id, $joins, $field, $operator, $quoted) = @$args{qw(chart_id joins field operator quoted)}; + my $table; + my $join = {table => 'bugs_activity', extra => []}; my $column = ($operator =~ /from/) ? 'removed' : 'added'; - my $field_object = $self->_chart_fields->{$field} - || ThrowCodeError("invalid_field_name", {field => $field}); - my $field_id = $field_object->id; - my $table = "act_${field_id}_$chart_id"; - my $join = { - table => 'bugs_activity', - as => $table, - extra => ["$table.fieldid = $field_id", "$table.$column = $quoted"], - }; + + if ($field eq 'anything') { + # Handle special field name to find changes in any field + $table = $join->{as} = "act_x_$chart_id"; + } else { + my $field_object = $self->_chart_fields->{$field} + || ThrowCodeError("invalid_field_name", {field => $field}); + my $field_id = $field_object->id; + $table = $join->{as} = "act_${field_id}_$chart_id"; + push(@{$join->{extra}}, "$table.fieldid = $field_id"); + } + + push(@{$join->{extra}}, "$table.$column = $quoted"); $args->{term} = "$table.bug_when IS NOT NULL"; $self->_changed_security_check($args, $join); @@ -3532,16 +3542,22 @@ sub _changedby { my ($chart_id, $joins, $field, $operator, $value) = @$args{qw(chart_id joins field operator value)}; - my $field_object = $self->_chart_fields->{$field} - || ThrowCodeError("invalid_field_name", {field => $field}); - my $field_id = $field_object->id; - my $table = "act_${field_id}_$chart_id"; - my $user_id = login_to_id($value, THROW_ERROR); - my $join = { - table => 'bugs_activity', - as => $table, - extra => ["$table.fieldid = $field_id", "$table.who = $user_id"], - }; + my $table; + my $join = {table => 'bugs_activity', extra => []}; + + if ($field eq 'anything') { + # Handle special field name to find changes in any field + $table = $join->{as} = "act_x_$chart_id"; + } else { + my $field_object = $self->_chart_fields->{$field} + || ThrowCodeError("invalid_field_name", {field => $field}); + my $field_id = $field_object->id; + $table = $join->{as} = "act_${field_id}_$chart_id"; + push(@{$join->{extra}}, "$table.fieldid = $field_id"); + } + + my $user_id = login_to_id($value, THROW_ERROR); + push(@{$join->{extra}}, "$table.who = $user_id"); $args->{term} = "$table.bug_when IS NOT NULL"; $self->_changed_security_check($args, $join); diff --git a/js/advanced-search.js b/js/advanced-search.js index 8f3214815..d1d8462fb 100644 --- a/js/advanced-search.js +++ b/js/advanced-search.js @@ -593,12 +593,31 @@ Bugzilla.CustomSearch.Row = class CustomSearchRow extends Bugzilla.CustomSearch. this.$element = $placeholder.firstElementChild; this.$action_grab = this.$element.querySelector('[data-action="grab"]'); this.$action_remove = this.$element.querySelector('[data-action="remove"]'); + this.$select_field = this.$element.querySelector('select.field'); + this.$select_operator = this.$element.querySelector('select.operator'); + this.$input_value = this.$element.querySelector('input.value'); this.$element.addEventListener('dragstart', event => this.handle_drag(event)); this.$element.addEventListener('dragend', event => this.handle_drag(event)); this.$action_grab.addEventListener('mousedown', () => this.enable_drag()); this.$action_grab.addEventListener('mouseup', () => this.disable_drag()); this.$action_remove.addEventListener('click', () => this.remove()); + this.$select_field.addEventListener('change', () => this.field_onchange()); + } + + /** + * Called whenever a field option is selected. + */ + field_onchange() { + const is_anything = this.$select_field.value === 'anything'; + + // Add support for the "anything" special field that allows to search the bug history. When it's selected, disable + // search types other than "changed before", "changed after", "changed from", "changed to", "changed by", and make + // "changed by" selected for convenience. + for (const $option of this.$select_operator.options) { + $option.disabled = is_anything ? !$option.value.match(/changed\w+/) : false; + $option.selected = $option.value === (is_anything ? 'changedby' : 'noop'); + } } }; diff --git a/template/en/default/global/field-descs.none.tmpl b/template/en/default/global/field-descs.none.tmpl index 4ee255e4c..4a7bf48f6 100644 --- a/template/en/default/global/field-descs.none.tmpl +++ b/template/en/default/global/field-descs.none.tmpl @@ -94,6 +94,7 @@ if ( $stash->get("in_template_var") ) { "[Bug creation]" => "[$terms->{Bug} creation]", "actual_time" => "Actual Hours", "alias" => "Alias", + "anything" => "Any field", "assigned_to" => "Assignee", "assigned_to_realname" => "Assignee Real Name", "assignee_last_login" => "Assignee Last Login Date", -- 2.47.3