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

Jim Brandt jbrandt at bestpractical.com
Fri May 8 16:29:33 EDT 2020


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

- Log -----------------------------------------------------------------
commit d5581ef0ded06754c8b631633efaaaf7cab83799
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 9bed2dbd13..9f84282830 100644
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -2642,6 +2642,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 0c5ffdab9b..7dbe6a2f7f 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 ' ',
     ($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 49f3a45e2bb18e19a544f6fbb2f4349e8fe79807
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 079ccba255806581854e30e2cd5a9df1f072fefa
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 1fafcee49310c0c6f16e9bcefec7776def25e2a2
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Fri May 8 16:22:59 2020 -0400

    Add new options to META for access from web config

diff --git a/lib/RT/Config.pm b/lib/RT/Config.pm
index c09cd117fb..14083ae504 100644
--- a/lib/RT/Config.pm
+++ b/lib/RT/Config.pm
@@ -1796,6 +1796,12 @@ our %META;
     LogToSyslogConf => {
         Immutable     => 1,
     },
+    LinkedQueuePortlets => {
+        Type            => 'HASH',
+    },
+    LinkedQueuePortletsFormats => {
+        Type            => 'HASH',
+    },
 );
 my %OPTIONS = ();
 my @LOADED_CONFIGS = ();

commit 3dfdaea75911128c9cb6dad5de76059410c6ff68
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 1bcbcf81c7..39e49f097f 100644
--- a/share/static/css/elevator-light/boxes.css
+++ b/share/static/css/elevator-light/boxes.css
@@ -100,6 +100,11 @@ div.results .titlebox .titlebox-content {
     padding: 0 15px 15px 15px;
 }
 
+/* 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 */

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


More information about the rt-commit mailing list