[Rt-commit] rt branch, 5.0/configurable-linked-queue-portlets, created. rt-5.0.0alpha1-419-gffa0b41f97

? sunnavy sunnavy at bestpractical.com
Mon May 11 17:57:59 EDT 2020


The branch, 5.0/configurable-linked-queue-portlets has been created
        at  ffa0b41f972e3b1e1c3b138b94e8c0845462ce0c (commit)

- Log -----------------------------------------------------------------
commit 86a85bc19ea436bd97464aae1e0d67dd6d987952
Author: Maureen E. Mirville <maureen at bestpractical.com>
Date:   Tue Aug 14 23:02:03 2018 -0400

    Add a configurable queue portlet to ticket display page
    
    RTIR Incident page displays links portlets by queue. Isolating
    these portlets allows a user to view linked tickets based on the
    queue and their relations on ticket display page.

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 8d8152c02e..f2ec3c14f2 100644
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -2545,6 +2545,59 @@ to the Article with that name.
 
 Set($WikiImplicitLinks, 0);
 
+=item C<%LinkedQueuePortlets>
+
+C<%LinkedQueuePortlets> allows you to display links to tickets in
+another queue in a stand-alone portlet on the ticket display page.
+This makes it easier to highlight specific ticket links separate from
+the standard Links portlet.
+
+For example, you might have a Sales queue that tracks incoming product
+requests, and for each ticket you create a linked ticket in the Shipping
+queue for each outgoing shipment. You could add the configuration below
+to create a stand-alone Shipping portlet on tickets in the Sales queue,
+making it easier to see those linked tickets. You might have a Returns
+queue to show as well.
+
+    Set( %LinkedQueuePortlets, (
+        'Sales' => [
+            { 'Shipping'   => [ 'All' ] },
+            { 'Returns'   => [ 'RefersTo' ] },
+        ],
+        'Shipping'   => [
+            { 'Postage' => [ 'DependsOn', 'HasMember' ] },
+        ],
+    ));
+
+You can include multiple linked queues in each ticket and they are
+displayed in the order you define them in the configuration. The values
+are RT link types: 'DependsOn', 'DependedOnBy', 'HasMember'
+(children), 'MemberOf' (parents), 'RefersTo', and 'ReferredToBy'.
+'All' lists all linked tickets. You can include multiple link types for
+each as shown above.
+
+=cut
+
+Set( %LinkedQueuePortlets, () );
+
+=item C<%LinkedQueuePortletFormats>
+
+C<%LinkedQueuePortletFormats> defines the format for displaying
+linked tickets in each linked queue portlet defined by C<%LinkedQueuePortlets>.
+
+To change just the General list you would do:
+
+    Set(%LinkedQueuePortletFormats, General => 'modified configuration');
+
+=cut
+
+Set( %LinkedQueuePortletFormats,
+    Default =>
+        q{'<b><a href="__WebPath__/Ticket/Display.html?id=__id__">__id__</a></b>/TITLE:#',}.
+        q{'<b><a href="__WebPath__/Ticket/Display.html?id=__id__">__Subject__</a></b>/TITLE:Subject',}.
+        q{Status},
+);
+
 =item C<$PreviewScripMessages>
 
 Set C<$PreviewScripMessages> to 1 if the scrips preview on the ticket
