diff options
author | Ivan Kohler <ivan@freeside.biz> | 2015-07-09 22:18:55 -0700 |
---|---|---|
committer | Ivan Kohler <ivan@freeside.biz> | 2015-07-09 22:18:55 -0700 |
commit | 1c538bfabc2cd31f27067505f0c3d1a46cba6ef0 (patch) | |
tree | 96922ad4459eda1e649327fd391d60c58d454c53 /rt/share/html/Search/Elements | |
parent | 4f5619288413a185e9933088d9dd8c5afbc55dfa (diff) |
RT 4.2.11, ticket#13852
Diffstat (limited to 'rt/share/html/Search/Elements')
22 files changed, 457 insertions, 222 deletions
diff --git a/rt/share/html/Search/Elements/BuildFormatString b/rt/share/html/Search/Elements/BuildFormatString index 9a3ba1e75..10ac1afbe 100644 --- a/rt/share/html/Search/Elements/BuildFormatString +++ b/rt/share/html/Search/Elements/BuildFormatString @@ -115,10 +115,12 @@ $m->callback( CallbackOnce => 1, CallbackName => 'SetFieldsOnce', Fields => \@fi my $CustomFields = RT::CustomFields->new( $session{'CurrentUser'}); foreach my $id (keys %queues) { - # Gotta load up the $queue object, since queues get stored by name now. my $id + # Gotta load up the $queue object, since queues get stored by name now. my $queue = RT::Queue->new($session{'CurrentUser'}); $queue->Load($id); - $CustomFields->LimitToQueue($queue->Id) if $queue->Id; + next unless $queue->Id; + $CustomFields->LimitToQueue($queue->Id); + $CustomFields->SetContextObject( $queue ) if keys %queues == 1; } $CustomFields->LimitToGlobal; @@ -140,8 +142,7 @@ foreach my $field (@format) { if ( $RemoveCol ) { # we do this regex match to avoid a non-numeric warning - my ($index) = $CurrentDisplayColumns =~ /^(\d+)/; - my $column = $seen[$index]; + my ($index) = ($CurrentDisplayColumns // '') =~ /^(\d+)/; if ( defined($index) ) { delete $seen[$index]; my @temp = @seen; @@ -206,7 +207,7 @@ elsif ( $AddCol ) { } } elsif ( $ColUp ) { - my $index = $CurrentDisplayColumns; + my ($index) = ($CurrentDisplayColumns // '') =~ /^(\d+)/; if ( defined $index && ( $index - 1 ) >= 0 ) { my $column = $seen[$index]; $seen[$index] = $seen[ $index - 1 ]; @@ -215,7 +216,7 @@ elsif ( $ColUp ) { } } elsif ( $ColDown ) { - my $index = $CurrentDisplayColumns; + my ($index) = ($CurrentDisplayColumns // '') =~ /^(\d+)/; if ( defined $index && ( $index + 1 ) < scalar @seen ) { my $column = $seen[$index]; $seen[$index] = $seen[ $index + 1 ]; diff --git a/rt/share/html/Search/Elements/Chart b/rt/share/html/Search/Elements/Chart index 38c15f6ef..6285fac2b 100644 --- a/rt/share/html/Search/Elements/Chart +++ b/rt/share/html/Search/Elements/Chart @@ -47,107 +47,44 @@ %# END BPS TAGGED BLOCK }}} <%args> $Query => "id > 0" -$PrimaryGroupBy => 'Queue' -$ChartStyle => 'bar' +@GroupBy => () +$ChartStyle => 'bar+table+sql' +@ChartFunction => 'COUNT' </%args> <%init> use RT::Report::Tickets; -$PrimaryGroupBy ||= 'Queue'; # make sure PrimaryGroupBy is not undef -my $tix = RT::Report::Tickets->new( $session{'CurrentUser'} ); -my %AllowedGroupings = reverse $tix->Groupings( Query => $Query ); -$PrimaryGroupBy = 'Queue' unless exists $AllowedGroupings{$PrimaryGroupBy}; -my ($count_name, $value_name) = $tix->SetupGroupings( - Query => $Query, GroupBy => $PrimaryGroupBy, -); +my $report = RT::Report::Tickets->new( $session{'CurrentUser'} ); -my %class = ( - Queue => 'RT::Queue', - Owner => 'RT::User', - Creator => 'RT::User', - LastUpdatedBy => 'RT::User', +my %columns = $report->SetupGroupings( + Query => $Query, + GroupBy => \@GroupBy, + Function => \@ChartFunction, ); -my $class = $class{ $PrimaryGroupBy }; - -my (@keys, @values); -while ( my $entry = $tix->Next ) { - if ($class) { - my $q = $class->new( $session{'CurrentUser'} ); - $q->Load( $entry->LabelValue( $value_name ) ); - push @keys, $q->Name; - } - else { - push @keys, $entry->LabelValue( $value_name ); - } - $keys[-1] ||= loc('(no value)'); - push @values, $entry->__Value( $count_name ); -} -my %data; -my %loc_keys; -foreach my $key (@keys) { $data{$key} = shift @values; $loc_keys{$key} = loc($key); } -my @sorted_keys = map { $loc_keys{$_}} sort { $loc_keys{$a} cmp $loc_keys{$b} } keys %loc_keys; -my @sorted_values = map { $data{$_}} sort { $loc_keys{$a} cmp $loc_keys{$b} } keys %loc_keys; -my $query_string = $m->comp('/Elements/QueryString', %ARGS); +$report->SortEntries; -my ($i,$total); +my $query_string = $m->comp('/Elements/QueryString', %ARGS, GroupBy => \@GroupBy ); </%init> <div class="chart-wrapper"> -<span class="chart image"> +% if ( ($ChartStyle || '') =~ /\b(pie|bar)\b/ ) { +<span class="chart image <% $1 %>"> % if (RT->Config->Get('DisableGD')) { <% loc('Graphical charts are not available.') %><br /> % } else { -<img src="<%RT->Config->Get('WebPath')%>/Search/Chart?<%$query_string|n%>" /> +% my $key = Digest::MD5::md5_hex( rand(1024) ); +% $session{'charts_cache'}{$key} = { columns => \%columns, report => $report->Serialize }; +% $session{'i'}++; +<img src="<% RT->Config->Get('WebPath') %>/Search/Chart?Cache=<% $key |un %>&<% $query_string |n %>" /> % } </span> -<table class="collection-as-table chart"> -<tr> -<th class="collection-as-table"><% loc($tix->Label($PrimaryGroupBy)) %> -</th> -<th class="collection-as-table"><&|/l&>Tickets</&> -</th> -</tr> -<%perl> - while (my $key = shift @sorted_keys) { - $i++; - my $value = shift @sorted_values; - $total += $value; -</%perl> -<tr class="<% $i%2 ? 'evenline' : 'oddline' %>"> -<%perl> -# TODO sadly we don't have "creator.city is null" or alike support yet -# so no link if the key is undef for now - if ( $PrimaryGroupBy !~ /(Hourly|Daily|Monthly|Annually)$/ - && $key ne loc('(no value)') ) { - my $group = $PrimaryGroupBy; $group =~ s! !.!; - my %orig_keys = reverse %loc_keys; - my $QueryString = $m->comp('/Elements/QueryString', - Query => "$Query and $group = '$orig_keys{$key}'", - Format => $ARGS{Format}, - Rows => $ARGS{Rows}, - OrderBy => $ARGS{OrderBy}, - Order => $ARGS{Order}, - ); -</%perl> -<td class="label collection-as-table"> -<a href=<% RT->Config->Get('WebPath') %>/Search/Results.html?<%$QueryString%>><%$key%></a> -</td> -<td class="value collection-as-table"> -<a href=<% RT->Config->Get('WebPath') %>/Search/Results.html?<%$QueryString%>><%$value%></a> -</td> -% } else { -<td class="label collection-as-table"><% $key %></td> -<td class="value collection-as-table"><% $value %></td> -% } -</tr> % } -%$i++; -<tr class="<%$i%2 ? 'evenline' : 'oddline' %> total"> -<td class="label collection-as-table"><%loc('Total')%></td> -<td class="value collection-as-table"><%$total||'0'%></td> -</tr> +% if ( ($ChartStyle || '') =~ /\btable\b/ ) { +<& ChartTable, %ARGS, Table => { $report->FormatTable( %columns ) } &> +% } -</table> +% if ( ($ChartStyle || '') =~ /\bsql\b/ ) { <div class="query"><span class="label"><% loc('Query') %>:</span><span class="value"><% $Query %></span></div> +% } </div> diff --git a/rt/share/html/Search/Elements/ChartTable b/rt/share/html/Search/Elements/ChartTable new file mode 100644 index 000000000..045653ae8 --- /dev/null +++ b/rt/share/html/Search/Elements/ChartTable @@ -0,0 +1,119 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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 }}} +<%ARGS> +%Table => () +$Query => undef +</%ARGS> +<%INIT> + +my $base_query = $m->comp('/Elements/QueryString', + Format => $ARGS{Format}, + Rows => $ARGS{Rows}, + OrderBy => $ARGS{OrderBy}, + Order => $ARGS{Order}, +); + +my $interp = $m->interp; +my $eh = sub { $interp->apply_escapes( @_, 'h' ) }; +my $eu = sub { $interp->apply_escapes( @_, 'u' ) }; + +$m->out('<table class="collection-as-table chart">'. "\n"); +foreach my $section (qw(thead tbody tfoot)) { + next unless $Table{ $section } && @{ $Table{ $section } }; + + $m->out("<$section>\n"); + foreach my $row ( @{ $Table{ $section } } ) { + $m->out(' <tr'); + $m->out(' class="'. ($row->{'even'}? 'evenline' : 'oddline') .'"') + if defined $row->{'even'}; + $m->out(">"); + + foreach my $cell ( @{ $row->{'cells'} } ) { + my $tag = $cell->{'type'} eq 'value'? 'td' : 'th'; + $m->out("<$tag"); + + my @class = ('collection-as-table'); + push @class, ($cell->{'type'}) unless $cell->{'type'} eq 'head'; + push @class, $cell->{'even'} ? 'evenline' : 'oddline' + if defined $cell->{'even'}; + $m->out(' class="'. $eh->( join ' ', @class ) .'"'); + + foreach my $dir ( grep $cell->{$_}, qw(rowspan colspan) ) { + my $value = int $cell->{ $dir }; + $m->out(qq{ $dir="$value"}); + } + $m->out(' style="background-color: #'. $m->interp->apply_escapes($cell->{color}) .'"') + if $cell->{color}; + + $m->out('>'); + if ( defined $cell->{'value'} ) { + if ( my $q = $cell->{'query'} ) { + $m->out( + '<a href="'. $eh->(RT->Config->Get('WebPath')) .'/Search/Results.html' + .'?Query='. $eu->(join ' AND ', map "($_)", grep defined && length, $Query, $q) + . $eh->('&') . $base_query + . '">' + ); + $m->out( $eh->( $cell->{'value'} ) ); + $m->out('</a>'); + } + else { + $m->out( $eh->( $cell->{'value'} ) ); + } + } + else { + $m->out(' '); + } + $m->out("</$tag>"); + } + $m->out("</tr>\n"); + } + $m->out("</$section>\n\n"); +} +$m->out("</table>"); +</%INIT> diff --git a/rt/share/html/Search/Elements/ConditionRow b/rt/share/html/Search/Elements/ConditionRow index edf738107..80ecd97b4 100644 --- a/rt/share/html/Search/Elements/ConditionRow +++ b/rt/share/html/Search/Elements/ConditionRow @@ -74,9 +74,11 @@ $handle_block = sub { return $m->scomp( $box->{'Path'}, %{ $box->{'Arguments'} }, Name => $name ); } if ( $box->{'Type'} eq 'text' ) { - my $default = $box->{'Default'} || ''; - my $size = $box->{'Size'}? qq{size="$box->{'Size'}"} : ''; - return qq{<input id="$name" name="$name" value="$default" $size />}; + $box->{id} ||= $box->{name} ||= $name; + $box->{value} ||= delete($box->{Default}) || ''; + return "<input ".join(" ", map{$m->interp->apply_escapes(lc($_),'h') + .q{="}.$m->interp->apply_escapes($box->{$_},'h').q{"}} + sort keys %$box)." />"; } if ( $box->{'Type'} eq 'select' ) { my $res = ''; diff --git a/rt/share/html/Search/Elements/EditFormat b/rt/share/html/Search/Elements/EditFormat index a78fa0574..fffec5c9d 100644 --- a/rt/share/html/Search/Elements/EditFormat +++ b/rt/share/html/Search/Elements/EditFormat @@ -59,7 +59,8 @@ <td valign="top"><select size="6" name="SelectDisplayColumns" multiple="multiple"> % my %seen; % foreach my $field ( grep !$seen{lc $_}++, @$AvailableColumns) { -<option value="<% $field %>"><% loc($field) %></option> +<option value="<% $field %>" <% $selected{$field} ? 'selected="selected"' : '' |n%>>\ +<% $field =~ /^(?:CustomField|CF)\./ ? $field : loc($field) %></option> % } </select></td> <td> @@ -105,8 +106,10 @@ <td valign="top"> <select size="4" name="CurrentDisplayColumns"> % my $i=0; +% my $current = $ARGS{CurrentDisplayColumns} || ''; $current =~ s/^\d+>//; % foreach my $field ( @$CurrentFormat ) { -<option value="<% $i++ %>><% $field->{Column} %>"><% loc( $field->{Column} ) %></option> +<option value="<% $i++ %>><% $field->{Column} %>" <% $field->{Column} eq $current ? 'selected="selected"' : '' |n%>>\ +<% $field->{Column} =~ /^(?:CustomField|CF)\./ ? $field->{Column} : loc( $field->{Column} ) %></option> % } </select> <br /> @@ -120,6 +123,12 @@ </tr> </table> +<%init> +my $selected = $ARGS{SelectDisplayColumns}; +$selected = [ $selected ] unless ref $selected; +my %selected; +$selected{$_}++ for grep {defined} @{ $selected }; +</%init> <%ARGS> $CurrentFormat => undef $AvailableColumns => undef diff --git a/rt/share/html/Search/Elements/EditSearches b/rt/share/html/Search/Elements/EditSearches index f5be486b8..0a55e0dff 100644 --- a/rt/share/html/Search/Elements/EditSearches +++ b/rt/share/html/Search/Elements/EditSearches @@ -146,7 +146,7 @@ $SavedSearch => {} $SavedSearch->{'Id'} = ( $ARGS{Type} && $ARGS{Type} eq 'Chart' ? $ARGS{'SavedChartSearchId'} : $ARGS{'SavedSearchId'} ) || 'new'; -$SavedSearch->{'Description'} = $ARGS{'SavedSearchDescription'} || undef; +$SavedSearch->{'Description'} = $ARGS{'SavedSearchDescription'} || ''; $SavedSearch->{'Privacy'} = $ARGS{'SavedSearchOwner'} || undef; my @results; @@ -158,7 +158,8 @@ if ( $ARGS{'SavedSearchRevert'} ) { if ( $ARGS{'SavedSearchLoad'} ) { my ($container, $id ) = _parse_saved_search ($ARGS{'SavedSearchLoad'}); if ( $container ) { - my $search = $container->Attributes->WithId( $id ); + my $search = RT::Attribute->new( $session{'CurrentUser'} ); + $search->Load( $id ); $SavedSearch->{'Id'} = $ARGS{'SavedSearchLoad'}; $SavedSearch->{'Object'} = $search; $SavedSearch->{'Description'} = $search->Description; @@ -194,7 +195,8 @@ elsif ( $ARGS{'SavedSearchDelete'} ) { } elsif ( $ARGS{'SavedSearchCopy'} ) { my ($container, $id ) = _parse_saved_search( $ARGS{'SavedSearchId'} ); - $SavedSearch->{'Object'} = $container->Attributes->WithId( $id ); + $SavedSearch->{'Object'} = RT::Attribute->new( $session{'CurrentUser'} ); + $SavedSearch->{'Object'}->Load( $id ); if ( $ARGS{'SavedSearchDescription'} && $ARGS{'SavedSearchDescription'} ne $SavedSearch->{'Object'}->Description ) { $SavedSearch->{'Description'} = $ARGS{'SavedSearchDescription'}; } else { @@ -208,7 +210,8 @@ if ( $SavedSearch->{'Id'} && $SavedSearch->{'Id'} ne 'new' && !$SavedSearch->{'Object'} ) { my ($container, $id ) = _parse_saved_search( $ARGS{'SavedSearchId'} ); - $SavedSearch->{'Object'} = $container->Attributes->WithId( $id ); + $SavedSearch->{'Object'} = RT::Attribute->new( $session{'CurrentUser'} ); + $SavedSearch->{'Object'}->Load( $id ); $SavedSearch->{'Description'} ||= $SavedSearch->{'Object'}->Description; } @@ -290,7 +293,7 @@ if ( $obj && $obj->id ) { } push @results, loc('Updated saved search "[_1]"', $desc); } -elsif ( $id eq 'new' ) { +elsif ( $id eq 'new' and defined $desc and length $desc ) { my $saved_search = RT::SavedSearch->new( $session{'CurrentUser'} ); my ($status, $msg) = $saved_search->Save( Privacy => $privacy, @@ -300,8 +303,8 @@ elsif ( $id eq 'new' ) { ); if ( $status ) { - $SavedSearch->{'Object'} = - $session{'CurrentUser'}->UserObj->Attributes->WithId( $saved_search->Id ); + $SavedSearch->{'Object'} = RT::Attribute->new( $session{'CurrentUser'} ); + $SavedSearch->{'Object'}->Load( $saved_search->Id ); # Build new SearchId $SavedSearch->{'Id'} = ref( $session{'CurrentUser'}->UserObj ) . '-' @@ -313,6 +316,9 @@ elsif ( $id eq 'new' ) { push @results, loc("Can't find a saved search to work with").': '.loc($msg); } } +elsif ( $id eq 'new' ) { + push @results, loc("Can't save a search without a Description"); +} else { push @results, loc("Can't save this search"); } diff --git a/rt/share/html/Search/Elements/EditSort b/rt/share/html/Search/Elements/EditSort index de5d2d818..43ae7292d 100644 --- a/rt/share/html/Search/Elements/EditSort +++ b/rt/share/html/Search/Elements/EditSort @@ -68,7 +68,7 @@ % if (defined $OrderBy[$o] and $fieldval eq $OrderBy[$o]) { selected="selected" % } -><% loc($field) %></option> +><% $field =~ /^(?:CustomField|CF)\./ ? $field : loc($field) %></option> % } </select> <select name="Order"> diff --git a/rt/share/html/Search/Elements/PickBasics b/rt/share/html/Search/Elements/PickBasics index 3aae96589..29eea7e3f 100644 --- a/rt/share/html/Search/Elements/PickBasics +++ b/rt/share/html/Search/Elements/PickBasics @@ -70,10 +70,10 @@ my @lines = ( Type => 'component', Path => '/Elements/SelectBoolean', Arguments => { - True => loc("matches"), - False => loc("doesn't match"), - TrueVal => 'LIKE', - FalseVal => 'NOT LIKE', + True => loc("matches"), + False => loc("doesn't match"), + TrueVal => 'LIKE', + FalseVal => 'NOT LIKE', }, }, Value => { Type => 'text', Size => 20 }, @@ -89,7 +89,7 @@ my @lines = ( Value => { Type => 'component', Path => '/Elements/SelectQueue', - Arguments => { NamedValues => 1, CheckQueueRight => 'ShowTicket' }, + Arguments => { NamedValues => 1, }, }, }, { @@ -102,7 +102,7 @@ my @lines = ( }, Value => { Type => 'component', - Path => '/Elements/SelectStatus', + Path => '/Ticket/Elements/SelectStatus', Arguments => { SkipDeleted => 1, Queues => \%queues }, }, }, @@ -114,6 +114,7 @@ my @lines = ( Owner => loc('Owner'), Creator => loc('Creator'), LastUpdatedBy => loc('Last updated by'), + UpdatedBy => loc('Updated by'), ], }, Op => { @@ -141,6 +142,19 @@ my @lines = ( Value => { Type => 'text', Size => 20 } }, { + Name => 'WatcherGroup', + Field => { + Type => 'component', + Path => 'SelectPersonType', + Arguments => { Default => 'Owner', Suffix => 'Group' }, + }, + Op => { + Type => 'select', + Options => [ '=' => loc('is') ], + }, + Value => { Type => 'text', Size => 20, "data-autocomplete" => "Groups" } + }, + { Name => 'Date', Field => { Type => 'component', diff --git a/rt/share/html/Search/Elements/PickCFs b/rt/share/html/Search/Elements/PickCFs index cf8c92a27..e8d9c71e2 100644 --- a/rt/share/html/Search/Elements/PickCFs +++ b/rt/share/html/Search/Elements/PickCFs @@ -58,7 +58,7 @@ $m->callback( my @lines; while ( my $CustomField = $CustomFields->Next ) { my %line; - $line{'Name'} = "'$TicketSQLField.{" . $CustomField->Name . "}'"; + $line{'Name'} = "$TicketSQLField.{" . $CustomField->Name . "}"; $line{'Field'} = $CustomField->Name; # Op @@ -88,20 +88,11 @@ while ( my $CustomField = $CustomFields->Next ) { } # Value - if ($CustomField->Type =~ /^Date(Time)?$/) { - my $is_datetime = $1 ? 1 : 0; - $line{'Value'} = { - Type => 'component', - Path => '/Elements/SelectDate', - Arguments => { $is_datetime ? (ShowTime => 1) : (ShowTime => 0), }, - }; - } else { - $line{'Value'} = { - Type => 'component', - Path => '/Elements/SelectCustomFieldValue', - Arguments => { CustomField => $CustomField }, - }; - } + $line{'Value'} = { + Type => 'component', + Path => '/Elements/SelectCustomFieldValue', + Arguments => { CustomField => $CustomField }, + }; push @lines, \%line; } diff --git a/rt/share/html/Search/Elements/PickCriteria b/rt/share/html/Search/Elements/PickCriteria index b2e84cae9..e55e27085 100644 --- a/rt/share/html/Search/Elements/PickCriteria +++ b/rt/share/html/Search/Elements/PickCriteria @@ -54,6 +54,8 @@ <& PickBasics &> <& PickCustomerFields &> <& PickTicketCFs, queues => \%queues &> +<& PickObjectCFs, Class => 'Transaction', queues => \%queues &> +<& PickObjectCFs, Class => 'Queue', queues => \%queues &> % $m->callback( %ARGS, CallbackName => "AfterCFs" ); <tr class="separator"><td colspan="3"><hr /></td></tr> diff --git a/rt/share/html/Search/Elements/PickObjectCFs b/rt/share/html/Search/Elements/PickObjectCFs new file mode 100644 index 000000000..1a67338c5 --- /dev/null +++ b/rt/share/html/Search/Elements/PickObjectCFs @@ -0,0 +1,76 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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 }}} +<%ARGS> +$Class +%queues => () +</%ARGS> +<%init> +my $CustomFields = RT::CustomFields->new( $session{'CurrentUser'} ); +$CustomFields->ApplySortOrder; +$CustomFields->LimitToLookupType( "RT::$Class"->CustomFieldLookupType ); +$CustomFields->LimitToObjectId(0); + +foreach my $name (keys %queues) { + my $queue = RT::Queue->new($session{'CurrentUser'}); + $queue->Load($name); + next unless $queue->Id; + $CustomFields->LimitToObjectId($queue->Id); + $CustomFields->SetContextObject( $queue ) if keys %queues == 1; +} + +my $has_cf = $CustomFields->First ? 1 : 0; +$CustomFields->GotoFirstItem; +</%init> +% if ($has_cf) { +<tr class="separator"> + <td colspan="3"> + <hr><em><% loc("[_1] CFs", loc($Class)) %></em> + </td> +</tr> +% } +<& PickCFs, %ARGS, TicketSQLField => "${Class}CF", CustomFields => $CustomFields &> diff --git a/rt/share/html/Search/Elements/PickTicketCFs b/rt/share/html/Search/Elements/PickTicketCFs index ac52049c3..ae3a4a286 100644 --- a/rt/share/html/Search/Elements/PickTicketCFs +++ b/rt/share/html/Search/Elements/PickTicketCFs @@ -54,8 +54,11 @@ foreach my $id (keys %queues) { # Gotta load up the $queue object, since queues get stored by name now. my $queue = RT::Queue->new($session{'CurrentUser'}); $queue->Load($id); - $CustomFields->LimitToQueue($queue->Id) if $queue->Id; + next unless $queue->Id; + $CustomFields->LimitToQueue($queue->Id); + $CustomFields->SetContextObject( $queue ) if keys %queues == 1; } $CustomFields->LimitToGlobal; +$CustomFields->OrderBy( FIELD => 'Name', ORDER => 'ASC' ); </%init> <& PickCFs, %ARGS, TicketSQLField => 'CF', CustomFields => $CustomFields &> diff --git a/rt/share/html/Search/Elements/ResultsRSSView b/rt/share/html/Search/Elements/ResultsRSSView index 0bce7ec45..f392369a8 100644 --- a/rt/share/html/Search/Elements/ResultsRSSView +++ b/rt/share/html/Search/Elements/ResultsRSSView @@ -46,41 +46,7 @@ %# %# END BPS TAGGED BLOCK }}} <%INIT> -my $current_user = $session{CurrentUser}; - -if ( $m->request_comp->path =~ RT->Config->Get('WebNoAuthRegex') ) { - my $path = $m->dhandler_arg; - - my $notfound = sub { - my $mesg = shift; - $r->headers_out->{'Status'} = '404 Not Found'; - $RT::Logger->info("Error encountered in rss generation: $mesg"); - $m->clear_and_abort; - }; - - $notfound->("Invalid path: $path") unless $path =~ m!^([^/]+)/([^/]+)/?!; - - my ( $name, $auth ) = ( $1, $2 ); - - # Unescape parts - $name =~ s/\%([0-9a-z]{2})/chr(hex($1))/gei; - - # Decode from bytes to characters - $name = Encode::decode( "UTF-8", $name ); - - my $user = RT::User->new(RT->SystemUser); - $user->Load($name); - $notfound->("Invalid user: $user") unless $user->id; - - $notfound->("Invalid authstring") - unless $user->ValidateAuthString( $auth, - $ARGS{Query} . $ARGS{Order} . $ARGS{OrderBy} ); - - $current_user = RT::CurrentUser->new; - $current_user->Load($user); -} - -my $Tickets = RT::Tickets->new($current_user); +my $Tickets = RT::Tickets->new($session{'CurrentUser'}); $Tickets->FromSQL($ARGS{'Query'}); if ($OrderBy =~ /\|/) { # Multiple Sorts @@ -92,48 +58,58 @@ if ($OrderBy =~ /\|/) { } else { $Tickets->OrderBy(FIELD => $OrderBy, ORDER => $Order); } -$r->content_type('application/rss+xml'); - - +$r->content_type('application/rss+xml; charset=utf-8'); - # create an RSS 1.0 file (http://purl.org/rss/1.0/) - use XML::RSS; - my $rss = XML::RSS->new(version => '1.0'); - $rss->channel( - title => RT->Config->Get('rtname').": Search " . $ARGS{'Query'}, - link => RT->Config->Get('WebURL'), - description => "", - dc => { - }, - generator => "RT v" . $RT::VERSION, - syn => { - updatePeriod => "hourly", - updateFrequency => "1", - updateBase => "1901-01-01T00:00+00:00", - }, - ); +use XML::RSS; +my $rss = XML::RSS->new(version => '1.0'); +my $url; +if ( RT->Config->Get('CanonicalizeURLsInFeeds') ) { + $url = RT->Config->Get('WebURL'); +} else { + $url = RT::Interface::Web::GetWebURLFromRequest(); +} - while ( my $Ticket = $Tickets->Next()) { - my $creator_str = $m->scomp('/Elements/ShowUser', User => $Ticket->CreatorObj); - $creator_str =~ s/[\r\n]//g; - - # Get the plain-text content; it is interpreted as HTML by RSS - # readers, so it must be escaped (and is escaped _again_ when - # inserted into the XML). - my $content = $Ticket->Transactions->First->Content; - $content = $m->interp->apply_escapes( $content, 'h'); - $rss->add_item( - title => $Ticket->Subject || loc('No Subject'), - link => RT->Config->Get('WebURL')."Ticket/Display.html?id=".$Ticket->id, - description => $content, - dc => { creator => $creator_str, - date => $Ticket->CreatedObj->RFC2822, - }, - guid => $Ticket->Queue . '_' . $Ticket->id, - ); - } +my $base_date = RT::Date->new( RT->SystemUser ); +$base_date->SetToNow; +$base_date->SetToMidnight; + +$rss->channel( + title => RT->Config->Get('rtname').": Search " . $ARGS{'Query'}, + link => $url, + description => "", + dc => { }, + generator => "RT v" . $RT::VERSION, + syn => { + updatePeriod => "hourly", + updateFrequency => "1", + updateBase => $base_date->W3CDTF, + }, +); + + +while ( my $Ticket = $Tickets->Next()) { + my $creator_str = $Ticket->CreatorObj->Format; + $creator_str =~ s/[\r\n]//g; + + # Get the plain-text content; it is interpreted as HTML by RSS + # readers, so it must be escaped (and is escaped _again_ when + # inserted into the XML). + my $content = $Ticket->Transactions->First->Content; + $content = $m->interp->apply_escapes( $content, 'h'); + + $rss->add_item( + title => $Ticket->Subject || loc('No Subject'), + link => $url . "Ticket/Display.html?id=".$Ticket->id, + description => $content, + dc => { + creator => $creator_str, + date => $Ticket->CreatedObj->W3CDTF, + }, + guid => $Ticket->Queue . '_' . $Ticket->id, + ); +} $m->out($rss->as_string); $m->abort(); diff --git a/rt/share/html/Search/Elements/SearchPrivacy b/rt/share/html/Search/Elements/SearchPrivacy index dd7ef3b2f..1e43dfd39 100644 --- a/rt/share/html/Search/Elements/SearchPrivacy +++ b/rt/share/html/Search/Elements/SearchPrivacy @@ -53,9 +53,9 @@ my $label; if (ref($Object) eq 'RT::User') { $label = $Object->id == $session{'CurrentUser'}->Id ? loc("My saved searches") - : loc("[_1]'s saved searches", $m->scomp('/Elements/ShowUser', User => $Object)); + : loc("[_1]'s saved searches", $Object->Format); } else { - $label = loc("[_1]'s saved searches", $m->interp->apply_escapes($Object->Name, 'h')); + $label = loc("[_1]'s saved searches", $Object->Name); } </%init> -<% $label |n %>\ +<% $label %>\ diff --git a/rt/share/html/Search/Elements/SearchesForObject b/rt/share/html/Search/Elements/SearchesForObject index 397a0d95c..f58752d00 100644 --- a/rt/share/html/Search/Elements/SearchesForObject +++ b/rt/share/html/Search/Elements/SearchesForObject @@ -55,10 +55,10 @@ my @result; while (my $search = $Object->Attributes->Next) { my $desc; if ($search->Name eq 'SavedSearch') { - push @result, [$search->Description, $search->Description, $search]; + push @result, [$search->Description, $search->Description, $search]; } elsif ($search->Name =~ m/^Search - (.*)/) { - push @result, [$1, loc($1), $search]; + push @result, [$1, loc($1), $search]; } } return @result; diff --git a/rt/share/html/Search/Elements/SelectAndOr b/rt/share/html/Search/Elements/SelectAndOr index cbea34fc2..d506ef785 100644 --- a/rt/share/html/Search/Elements/SelectAndOr +++ b/rt/share/html/Search/Elements/SelectAndOr @@ -45,8 +45,8 @@ %# those contributions and any derivatives thereof. %# %# END BPS TAGGED BLOCK }}} -<input type="radio" class="radio" name="<%$Name%>" checked="checked" value="AND" /><&|/l&>AND</&> -<input type="radio" class="radio" name="<%$Name%>" value="OR" /><&|/l&>OR</&> +<label><input type="radio" class="radio" name="<%$Name%>" checked="checked" value="AND" /><&|/l&>AND</&></label> +<label><input type="radio" class="radio" name="<%$Name%>" value="OR" /><&|/l&>OR</&></label> <%ARGS> $Name => "Operator" diff --git a/rt/share/html/Search/Elements/SelectChartFunction b/rt/share/html/Search/Elements/SelectChartFunction new file mode 100644 index 000000000..dad6b781a --- /dev/null +++ b/rt/share/html/Search/Elements/SelectChartFunction @@ -0,0 +1,79 @@ +%# BEGIN BPS TAGGED BLOCK {{{ +%# +%# COPYRIGHT: +%# +%# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC +%# <sales@bestpractical.com> +%# +%# (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 }}} +<select name="<% $Name %>" class="cascade-by-optgroup"> +% if ( $ShowEmpty ) { +<option value=""> </option> +% } +<%perl> +my $in_optgroup = ""; +while ( my ($value, $display) = splice @functions, 0, 2 ) { + my $optgroup = $value =~ /\((.+)\)$/ ? $1 : $display; + if ($in_optgroup ne $optgroup) { + $m->out("</optgroup>\n") if $in_optgroup; + + my $name = $m->interp->apply_escapes(loc($optgroup), 'h'); + $m->out(qq[<optgroup label="$name">\n]); + + $in_optgroup = $optgroup; + } +</%perl> +<option value="<% $value %>"<% $value eq $Default ? qq[ selected="selected"] : '' |n %>><% loc( $display ) %></option> +% } +% if ($in_optgroup) { + </optgroup> +% } +</select> +<%ARGS> +$Name => 'ChartFunction' +$Default => 'COUNT' +$ShowEmpty => 0 +</%ARGS> +<%INIT> +my @functions = RT::Report::Tickets->Statistics; +$Default = '' unless defined $Default; +</%INIT> diff --git a/rt/share/html/Search/Elements/SelectChartType b/rt/share/html/Search/Elements/SelectChartType index 266885f0d..c4d95d00c 100644 --- a/rt/share/html/Search/Elements/SelectChartType +++ b/rt/share/html/Search/Elements/SelectChartType @@ -50,9 +50,10 @@ $Name => 'ChartType' $Default => 'bar' </%args> <select id="<%$Name%>" name="<%$Name%>"> -% foreach my $option (qw(bar pie)) { +% foreach my $option ('bar', 'pie', 'table') { % # 'bar' # loc % # 'pie' # loc +% # 'table' # loc <option value="<%$option%>"<% $option eq $Default ? qq[ selected="selected"] : '' |n %>><%loc($option)%></option> % } </select> diff --git a/rt/share/html/Search/Elements/SelectGroup b/rt/share/html/Search/Elements/SelectGroup index 907c88e27..27d6a762e 100644 --- a/rt/share/html/Search/Elements/SelectGroup +++ b/rt/share/html/Search/Elements/SelectGroup @@ -56,7 +56,7 @@ <%INIT> my $groups = RT::Groups->new($session{'CurrentUser'}); -$groups->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => $Domain); +$groups->Limit(FIELD => 'Domain', OPERATOR => '=', VALUE => $Domain, CASESENSITIVE => 0); </%INIT> <%ARGS> diff --git a/rt/share/html/Search/Elements/SelectGroupBy b/rt/share/html/Search/Elements/SelectGroupBy index 8daab6daa..99f0f47eb 100644 --- a/rt/share/html/Search/Elements/SelectGroupBy +++ b/rt/share/html/Search/Elements/SelectGroupBy @@ -49,11 +49,29 @@ $Name => 'GroupBy' $Default => 'Status' $Query => '' +$ShowEmpty => 0 </%args> -<select id="<% $Name %>" name="<% $Name %>"> -% while (@options) { -% my ($text, $value) = (shift @options, shift @options); -<option value="<% $value %>" <% $value eq $Default ? 'selected="selected"' : '' |n%>><% $text %></option> +<select name="<% $Name %>" class="cascade-by-optgroup"> +% if ( $ShowEmpty ) { +<option value=""> </option> +% } +<%perl> +my $in_optgroup = ""; +while ( my ($label, $value) = splice @options, 0, 2 ) { + my ($optgroup, $text) = @$label; + if ($in_optgroup ne $optgroup) { + $m->out("</optgroup>\n") if $in_optgroup; + + my $name = $m->interp->apply_escapes(loc($optgroup), 'h'); + $m->out(qq[<optgroup label="$name">\n]); + + $in_optgroup = $optgroup; + } +</%perl> +<option value="<% $value %>" <% $value eq ($Default||'') ? 'selected="selected"' : '' |n %>><% loc($text) %></option> +% } +% if ($in_optgroup) { + </optgroup> % } </select> <%init> diff --git a/rt/share/html/Search/Elements/SelectLinks b/rt/share/html/Search/Elements/SelectLinks index 3759a58d1..1b8509461 100644 --- a/rt/share/html/Search/Elements/SelectLinks +++ b/rt/share/html/Search/Elements/SelectLinks @@ -47,7 +47,7 @@ %# END BPS TAGGED BLOCK }}} <select name="<%$Name%>"> % foreach (@fields) { -<option value="<%$_%>"><% loc($_) %></option> +<option value="<%$_->[0]%>"><% $_->[1] %></option> % } </select> <%ARGS> @@ -55,12 +55,13 @@ $Name => 'LinksField' </%ARGS> <%INIT> -my @fields = ('HasMember', - 'MemberOf', - 'DependsOn', - 'DependedOnBy', - 'RefersTo', - 'ReferredToBy', - 'LinkedTo', - ); +my @fields = ( + [ HasMember => loc("Child") ], + [ MemberOf => loc("Parent") ], + [ DependsOn => loc("Depends on") ], + [ DependedOnBy => loc("Depended on by") ], + [ RefersTo => loc("Refers to") ], + [ ReferredToBy => loc("Referred to by") ], + [ LinkedTo => loc("Links to") ], +); </%INIT> diff --git a/rt/share/html/Search/Elements/SelectPersonType b/rt/share/html/Search/Elements/SelectPersonType index 7ec875a8d..0fc541b07 100644 --- a/rt/share/html/Search/Elements/SelectPersonType +++ b/rt/share/html/Search/Elements/SelectPersonType @@ -51,7 +51,7 @@ % } % for my $option (@types) { % if ($Suffix) { -<option value="<% $option %><% $Suffix %>"<%$option eq $Default && qq[ selected="selected"] |n %> ><%loc($option)%></option> +<option value="<% $option %><% $Suffix %>"<%$option eq $Default && qq[ selected="selected"] |n %> ><% loc($option) %> <% loc('Group') %></option> % next; % } % foreach my $subtype (@subtypes) { @@ -66,7 +66,7 @@ if ($Scope =~ /queue/) { @types = qw(Cc AdminCc); } elsif ($Suffix eq 'Group') { - @types = qw(Requestor Cc AdminCc Watcher); + @types = qw(Owner Requestor Cc AdminCc Watcher); } else { @types = qw(Requestor Cc AdminCc Watcher Owner QueueCc QueueAdminCc QueueWatcher); |