diff --git a/share/html/Elements/CollectionAsTable/Header b/share/html/Elements/CollectionAsTable/Header index 9b4ac06fffc..ad0225975d2 100644 --- a/share/html/Elements/CollectionAsTable/Header +++ b/share/html/Elements/CollectionAsTable/Header @@ -218,12 +218,22 @@ foreach my $col ( @Format ) { $m->out( qq{$loc_title} ); } - if ( $AllowFiltering && $Class eq 'RT::Tickets' ) { + if ( $AllowFiltering ) { my $attr = ProcessColumnMapValue( $attribute, Arguments => [ $col->{'attribute'} ], Escape => 1 ); - my $field; - my %supported = map { $_ => 1 } - qw/id Subject Status Queue Owner Type Creator LastUpdatedBy SLA InitialPriority FinalPriority Priority TimeLeft TimeWorked TimeEstimated Created LastUpdated Told Starts Started Due Resolved Requestors Requestor Cc AdminCc/; + my %supported; + my $filter_comp; + if ( $Class eq 'RT::Tickets' ) { + %supported = map { $_ => 1 } + qw/id Subject Status Queue Owner Type Creator LastUpdatedBy SLA InitialPriority FinalPriority Priority TimeLeft TimeWorked TimeEstimated Created LastUpdated Told Starts Started Due Resolved Requestors Requestor Cc AdminCc/; + $filter_comp = '/Search/Elements/FilterTickets'; + } + elsif ( $Class eq 'RT::Assets' ) { + %supported = map { $_ => 1 } + qw/id Name Description Status Catalog Created LastUpdated Creator LastUpdatedBy Owner HeldBy Contact Contacts/; + $filter_comp = '/Search/Elements/FilterAssets'; + } + my $field; if ( ( $attr || '' ) =~ /^(\w+)/ && $supported{$1} ) { $field = $1; } @@ -242,7 +252,7 @@ foreach my $col ( @Format ) { $m->out( qq{ $icon} ); - $m->out( $m->scomp( '/Elements/SearchFilter', Attribute => $field, FilterData => \%filter_data, %ARGS ) ); + $m->out( $m->scomp( $filter_comp, Attribute => $field, FilterData => \%filter_data, %ARGS ) ); } } $m->out(''); @@ -253,109 +263,218 @@ foreach my $col ( @Format ) { <%INIT> my %filter_data; -if ( $AllowFiltering && $Class eq 'RT::Tickets' && $ARGS{Query} && $ARGS{BaseQuery} ) { - - my $tickets = RT::Tickets->new( $session{CurrentUser} ); - my ($ok) = $tickets->FromSQL( $ARGS{Query} ); - return unless $ok && ( $ARGS{BaseQuery} || $tickets->Count ); - - my @queues; - - my $tree = RT::Interface::Web::QueryBuilder::Tree->new; - $tree->ParseSQL( Query => $ARGS{BaseQuery} || $ARGS{Query}, CurrentUser => $session{'CurrentUser'} ); - my $referenced_queues = $tree->GetReferencedQueues; - for my $name_or_id ( keys %$referenced_queues ) { - my $queue = RT::Queue->new( $session{CurrentUser} ); - $queue->Load($name_or_id); - if ( $queue->id ) { - push @queues, $queue; +if ( $AllowFiltering && $ARGS{Query} && $ARGS{BaseQuery} ) { + + if ( $Class eq 'RT::Tickets' ) { + my $tickets = RT::Tickets->new( $session{CurrentUser} ); + my ($ok) = $tickets->FromSQL( $ARGS{Query} ); + return unless $ok && ( $ARGS{BaseQuery} || $tickets->Count ); + + my @queues; + + my $tree = RT::Interface::Web::QueryBuilder::Tree->new; + $tree->ParseSQL( Query => $ARGS{BaseQuery} || $ARGS{Query}, CurrentUser => $session{'CurrentUser'} ); + my $referenced_queues = $tree->GetReferencedQueues; + for my $name_or_id ( keys %$referenced_queues ) { + my $queue = RT::Queue->new( $session{CurrentUser} ); + $queue->Load($name_or_id); + if ( $queue->id ) { + push @queues, $queue; + } } - } - my %status; - my @lifecycles; + my %status; + my @lifecycles; - if (@queues) { - my %lifecycle; - for my $queue (@queues) { - next if $lifecycle{ $queue->Lifecycle }++; - push @lifecycles, $queue->LifecycleObj; + if (@queues) { + my %lifecycle; + for my $queue (@queues) { + next if $lifecycle{ $queue->Lifecycle }++; + push @lifecycles, $queue->LifecycleObj; + } + } + else { + @lifecycles = map { RT::Lifecycle->Load( Type => 'ticket', Name => $_ ) } RT::Lifecycle->List('ticket'); } - } - else { - @lifecycles = map { RT::Lifecycle->Load( Type => 'ticket', Name => $_ ) } RT::Lifecycle->List('ticket'); - } - for my $lifecycle (@lifecycles) { - $status{$_} = 1 for $lifecycle->Valid; - } - delete $status{deleted}; + for my $lifecycle (@lifecycles) { + $status{$_} = 1 for $lifecycle->Valid; + } + delete $status{deleted}; - if ( !@queues ) { - my $queues = RT::Queues->new( $session{CurrentUser} ); - $queues->UnLimit; + if ( !@queues ) { + my $queues = RT::Queues->new( $session{CurrentUser} ); + $queues->UnLimit; - while ( my $queue = $queues->Next ) { - push @queues, $queue; - last if @queues == 100; # TODO make a config for it + while ( my $queue = $queues->Next ) { + push @queues, $queue; + last if @queues == 100; # TODO make a config for it + } + } + + my %filter; + + if ( $ARGS{BaseQuery} && $ARGS{BaseQuery} ne $ARGS{Query} ) { + my $query = $ARGS{Query}; + $query =~ s!^\s*\(?\s*\Q$ARGS{BaseQuery}\E\s*\)? AND !!; + my $tree = RT::Interface::Web::QueryBuilder::Tree->new; + $tree->ParseSQL( Query => $query, CurrentUser => $session{'CurrentUser'} ); + $tree->traverse( + sub { + my $node = shift; + + return if $node->isRoot; + return unless $node->isLeaf; + + my $clause = $node->getNodeValue(); + if ( $clause->{Key} =~ /^Queue/ ) { + my $queue = RT::Queue->new( $session{CurrentUser} ); + $queue->Load( $clause->{Value} ); + if ( $queue->id ) { + $filter{ $clause->{Key} }{ $queue->id } = 1; + } + } + elsif ( $clause->{Key} =~ /^(?:Status|SLA|Type)/ ) { + $filter{ $clause->{Key} }{ $clause->{Value} } = 1; + } + elsif ( $clause->{Key} + =~ /^(?:(?:Initial|Final)?Priority|Time(?:Worked|Estimated|Left)|id|Told|Starts|Started|Due|Resolved|Created|LastUpdated\b)/ + ) + { + $filter{ $clause->{Key} }{ $clause->{Op} } = $clause->{Value}; + } + else { + my $value = $clause->{Value}; + $value =~ s!\\([\\"])!$1!g; + my $key = $clause->{Key}; + my $cf; + if ( $key eq 'CustomField' ) { + $key .= ".$clause->{Subkey}"; + my ($cf_name) = $clause->{Subkey} =~ /{(.+)}/; + $cf = RT::CustomField->new( RT->SystemUser ); + $cf->Load($cf_name); + } + elsif ( $key eq 'CustomRole' ) { + $key .= ".$1" if $clause->{Subkey} =~ /(\{.+?\})/; + } + if ( $cf && $cf->id && $cf->Type eq 'Select' ) { + $filter{$key}{$value} = 1; + } + else { + $filter{$key} = $value; + } + } + } + ); + $filter{Requestors} = $filter{Requestor} if $filter{Requestor}; } + %filter_data = ( status => \%status, queues => \@queues, filter => \%filter ); } + elsif ( $Class eq 'RT::Assets' ) { + my $assets = RT::Assets->new( $session{CurrentUser} ); + my ($ok) = $assets->FromSQL( $ARGS{Query} ); + return unless $ok && ( $ARGS{BaseQuery} || $assets->Count ); - my %filter; + my @catalogs; - if ( $ARGS{BaseQuery} && $ARGS{BaseQuery} ne $ARGS{Query} ) { - my $query = $ARGS{Query}; - $query =~ s!^\s*\(?\s*\Q$ARGS{BaseQuery}\E\s*\)? AND !!; my $tree = RT::Interface::Web::QueryBuilder::Tree->new; - $tree->ParseSQL( Query => $query, CurrentUser => $session{'CurrentUser'} ); - $tree->traverse( - sub { - my $node = shift; - - return if $node->isRoot; - return unless $node->isLeaf; - - my $clause = $node->getNodeValue(); - if ( $clause->{Key} =~ /^Queue/ ) { - my $queue = RT::Queue->new( $session{CurrentUser} ); - $queue->Load( $clause->{Value} ); - if ( $queue->id ) { - $filter{ $clause->{Key} }{ $queue->id } = 1; - } - } - elsif ( $clause->{Key} =~ /^(?:Status|SLA|Type)/ ) { - $filter{ $clause->{Key} }{ $clause->{Value} } = 1; - } - elsif ( $clause->{Key} - =~ /^(?:(?:Initial|Final)?Priority|Time(?:Worked|Estimated|Left)|id|Told|Starts|Started|Due|Resolved|Created|LastUpdated\b)/ - ) - { - $filter{ $clause->{Key} }{ $clause->{Op} } = $clause->{Value}; - } - else { - my $value = $clause->{Value}; - $value =~ s!\\([\\"])!$1!g; - my $key = $clause->{Key}; - my $cf; - if ( $key eq 'CustomField' ) { - $key .= ".$clause->{Subkey}"; - my ($cf_name) = $clause->{Subkey} =~ /{(.+)}/; - $cf = RT::CustomField->new( RT->SystemUser ); - $cf->Load($cf_name); + $tree->ParseSQL( + Query => $ARGS{BaseQuery} || $ARGS{Query}, + CurrentUser => $session{'CurrentUser'}, + Class => 'RT::Assets', + ); + my $referenced_catalogs = $tree->GetReferencedCatalogs; + for my $name_or_id ( keys %$referenced_catalogs ) { + my $catalog = RT::Catalog->new( $session{CurrentUser} ); + $catalog->Load($name_or_id); + if ( $catalog->id ) { + push @catalogs, $catalog; + } + } + + my %status; + my @lifecycles; + + if (@catalogs) { + my %lifecycle; + for my $catalog (@catalogs) { + next if $lifecycle{ $catalog->Lifecycle }++; + push @lifecycles, $catalog->LifecycleObj; + } + } + else { + @lifecycles = map { RT::Lifecycle->Load( Type => 'asset', Name => $_ ) } RT::Lifecycle->List('asset'); + } + + for my $lifecycle (@lifecycles) { + $status{$_} = 1 for $lifecycle->Valid; + } + delete $status{deleted}; + + if ( !@catalogs ) { + my $catalogs = RT::Catalogs->new( $session{CurrentUser} ); + $catalogs->UnLimit; + + while ( my $catalog = $catalogs->Next ) { + push @catalogs, $catalog; + last if @catalogs == 100; # TODO make a config for it + } + } + + my %filter; + + if ( $ARGS{BaseQuery} && $ARGS{BaseQuery} ne $ARGS{Query} ) { + my $query = $ARGS{Query}; + $query =~ s!^\s*\(?\s*\Q$ARGS{BaseQuery}\E\s*\)? AND !!; + my $tree = RT::Interface::Web::QueryBuilder::Tree->new; + $tree->ParseSQL( Query => $query, CurrentUser => $session{'CurrentUser'}, Class => 'RT::Assets' ); + $tree->traverse( + sub { + my $node = shift; + + return if $node->isRoot; + return unless $node->isLeaf; + + my $clause = $node->getNodeValue(); + if ( $clause->{Key} =~ /^Catalog/ ) { + my $catalog = RT::Catalog->new( $session{CurrentUser} ); + $catalog->Load( $clause->{Value} ); + if ( $catalog->id ) { + $filter{ $clause->{Key} }{ $catalog->id } = 1; + } } - elsif ( $key eq 'CustomRole' ) { - $key .= ".$1" if $clause->{Subkey} =~ /(\{.+?\})/; + elsif ( $clause->{Key} eq 'Status' ) { + $filter{ $clause->{Key} }{ $clause->{Value} } = 1; } - if ( $cf && $cf->id && $cf->Type eq 'Select' ) { - $filter{$key}{$value} = 1; + elsif ( $clause->{Key} =~ /^(?:id|Created|LastUpdated\b)/ ) { + $filter{ $clause->{Key} }{ $clause->{Op} } = $clause->{Value}; } else { - $filter{$key} = $value; + my $value = $clause->{Value}; + $value =~ s!\\([\\"])!$1!g; + my $key = $clause->{Key}; + my $cf; + if ( $key eq 'CustomField' ) { + $key .= ".$clause->{Subkey}"; + my ($cf_name) = $clause->{Subkey} =~ /{(.+)}/; + $cf = RT::CustomField->new( RT->SystemUser ); + $cf->Load($cf_name); + } + elsif ( $key eq 'CustomRole' ) { + $key .= ".$1" if $clause->{Subkey} =~ /(\{.+?\})/; + } + if ( $cf && $cf->id && $cf->Type eq 'Select' ) { + $filter{$key}{$value} = 1; + } + else { + $filter{$key} = $value; + } } } - } - ); + ); + $filter{Contacts} = $filter{Contact} if $filter{Contact}; + } + %filter_data = ( status => \%status, catalogs => \@catalogs, filter => \%filter ); } - %filter_data = ( status => \%status, queues => \@queues, filter => \%filter ); } diff --git a/share/html/Elements/SearchFilter b/share/html/Elements/SearchFilter index 24172b75d28..ebfe08e4d5a 100644 --- a/share/html/Elements/SearchFilter +++ b/share/html/Elements/SearchFilter @@ -45,305 +45,11 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} - <%INIT> -return unless $ARGS{Query}; - -my $status = $FilterData{status}; -my $queues = $FilterData{queues}; -my $filter = $FilterData{filter}; - -my $modal_class; -if ( $Attribute =~ /^(?:Time|(?:Initial|Final)Priority|LastUpdated)/ ) { - $modal_class = 'modal-md'; -} -else { - $modal_class = 'modal-sm'; -} +RT->Deprecated( + Instead => '/Search/Elements/FilterTickets', + Remove => '5.2', +); - -<%ARGS> -$Attribute => '' -%FilterData => () - diff --git a/share/html/Search/Elements/FilterAssets b/share/html/Search/Elements/FilterAssets new file mode 100644 index 00000000000..bbaff8689c7 --- /dev/null +++ b/share/html/Search/Elements/FilterAssets @@ -0,0 +1,245 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC +%# +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} + +<%INIT> +return unless $ARGS{Query}; + +my $status = $FilterData{status}; +my $catalogs = $FilterData{catalogs}; +my $filter = $FilterData{filter}; + +my $modal_class; +if ( $Attribute =~ /^(?:Created|LastUpdated|Description)/ ) { + $modal_class = 'modal-md'; +} +else { + $modal_class = 'modal-sm'; +} + + +<%ARGS> +$Attribute => '' +%FilterData => () + diff --git a/share/html/Search/Elements/FilterTickets b/share/html/Search/Elements/FilterTickets new file mode 100644 index 00000000000..3276aa2d941 --- /dev/null +++ b/share/html/Search/Elements/FilterTickets @@ -0,0 +1,349 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC +%# +%# +%# (Except where explicitly superseded by other copyright notices) +%# +%# +%# LICENSE: +%# +%# This work is made available to you under the terms of Version 2 of +%# the GNU General Public License. A copy of that license should have +%# been provided with this software, but in any event can be snarfed +%# from www.gnu.org. +%# +%# This work is distributed in the hope that it will be useful, but +%# WITHOUT ANY WARRANTY; without even the implied warranty of +%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +%# General Public License for more details. +%# +%# You should have received a copy of the GNU General Public License +%# along with this program; if not, write to the Free Software +%# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +%# 02110-1301 or visit their web page on the internet at +%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html. +%# +%# +%# CONTRIBUTION SUBMISSION POLICY: +%# +%# (The following paragraph is not intended to limit the rights granted +%# to you to modify and distribute this software under the terms of +%# the GNU General Public License and is only of importance to you if +%# you choose to contribute your changes and enhancements to the +%# community by submitting them to Best Practical Solutions, LLC.) +%# +%# By intentionally submitting any modifications, corrections or +%# derivatives to this work, or any other work intended for use with +%# Request Tracker, to Best Practical Solutions, LLC, you confirm that +%# you are the copyright holder for those contributions and you grant +%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable, +%# royalty-free, perpetual, license to use, copy, create derivative +%# works based on those contributions, and sublicense and distribute +%# those contributions and any derivatives thereof. +%# +%# END BPS TAGGED BLOCK }}} + +<%INIT> +return unless $ARGS{Query}; + +my $status = $FilterData{status}; +my $queues = $FilterData{queues}; +my $filter = $FilterData{filter}; + +my $modal_class; +if ( $Attribute =~ /^(?:Time|(?:Initial|Final)Priority|Created|LastUpdated)/ ) { + $modal_class = 'modal-md'; +} +else { + $modal_class = 'modal-sm'; +} + + +<%ARGS> +$Attribute => '' +%FilterData => () + diff --git a/share/static/js/util.js b/share/static/js/util.js index d349bd6dcc9..79e21316c7f 100644 --- a/share/static/js/util.js +++ b/share/static/js/util.js @@ -1023,66 +1023,121 @@ jQuery(function() { }); }); -function filterSearchResults () { +function filterSearchResults (type) { var clauses = []; - var queue_clauses = []; - jQuery('.search-results-filter input[name=Queue]:checked').each(function() { - queue_clauses.push( 'Queue = ' + '"' + jQuery(this).val() + '"' ); - }); + if ( type === 'RT::Tickets' ) { - if ( queue_clauses.length ) { - clauses.push( '( ' + queue_clauses.join( ' OR ' ) + ' )' ); - } + var queue_clauses = []; + jQuery('.search-results-filter input[name=Queue]:checked').each(function() { + queue_clauses.push( 'Queue = ' + '"' + jQuery(this).val() + '"' ); + }); - var status_clauses = []; - jQuery('.search-results-filter input[name=Status]:checked').each(function() { - status_clauses.push('Status = ' + '"' + jQuery(this).val() + '"' ); - }); + if ( queue_clauses.length ) { + clauses.push( '( ' + queue_clauses.join( ' OR ' ) + ' )' ); + } - if ( status_clauses.length ) { - clauses.push( '( ' + status_clauses.join( ' OR ' ) + ' )' ); - } + var sla_clauses = []; + jQuery('.search-results-filter input[name=SLA]:checked').each(function() { + var value = jQuery(this).val(); + if ( value == 'NULL' ) { + sla_clauses.push( 'SLA IS NULL' ); + } + else { + sla_clauses.push( 'SLA = ' + '"' + value + '"' ); + } + }); - var sla_clauses = []; - jQuery('.search-results-filter input[name=SLA]:checked').each(function() { - var value = jQuery(this).val(); - if ( value == 'NULL' ) { - sla_clauses.push( 'SLA IS NULL' ); + var type_clauses = []; + jQuery('.search-results-filter input[name=Type]:checked').each(function() { + type_clauses.push('Type = ' + '"' + jQuery(this).val() + '"' ); + }); + + if ( type_clauses.length ) { + clauses.push( '( ' + type_clauses.join( ' OR ' ) + ' )' ); } - else { - sla_clauses.push( 'SLA = ' + '"' + value + '"' ); + + var subject = jQuery('.search-results-filter input[name=Subject]').val(); + if ( subject && subject.match(/\S/) ) { + clauses.push( '( Subject LIKE "' + subject.replace(/(["\\])/g, "\\$1") + '" )' ); } - }); - var type_clauses = []; - jQuery('.search-results-filter input[name=Type]:checked').each(function() { - type_clauses.push('Type = ' + '"' + jQuery(this).val() + '"' ); - }); + jQuery('.search-results-filter :input[name=Owner]').each(function() { + var value = jQuery(this).val(); + if ( value && value.match(/\S/) ) { + clauses.push( 'Owner.Name = ' + '"' + value + '"' ); + } + }); - if ( type_clauses.length ) { - clauses.push( '( ' + type_clauses.join( ' OR ' ) + ' )' ); - } + [ 'Requestors', 'Requestor', 'Cc', 'AdminCc' ].forEach( function(role) { + var value = jQuery('.search-results-filter input[name=' + role + ']').val(); + if ( value && value.match(/\S/) ) { + clauses.push( role + '.EmailAddress = ' + "'" + value + "'" ); + } + }); + + + [ 'Told', 'Starts', 'Started', 'Due', 'Resolved', 'Priority', 'InitialPriority', 'FinalPriority', 'TimeWorked', 'TimeEstimated', 'TimeLeft' ].forEach(function(type) { + var subs = []; + [ 'EqualTo', 'GreaterThan', 'LessThan' ].forEach( function(op) { + var value = jQuery('.search-results-filter :input[name=' + type + op + ']').val(); + if ( value && value.match(/\S/) ) { + if ( value.match(/\D/) ) { + value = "'" + value + "'"; + } - var subject = jQuery('.search-results-filter input[name=Subject]').val(); - if ( subject && subject.match(/\S/) ) { - clauses.push( '( Subject LIKE "' + subject.replace(/(["\\])/g, "\\$1") + '" )' ); + if ( op == 'EqualTo' ) { + subs.push( type + ' = ' + value ); + } + else if ( op == 'GreaterThan' ) { + subs.push( type + ' > ' + value ); + } + else { + subs.push( type + ' < ' + value ); + } + } + }); + if ( subs.length ) { + clauses.push( '( ' + subs.join( ' AND ' ) + ' )' ); + } + }); } + else if ( type === 'RT::Assets' ) { - [ 'Requestors', 'Requestor', 'Cc', 'AdminCc', ].forEach( function(role) { - var value = jQuery('.search-results-filter input[name=' + role + ']').val(); - if ( value && value.match(/\S/) ) { - clauses.push( role + '.EmailAddress = ' + "'" + value + "'" ); - } - }); + var catalog_clauses = []; + jQuery('.search-results-filter input[name=Catalog]:checked').each(function() { + catalog_clauses.push( 'Catalog = ' + '"' + jQuery(this).val() + '"' ); + }); - jQuery('.search-results-filter :input[name=Owner]').each(function() { - var value = jQuery(this).val(); - if ( value && value.match(/\S/) ) { - clauses.push( 'Owner.Name = ' + '"' + value + '"' ); + if ( catalog_clauses.length ) { + clauses.push( '( ' + catalog_clauses.join( ' OR ' ) + ' )' ); } + + [ 'Owner', 'HeldBy', 'Contact' ].forEach( function(role) { + var value = jQuery('.search-results-filter input[name=' + role + ']').val(); + if ( value && value.match(/\S/) ) { + clauses.push( role + '.EmailAddress = ' + "'" + value + "'" ); + } + }); + + [ 'Name', 'Description' ].forEach( function(item) { + var value = jQuery('.search-results-filter input[name=' + item + ']').val(); + if ( value && value.match(/\S/) ) { + clauses.push( '( ' + item + ' LIKE "' + value.replace(/(["\\])/g, "\\$1") + '" )' ); + } + }); + } + + + var status_clauses = []; + jQuery('.search-results-filter input[name=Status]:checked').each(function() { + status_clauses.push('Status = ' + '"' + jQuery(this).val() + '"' ); }); + if ( status_clauses.length ) { + clauses.push( '( ' + status_clauses.join( ' OR ' ) + ' )' ); + } + jQuery('.search-results-filter input[name^=CustomRole]').each(function() { var role = jQuery(this).attr('name'); var value = jQuery(this).val(); @@ -1099,7 +1154,7 @@ function filterSearchResults () { } }); - [ 'id', 'Told', 'Starts', 'Started', 'Due', 'Resolved', 'Created', 'LastUpdated', 'Priority', 'InitialPriority', 'FinalPriority', 'TimeWorked', 'TimeEstimated', 'TimeLeft' ].forEach(function(type) { + [ 'id', 'Created', 'LastUpdated' ].forEach(function(type) { var subs = []; [ 'EqualTo', 'GreaterThan', 'LessThan' ].forEach( function(op) { var value = jQuery('.search-results-filter :input[name=' + type + op + ']').val();