diff --git a/share/html/Ticket/Elements/ShowLinkedQueues b/share/html/Ticket/Elements/ShowLinkedQueues
new file mode 100644
index 0000000000..bff684b001
--- /dev/null
+++ b/share/html/Ticket/Elements/ShowLinkedQueues
@@ -0,0 +1,165 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2018 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<%PERL>
+
+foreach my $queues ( @{ $portlet_config{ $queue } } ) {
+    foreach my $queue_name ( keys %{ $queues } ) {
+        my $queue_obj = RT::Queue->new( $session{ CurrentUser } );
+        my ( $ret ) = $queue_obj->Load( $queue_name );
+        unless ( $ret ) {
+            RT::Logger->error( "Couldn't load queue $queue_name" );
+            next;
+        }
+        my $link_types = $queues->{$queue_name};
+        my $query      = "Queue = '$queue_name'";
+
+        my $ticket_id = $TicketObj->id;
+        if ( grep { lc $_ eq 'all' } @$link_types ) {
+            $query .= " AND ( LinkedTo = $ticket_id OR LinkedFrom = $ticket_id )";
+        }
+        else {
+            my @link_relations = map { $_ . " = $ticket_id" } @$link_types;
+            my $link_query = join( ' OR ', @link_relations );
+            if ($link_query) {
+                $query .= ' AND ( ' . $link_query . ' )';
+            }
+            else {
+                $query = 'id=0';
+            }
+        }
+
+        # create an identifiable class name for the linked queue portlet so
+        # we can specifically target it apart from ticket-info-links.
+        my $linked_queue_class = 'linked-queue';
+
+        my $query_string = $m->comp( '/Elements/QueryString', Query => $query );
+        my $title_href = RT->Config->Get( 'WebPath' ) .  "/Search/Results.html?$query_string";
+        my $title_class = 'inverse';
+        my $class = 'ticket-info-links' . ' ' . $linked_queue_class;
+        my $titleright_raw = '';
+
+$m->callback( CallbackName => 'MassageTitleBox',
+    ARGSRef         => \%ARGS,
+    title           => \$queue_name,
+    title_href      => \$title_href,
+    titleright_raw  => \$titleright_raw,
+    title_class     => \$title_class,
+    class           => \$class,
+);
+
+</%PERL>
+
+<&| /Widgets/TitleBox,
+    title           => $queue_name,
+    title_href      => $title_href,
+    titleright_raw  => $titleright_raw,
+    title_class     => $title_class,
+    class           => $class,
+&>
+
+<%PERL>
+my @queries = map { "$query AND $_" } q{Status = '__Active__'}, q{Status = '__Inactive__'};
+my @empty_messages
+    = ( loc( '(No active tickets)', $queue_name ), loc( '(No inactive tickets)', $queue_name ) );
+
+$m->callback( CallbackName => 'MassageQueries',
+    ARGSRef         => \%ARGS,
+    Queue           => $queue_name,
+    Queries         => \@queries,
+    EmptyMessages   => \@empty_messages,
+);
+
+for my $query ( @queries ) {
+    my $empty_message = shift @empty_messages;
+    my $format = $Format;
+    my $order_by = $OrderBy;
+    my $rows = $Rows;
+
+$m->callback( CallbackName => 'MassageSearchArgs',
+    ARGSRef      => \%ARGS,
+    Queue        => $queue_name,
+    Query        => $query,
+    Format       => \$format,
+    OrderBy      => \$order_by,
+    Rows         => \$rows,
+);
+    my $tickets = RT::Tickets->new($session{CurrentUser});
+    $tickets->FromSQL($query);
+    if ( $tickets->Count ) {
+</%PERL>
+<& /Elements/CollectionList, %ARGS,
+    Class            => 'RT::Tickets',
+    Query            => $query,
+    Format           => $format,
+    OrderBy          => $order_by,
+    Rows             => $rows,
+    ShowHeader       => 0,
+&>
+
+% } else {
+    <div class="empty-message"><% $empty_message %></div>
+% }
+% }
+
+</&>
+%   }
+%}
+<%INIT>
+my %portlet_config = RT->Config->Get( 'LinkedQueuePortlets' );
+return unless %portlet_config;
+my $queue = $TicketObj->QueueObj->Name;
+return unless $portlet_config{ $queue };
+</%INIT>
+
+
+<%ARGS>
+$TicketObj
+$OrderBy => 'Due'
+$Rows => 8
+$Format => RT->Config->Get( 'LinkedQueuePortletFormats' )->{ 'Default' }
+</%ARGS>
diff --git a/share/html/Ticket/Elements/ShowSummary b/share/html/Ticket/Elements/ShowSummary
index 2ac9edae0c..9742586af4 100644
--- a/share/html/Ticket/Elements/ShowSummary
+++ b/share/html/Ticket/Elements/ShowSummary
@@ -171,6 +171,13 @@ my $dates_behavior = $InlineEdit ? ($inline_edit_behavior{Dates} || $inline_edit
 %       }
     </&>
 % $m->callback( %ARGS, CallbackName => 'AfterDates' );
+% my (@extra);
+% push @extra, titleright_raw => '<a href="'. RT->Config->Get('WebPath'). '/Ticket/Graphs/index.html?id='.$Ticket->id.'">'.loc('Graph').'</a>' unless RT->Config->Get('DisableGraphViz');
+
+<& /Ticket/Elements/ShowLinkedQueues,
+    TicketObj => $Ticket,
+&>
+
 <& /Ticket/Elements/ShowAssets, Ticket => $Ticket &>
 <%PERL>
 my $links_url = RT->Config->Get('WebPath')."/Ticket/ModifyLinks.html?id=".$Ticket->Id;
@@ -182,7 +189,6 @@ my $links_graph = '<a href="' . RT->Config->Get('WebPath') . '/Ticket/Graphs/ind
 my $links_titleright = join ' ',
     ($can_modify && $links_behavior =~ /^(link|click)$/ ? ($links_inline) : ()),
     (RT->Config->Get('DisableGraphViz') ? () : $links_graph);
-my @extra;
 push @extra, (titleright_raw => $links_titleright) if $links_titleright;
 </%PERL>
 % $m->callback( %ARGS, CallbackName => 'LinksExtra', extra => \@extra );

commit 749b692f19444b9a064f4ec9fabb0f34846945db
Author: Blaine Motsinger <blaine at bestpractical.com>
Date:   Fri Mar 20 13:46:32 2020 -0500

    Add test for Linked Queue Portlets

diff --git a/t/web/linked_queue_portlets.t b/t/web/linked_queue_portlets.t
new file mode 100644
index 0000000000..77cf751164
--- /dev/null
+++ b/t/web/linked_queue_portlets.t
@@ -0,0 +1,55 @@
+use strict;
+use warnings;
+
+use RT::Test tests => undef;
+
+# create ticket in general queue
+# this ticket will display the portlet for the other queue, with the other ticket in it
+my $ticket_one = RT::Test->create_ticket(
+    Subject => 'test ticket in General queue',
+    Queue   => 'General'
+);
+
+# create test queue and test ticket in it
+my $queue_name = 'test queue';
+my $queue_two  = RT::Test->load_or_create_queue(
+    Name        => $queue_name,
+    Description => $queue_name
+);
+my $ticket_two = RT::Test->create_ticket(
+    Subject => 'test ticket in "' . $queue_name . '" queue',
+    Queue   => $queue_name
+);
+
+# change config to load new queue portlet in general
+# this isn't exercising limiting to a specific link relationship set such as 'HasMember', 'MemberOf', or 'RefersTo'; just 'All'
+RT->Config->Set(
+    LinkedQueuePortlets => (
+        General => [
+            { $queue_name => [ 'All' ] },
+        ],
+    ),
+);
+
+# verify new queue portlet is present in ticket in general
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok( $m->login(), 'logged in' );
+
+my $linked_queue_class = 'linked-queue';
+$m->get_ok( "/Ticket/Display.html?id=" . $ticket_one->Id );
+$m->content_contains( $linked_queue_class,
+    'ticket in "General" queue contains linked queue portlet for "' . $queue_name . '" queue' );
+
+# link tickets so the ticket shows up in the linked queue portlet
+ok( $ticket_one->AddLink( Type => 'RefersTo', Target => $ticket_two->Id ),
+    'added RefersTo link for ticket in "General" queue to ticket in "' . $queue_name . '" queue' );
+
+$m->get_ok( "/Ticket/Display.html?id=" . $ticket_one->Id );
+is( $m->dom->find(".$linked_queue_class .collection-as-table a")->first->attr('href'),
+    '/Ticket/Display.html?id=' . $ticket_two->Id,
+    'linked queue portlet contains link to ticket in "' . $queue_name . '" queue' );
+
+# TODO:
+# limit the linked queue configuration to only specific link relationships to ensure only those tickets show up in the portlet
+
+done_testing();

commit 0c6e667c34c6ac2fdc2184247cd70cc0f3e0132a
Author: Blaine Motsinger <blaine at bestpractical.com>
Date:   Wed Apr 29 10:37:28 2020 -0500

    Use LinkedQueuePortletFormats for ShowLinkedQueues
    
    This commit changes ShowLinkedQueues to use the defined format in
    LinkedQueuePortletFormats for the linked queue being displayed. If
    the queue name isn't set in the config, the default format is used.

diff --git a/share/html/Ticket/Elements/ShowLinkedQueues b/share/html/Ticket/Elements/ShowLinkedQueues
index bff684b001..8ae3639fcf 100644
--- a/share/html/Ticket/Elements/ShowLinkedQueues
+++ b/share/html/Ticket/Elements/ShowLinkedQueues
@@ -114,9 +114,12 @@ $m->callback( CallbackName => 'MassageQueries',
     EmptyMessages   => \@empty_messages,
 );
 
+my $format = ( exists RT->Config->Get('LinkedQueuePortletFormats')->{$queue_name}
+    ? RT->Config->Get('LinkedQueuePortletFormats')->{$queue_name}
+    : RT->Config->Get('LinkedQueuePortletFormats')->{'Default'} );
+
 for my $query ( @queries ) {
     my $empty_message = shift @empty_messages;
-    my $format = $Format;
     my $order_by = $OrderBy;
     my $rows = $Rows;
 
@@ -161,5 +164,4 @@ return unless $portlet_config{ $queue };
 $TicketObj
 $OrderBy => 'Due'
 $Rows => 8
-$Format => RT->Config->Get( 'LinkedQueuePortletFormats' )->{ 'Default' }
 </%ARGS>

commit df45abbab5f22aa01c433cdd32de94794fce5a7c
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Fri May 8 16:28:09 2020 -0400

    Add spacing between title and table showing linked tickets

diff --git a/share/html/Ticket/Elements/ShowLinkedQueues b/share/html/Ticket/Elements/ShowLinkedQueues
index 8ae3639fcf..b20abfe850 100644
--- a/share/html/Ticket/Elements/ShowLinkedQueues
+++ b/share/html/Ticket/Elements/ShowLinkedQueues
@@ -100,6 +100,7 @@ $m->callback( CallbackName => 'MassageTitleBox',
     titleright_raw  => $titleright_raw,
     title_class     => $title_class,
     class           => $class,
+    content_class   => 'linked-queue-portlet',
 &>
 
 <%PERL>
diff --git a/share/static/css/elevator-light/boxes.css b/share/static/css/elevator-light/boxes.css
index c201c7b236..d3e220e22f 100644
--- a/share/static/css/elevator-light/boxes.css
+++ b/share/static/css/elevator-light/boxes.css
@@ -105,6 +105,11 @@ div.results .titlebox .titlebox-content {
     padding: 0;
 }
 
+/* Add some space before the displayed link table */
+.titlebox .linked-queue-portlet .card-body {
+    padding: 15px 15px 15px 15px;
+}
+
 /* Ticket display page colored top borders */
 /* Keep in sync with transaction colors in history.css */
 /* material.io reference: https://material.io/design/color/#tools-for-picking-colors */

commit ffa0b41f972e3b1e1c3b138b94e8c0845462ce0c
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Tue May 12 05:35:37 2020 +0800

    Fix inline edit icons in ticket list when height is not big enough

diff --git a/share/html/Elements/CollectionList b/share/html/Elements/CollectionList
index 5f2fc89662..1960548f6a 100644
--- a/share/html/Elements/CollectionList
+++ b/share/html/Elements/CollectionList
@@ -125,7 +125,7 @@ $Class ||= $Collection->ColumnMapClassName;
 
 $InlineEdit = 0 unless $Collection->isa('RT::Tickets');
 
-$m->out('<div class="table-responsive">');
+$m->out('<div class="table-responsive' . ($InlineEdit ? ' inline-edit' : '') . '">');
 $m->out('<table cellspacing="0"');
 $m->out(' class="table ' .  ($Collection->isa('RT::Tickets') ? 'ticket-list' : 'collection') . ($InlineEdit ? ' inline-edit' : '') . ' collection-as-table"');
 $m->out(' data-display-format="' . $m->interp->apply_escapes($DisplayFormat, 'h') . '"');
diff --git a/share/static/css/elevator-light/inline-edit.css b/share/static/css/elevator-light/inline-edit.css
index 5b80edfa63..5c27c35400 100644
--- a/share/static/css/elevator-light/inline-edit.css
+++ b/share/static/css/elevator-light/inline-edit.css
@@ -101,3 +101,10 @@ td.editable > form.editor .form-row {
 .titlebox .inline-edit-display {
   display: block;
 }
+
+/* Because of .table-responsive's overflow setting, we need to give
+ * inline-edit tooltips enough space to show up, otherwise the edit
+ * icons would flicker and you can't really click it */
+.table-responsive.inline-edit {
+  min-height: 60px;
+}

-----------------------------------------------------------------------


More information about the rt-commit mailing list