[Rt-commit] rt branch, 4.6/article-refactor, created. rt-4.4.4-69-g1e1f27508

? sunnavy sunnavy at bestpractical.com
Thu Apr 18 17:23:11 EDT 2019


The branch, 4.6/article-refactor has been created
        at  1e1f275084abbd5ec5bc6f703b53a393bcd62fda (commit)

- Log -----------------------------------------------------------------
commit 668d7a23f04d0b3e69d6de1d33c909447bb96cbf
Author: craig Kaiser <craig at bestpractical.com>
Date:   Wed Feb 21 14:35:54 2018 -0500

    Add default value for Articles in Queues
    
    Automatically add default article content to tickets on create for queue.

diff --git a/lib/RT/Queue.pm b/lib/RT/Queue.pm
index bd486ae9c..dc286a756 100644
--- a/lib/RT/Queue.pm
+++ b/lib/RT/Queue.pm
@@ -1198,6 +1198,29 @@ sub SetDefaultValue {
         $new_value = $self->loc( '(no value)' );
     }
 
+    if ( $args{Name} eq 'Article' && $args{Value} ) {
+        my $article = RT::Article->new($self->CurrentUser);
+        my ($ret, $msg);
+        if ( $args{Value} =~ /^\d+$/ ) {
+            ($ret, $msg) = $article->Load( $args{Value} );
+        }
+        else {
+            ($ret, $msg) = $article->LoadByCols( Name => $args{Value} );
+        }
+        return ($ret, $msg ) unless $ret;
+
+        $args{Value} = $article->Id;
+        $new_value = $article->Name;
+    }
+
+    if ( $args{Name} eq 'Article' && $old_value =~ /^\d+$/ ) {
+        my $article = RT::Article->new($self->CurrentUser);
+        my ($ret, $msg) = $article->Load( $old_value );
+        if ($ret) {
+            $old_value = $article->Name;
+        }
+    }
+
     return 1 if $new_value eq $old_value;
 
     my ($ret, $msg) = $self->SetAttribute(
diff --git a/share/html/Admin/Queues/DefaultValues.html b/share/html/Admin/Queues/DefaultValues.html
index 201e8c8ab..2b94c3ec7 100644
--- a/share/html/Admin/Queues/DefaultValues.html
+++ b/share/html/Admin/Queues/DefaultValues.html
@@ -71,6 +71,11 @@
         Grouping => 'Basics',
         InTable => 1,
     &>
+
+    <tr><td class="label"><&|/l&>Article</&>:</td>
+        <td><& /Elements/SelectArticle, QueueObj => $queue, Default => $queue->DefaultValue('Article'), Name => 'Article' &>
+    </td></tr>
+
     </table>
     </&>
 </div>
@@ -149,7 +154,7 @@ if ( $ARGS{Reset} ) {
     }
 }
 elsif ( $ARGS{Update} ) {
-    for my $field ( qw/InitialPriority FinalPriority Starts Due/ ) {
+    for my $field ( qw/InitialPriority FinalPriority Starts Due Article/ ) {
         my ($ret, $msg) = $queue->SetDefaultValue(
             Name => $field,
             Value => $ARGS{$field},
diff --git a/share/html/Articles/Elements/IncludeArticle b/share/html/Articles/Elements/IncludeArticle
index ce9714518..b9d41c874 100644
--- a/share/html/Articles/Elements/IncludeArticle
+++ b/share/html/Articles/Elements/IncludeArticle
@@ -48,6 +48,7 @@
 <%INIT>
 
 my $parent_args = $m->caller_args(-1);
+my @articles;
 
 my $name_prefix = '';
 $name_prefix = $ARGS{'Name'} .'-'
@@ -55,18 +56,18 @@ $name_prefix = $ARGS{'Name'} .'-'
     && grep rindex($_, "$ARGS{'Name'}-Articles-", 0) == 0,
         keys %$parent_args;
 
+my $Ticket = $ARGS{Ticket};
+if ( !$Ticket and $parent_args->{id} and $parent_args->{id} ne 'new' ) {
+    $Ticket = RT::Ticket->new($session{'CurrentUser'});
+    $Ticket->Load($parent_args->{id});
+    unless ( $Ticket->id ) {
+        $RT::Logger->error("Couldn't load ticket ". $parent_args->{id} )
+    }
+}
+
 foreach my $arg ( keys %$parent_args ) {
     next if $name_prefix && substr($arg, 0, length($name_prefix)) ne $name_prefix;
 
-    my $Ticket = $ARGS{Ticket};
-    if ( !$Ticket and $parent_args->{id} and $parent_args->{id} ne 'new' ) {
-        $Ticket = RT::Ticket->new($session{'CurrentUser'});
-        $Ticket->Load($parent_args->{id});
-        unless ( $Ticket->id ) {
-            $RT::Logger->error("Couldn't load ticket ". $parent_args->{id} )
-        }
-    }
-
     my $Queue = RT::Queue->new($session{CurrentUser});
     if ($Ticket && $Ticket->Id) {
         $Queue = $Ticket->QueueObj;
@@ -79,7 +80,26 @@ foreach my $arg ( keys %$parent_args ) {
         Queue => $Queue->Id,
     );
     next unless $article && $article->id;
+    push (@articles, $article);
+}
+
+if ( !@articles && ( !$parent_args->{id} || $parent_args->{id} eq 'new' ) && $parent_args->{'Queue'} ) {
+    my $queue_id = $parent_args->{'Queue'};
+    my $QueueObj = RT::Queue->new($session{'CurrentUser'});
+    my ($ret, $msg) = $QueueObj->Load( $queue_id );
+    $RT::Logger->error($msg) unless ($ret);
+
+    if ( $QueueObj->id && $QueueObj->DefaultValue('Article') ) {
+        my $article = RT::Article->new($session{'CurrentUser'});
+        my ($ret, $msg) = $article->Load( $QueueObj->DefaultValue('Article') );
+        $RT::Logger->error($msg) unless ($ret);
+        if ($ret) {
+            push (@articles, $article);
+        }
+    }
+}
 
+foreach my $article (@articles) {
     my $formatted_article = $m->scomp('/Articles/Article/Elements/Preformatted',
         Article => $article, Ticket => $Ticket
     );
diff --git a/share/html/Articles/Elements/IncludeArticle b/share/html/Elements/SelectArticle
similarity index 54%
copy from share/html/Articles/Elements/IncludeArticle
copy to share/html/Elements/SelectArticle
index ce9714518..0354837a8 100644
--- a/share/html/Articles/Elements/IncludeArticle
+++ b/share/html/Elements/SelectArticle
@@ -2,7 +2,7 @@
 %#
 %# COPYRIGHT:
 %#
-%# This software is Copyright (c) 1996-2019 Best Practical Solutions, LLC
+%# This software is Copyright (c) 1996-2018 Best Practical Solutions, LLC
 %#                                          <sales at bestpractical.com>
 %#
 %# (Except where explicitly superseded by other copyright notices)
@@ -45,55 +45,43 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<%INIT>
-
-my $parent_args = $m->caller_args(-1);
-
-my $name_prefix = '';
-$name_prefix = $ARGS{'Name'} .'-'
-    if $ARGS{'Name'}
-    && grep rindex($_, "$ARGS{'Name'}-Articles-", 0) == 0,
-        keys %$parent_args;
 
-foreach my $arg ( keys %$parent_args ) {
-    next if $name_prefix && substr($arg, 0, length($name_prefix)) ne $name_prefix;
+<select name="<% $Name %>">
+<option value="">-</option>
+% while (my $article = $articles->Next) {
+<option <% ( $article->Name eq $Default) ? qq[ selected="selected"] : '' |n %>
+    value="<%$article->Id%>"
+><% $article->Name %></option>
+% }
+</select>
 
-    my $Ticket = $ARGS{Ticket};
-    if ( !$Ticket and $parent_args->{id} and $parent_args->{id} ne 'new' ) {
-        $Ticket = RT::Ticket->new($session{'CurrentUser'});
-        $Ticket->Load($parent_args->{id});
-        unless ( $Ticket->id ) {
-            $RT::Logger->error("Couldn't load ticket ". $parent_args->{id} )
-        }
-    }
-
-    my $Queue = RT::Queue->new($session{CurrentUser});
-    if ($Ticket && $Ticket->Id) {
-        $Queue = $Ticket->QueueObj;
-    }
+<%INIT>
+my $articles = RT::Articles->new( $session{'CurrentUser'} );
+$articles->LimitAppliedClasses( Queue => $QueueObj );
 
-    my $article = RT::Article->new($session{'CurrentUser'});
-    $article->LoadByInclude(
-        Field => substr($arg, length($name_prefix)),
-        Value => $parent_args->{$arg},
-        Queue => $Queue->Id,
-    );
-    next unless $article && $article->id;
+my $dropdown_limit = RT->Config->Get( 'DropdownMenuLimit' ) || 50;
+$m->callback( CallbackName => 'ModifyDropdownLimit', DropdownLimit => \$dropdown_limit );
 
-    my $formatted_article = $m->scomp('/Articles/Article/Elements/Preformatted',
-        Article => $article, Ticket => $Ticket
-    );
+my $autocomplete =  $articles->Count > $dropdown_limit ? 1 : 0;
 
-    $m->callback( Article => $article, Ticket => $Ticket, formatted_article => \$formatted_article, ARGSRef => \%ARGS );
+if ( $Default and $Default =~ /^\d+$/ ){
+    # We got an id, look up the name
+    my $default_article = RT::Article->new($session{'CurrentUser'});
+    my ($ret, $msg) = $default_article->Load( $Default );
 
-    if (RT->Config->Get('MessageBoxRichText',  $session{'CurrentUser'})) {
-        $formatted_article =~ s/>/>/g;
-        $formatted_article =~ s/</</g;
-        $formatted_article =~ s/&/&/g;
-        $formatted_article =~ s/\n/\n<br \/>/g;
+    if ($ret) {
+         $Default = $default_article->Name;
+    }
+    else {
+        RT::Logger->error("Unable to load article $Default: $msg");
     }
-    $m->print($formatted_article);
-
 }
-return;
+
+$Default //= '';
 </%INIT>
+
+<%ARGS>
+$QueueObj
+$Name => 'Article'
+$Default => ''
+</%ARGS>

commit 58e02cdb5f78ee793a7b033353a819d35abe585b
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Sun Jun 24 12:14:00 2018 -0400

    Add autocomplete for articles

diff --git a/share/html/Elements/SelectArticle b/share/html/Elements/SelectArticle
index 0354837a8..b65116f7b 100644
--- a/share/html/Elements/SelectArticle
+++ b/share/html/Elements/SelectArticle
@@ -46,6 +46,9 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 
+% if ( $autocomplete ) {
+<& "SelectArticleAutocomplete", QueueObj => $QueueObj, Default => $Default, Name => $Name &>
+% } else {
 <select name="<% $Name %>">
 <option value="">-</option>
 % while (my $article = $articles->Next) {
@@ -54,6 +57,7 @@
 ><% $article->Name %></option>
 % }
 </select>
+% }
 
 <%INIT>
 my $articles = RT::Articles->new( $session{'CurrentUser'} );
diff --git a/share/html/Elements/SelectArticle b/share/html/Elements/SelectArticleAutocomplete
similarity index 66%
copy from share/html/Elements/SelectArticle
copy to share/html/Elements/SelectArticleAutocomplete
index 0354837a8..e1c36e9cd 100644
--- a/share/html/Elements/SelectArticle
+++ b/share/html/Elements/SelectArticleAutocomplete
@@ -45,43 +45,10 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-
-<select name="<% $Name %>">
-<option value="">-</option>
-% while (my $article = $articles->Next) {
-<option <% ( $article->Name eq $Default) ? qq[ selected="selected"] : '' |n %>
-    value="<%$article->Id%>"
-><% $article->Name %></option>
-% }
-</select>
-
-<%INIT>
-my $articles = RT::Articles->new( $session{'CurrentUser'} );
-$articles->LimitAppliedClasses( Queue => $QueueObj );
-
-my $dropdown_limit = RT->Config->Get( 'DropdownMenuLimit' ) || 50;
-$m->callback( CallbackName => 'ModifyDropdownLimit', DropdownLimit => \$dropdown_limit );
-
-my $autocomplete =  $articles->Count > $dropdown_limit ? 1 : 0;
-
-if ( $Default and $Default =~ /^\d+$/ ){
-    # We got an id, look up the name
-    my $default_article = RT::Article->new($session{'CurrentUser'});
-    my ($ret, $msg) = $default_article->Load( $Default );
-
-    if ($ret) {
-         $Default = $default_article->Name;
-    }
-    else {
-        RT::Logger->error("Unable to load article $Default: $msg");
-    }
-}
-
-$Default //= '';
-</%INIT>
+<input data-autocomplete="Articles" <% $QueueObj && $QueueObj->id ? q{data-autocomplete-queue="} . $QueueObj->id . q{"} : '' |n %> data-autocomplete-return="Name" name="<% $Name %>" value="<% $Default %>">
 
 <%ARGS>
-$QueueObj
-$Name => 'Article'
-$Default => ''
+$QueueObj => undef
+$Default => undef
+$Name => 'IncludeArticleId'
 </%ARGS>
diff --git a/share/html/Elements/SelectArticle b/share/html/Helpers/Autocomplete/Articles
similarity index 63%
copy from share/html/Elements/SelectArticle
copy to share/html/Helpers/Autocomplete/Articles
index 0354837a8..45da288b0 100644
--- a/share/html/Elements/SelectArticle
+++ b/share/html/Helpers/Autocomplete/Articles
@@ -45,43 +45,50 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-
-<select name="<% $Name %>">
-<option value="">-</option>
-% while (my $article = $articles->Next) {
-<option <% ( $article->Name eq $Default) ? qq[ selected="selected"] : '' |n %>
-    value="<%$article->Id%>"
-><% $article->Name %></option>
-% }
-</select>
-
+% $r->content_type('application/json; charset=utf-8');
+<% JSON( \@suggestions ) |n %>
+% $m->abort;
+<%ARGS>
+$term       => undef
+$max        => 10
+$op         => 'STARTSWITH'
+$right      => undef
+$return     => 'Name'
+$queue      => undef
+</%ARGS>
 <%INIT>
-my $articles = RT::Articles->new( $session{'CurrentUser'} );
-$articles->LimitAppliedClasses( Queue => $QueueObj );
+# Only allow certain return fields
+$return = 'Name'
+    unless $return =~ /^(?:id|Name)$/;
 
-my $dropdown_limit = RT->Config->Get( 'DropdownMenuLimit' ) || 50;
-$m->callback( CallbackName => 'ModifyDropdownLimit', DropdownLimit => \$dropdown_limit );
+$m->abort unless defined $return
+             and defined $term
+             and length $term;
 
-my $autocomplete =  $articles->Count > $dropdown_limit ? 1 : 0;
+# Sanity check the operator
+$op = 'STARTSWITH' unless $op =~ /^(?:LIKE|(?:START|END)SWITH|=|!=)$/i;
 
-if ( $Default and $Default =~ /^\d+$/ ){
-    # We got an id, look up the name
-    my $default_article = RT::Article->new($session{'CurrentUser'});
-    my ($ret, $msg) = $default_article->Load( $Default );
+$m->callback( CallbackName => 'ModifyMaxResults', max => \$max );
 
-    if ($ret) {
-         $Default = $default_article->Name;
-    }
-    else {
-        RT::Logger->error("Unable to load article $Default: $msg");
-    }
+my $articles = RT::Articles->new( $session{CurrentUser} );
+if( $queue ) {
+    $articles->LimitAppliedClasses( Queue => $queue );
 }
 
-$Default //= '';
-</%INIT>
+$articles->RowsPerPage( $max );
+$articles->Limit(
+    FIELD           => 'Name',
+    OPERATOR        => $op,
+    VALUE           => $term,
+    ENTRYAGGREGATOR => 'OR',
+    CASESENSITIVE   => 0,
+);
 
-<%ARGS>
-$QueueObj
-$Name => 'Article'
-$Default => ''
-</%ARGS>
+my @suggestions;
+while (my $a = $articles->Next) {
+    next if $right and not $a->CurrentUserHasRight($right);
+    my $value = $a->$return;
+    push @suggestions, { label => $a->Name, value => $value };
+    $m->callback( CallbackName => "ModifySuggestion", suggestions => @suggestions, label => $a );
+}
+</%INIT>
diff --git a/share/static/js/autocomplete.js b/share/static/js/autocomplete.js
index cd8ab2b0d..c4362edb1 100644
--- a/share/static/js/autocomplete.js
+++ b/share/static/js/autocomplete.js
@@ -5,7 +5,8 @@ window.RT.Autocomplete.Classes = {
     Users: 'user',
     Groups: 'group',
     Tickets: 'tickets',
-    Queues: 'queues'
+    Queues: 'queues',
+    Articles: 'articles'
 };
 
 window.RT.Autocomplete.bind = function(from) {
@@ -84,6 +85,9 @@ window.RT.Autocomplete.bind = function(from) {
             };
         }
 
+        var queue = input.attr("data-autocomplete-queue");
+        if (queue) queryargs.push("queue=" + queue);
+
         var checkRight = input.attr("data-autocomplete-checkright");
         if (checkRight) queryargs.push("right=" + checkRight);
 

commit de0dd40a20163dff91631e8068cb9b4be0fa61c2
Author: craig Kaiser <craig at bestpractical.com>
Date:   Wed Feb 21 14:43:41 2018 -0500

    Test default article content on ticket create

diff --git a/t/web/ticket-create-utf8.t b/t/web/ticket-create-utf8.t
index ebb2d5eab..76a7360b7 100644
--- a/t/web/ticket-create-utf8.t
+++ b/t/web/ticket-create-utf8.t
@@ -2,7 +2,7 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 43;
+use RT::Test tests => 49;
 
 my $ru_test = "\x{442}\x{435}\x{441}\x{442}";
 my $ru_support = "\x{43f}\x{43e}\x{434}\x{434}\x{435}\x{440}\x{436}\x{43a}\x{430}";
@@ -86,3 +86,23 @@ foreach my $test_str ( $ru_test, $l1_test ) {
     }
 }
 
+my $article = RT::Article->new($RT::SystemUser);
+my ( $id, $msg ) = $article->Create(
+    Class   => 'General',
+    Name    => 'My Article',
+    'CustomField-Content' => 'My Article Test Content',
+);
+ok( $id, $msg );
+(my $ret, $msg) = $article->Load(1);
+ok ($ret, $msg);
+
+my $queue = RT::Queue->new(RT->SystemUser);
+$queue->Load('General');
+ok( $queue, 'Loaded General Queue' );
+($ret, $msg) = $queue->SetDefaultValue( Name => 'Article', Value => $article->Id);
+ok( $ret, $msg );
+
+ok $m->login(root => 'password'), "logged in";
+$m->goto_create_ticket('General');
+$m->scraped_id_is('Content', '#1: My Article <br />-------------- <br />Content: <br />------- <br />My Article Test Content <br />');
+

commit c2446dc753ce452a45093cab7277a1bf83b4932c
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Fri Jun 22 13:26:20 2018 -0400

    Push default article loading toward create

diff --git a/share/html/Elements/MessageBox b/share/html/Elements/MessageBox
index b798076a6..0da3468cc 100644
--- a/share/html/Elements/MessageBox
+++ b/share/html/Elements/MessageBox
@@ -46,7 +46,7 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <textarea autocomplete="off" class="messagebox <% $Type eq 'text/html' ? 'richtext' : '' %>" <% $width_attr %>="<% $Width %>" rows="<% $Height %>" <% $wrap_type |n %> name="<% $Name %>" id="<% $Name %>" placeholder="<% $Placeholder %>">
-% $m->comp('/Articles/Elements/IncludeArticle', %ARGS) if $IncludeArticle;
+% $m->comp('/Articles/Elements/IncludeArticle', %ARGS, ArticleId => $article_id) if $IncludeArticle;
 % $m->callback( %ARGS, SignatureRef => \$signature, DefaultRef => \$Default, MessageRef => \$message );
 % if (RT->Config->Get("SignatureAboveQuote", $session{'CurrentUser'})) {
 <% $Default || '' %><% $signature %><% $message %></textarea>
@@ -101,6 +101,11 @@ if ( $IncludeSignature and $signature =~ /\S/ ) {
     $signature = '';
 }
 
+my $article_id;
+if ( $IncludeDefaultArticle && defined $QueueObj && $QueueObj->Id ) {
+    $article_id = $QueueObj->DefaultValue('Article') if $QueueObj->DefaultValue('Article');
+}
+
 # wrap="something" seems to really break IE + richtext
 my $wrap_type = $Type eq 'text/html' ? '' : 'wrap="soft"';
 
@@ -125,4 +130,6 @@ $IncludeArticle            => 1;
 $Type                      => RT->Config->Get('MessageBoxRichText',  $session{'CurrentUser'}) ? 'text/html' : 'text/plain';
 $SuppressAttachmentWarning => 0
 $Placeholder               => ''
+$IncludeDefaultArticle            => 0  # Preload a default article based on queue settings
+$QueueObj                  => undef
 </%ARGS>
diff --git a/share/html/Ticket/Create.html b/share/html/Ticket/Create.html
index bbe1ccf0d..f2cb01733 100644
--- a/share/html/Ticket/Create.html
+++ b/share/html/Ticket/Create.html
@@ -241,9 +241,11 @@
 % }
 % $m->callback( %ARGS, QueueObj => $QueueObj, CallbackName => 'BeforeMessageBox' );
 % if (exists $ARGS{Content}) {
-<& /Elements/MessageBox, Default => $ARGS{Content}, IncludeSignature => 0 &>
+<& /Elements/MessageBox, Default => $ARGS{Content}, IncludeSignature => 0, IncludeDefaultArticle => 0 &>
+% } elsif ( $QuoteTransaction ) {
+<& /Elements/MessageBox, QuoteTransaction => $QuoteTransaction, IncludeDefaultArticle => 0 &>
 % } else {
-<& /Elements/MessageBox, QuoteTransaction => $QuoteTransaction &>
+<& /Elements/MessageBox, QueueObj => $QueueObj, IncludeDefaultArticle => 1 &>
 %}
 % $m->callback( %ARGS, QueueObj => $QueueObj, CallbackName => 'AfterMessageBox' );
 

commit f2124f372bbc0bc697509821f0ae28f8ea8b8b21
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Sun Jun 24 12:16:44 2018 -0400

    Refactor ticket create and update to use new SelectArticle
    
    Remove multiple article selection options from the ticket update
    page and replace with a single article selection control. This
    new article selector is a dropdown like the former hotlist,
    but converts to an autocomplete when the number of items in the list
    exceeds the DropdownLimit configuration.
    
    This change removes some extra code that worked to load a ticket
    object in IncludeArticle. The template no longer needs it, but
    it was also passed to a callback. Extensions that use this
    callback may need to make changes to handle receiving an empty
    ticket object.

diff --git a/share/html/Articles/Elements/BeforeMessageBox b/share/html/Articles/Elements/BeforeMessageBox
index b41b01d9d..6ff902eaf 100644
--- a/share/html/Articles/Elements/BeforeMessageBox
+++ b/share/html/Articles/Elements/BeforeMessageBox
@@ -52,43 +52,8 @@
 <table class="articles-select-article">
 % unless (RT->Config->Get('HideArticleSearchOnReplyCreate')) {
 <tr>
-<td><&|/l&>Search for Articles matching</&></td>
-<td><input size=20 name="<% $name_prefix %>Articles_Content" /></td>
-</tr>
-<tr>
 <td><&|/l&>Include Article:</&></td>
-<td><input size=20 name="<% $name_prefix %>Articles-Include-Article-Named" /></td>
-<td><input type="submit" name="Go" value="Go" /></td>
-</tr>
-% }
-% if ($hotlist->Count) {
-<tr>
-<td><&|/l&>Select an Article to include</&></td>
-<td><select name="<% $name_prefix %>Articles-Include-Article-Named-Hotlist" onchange="this.form.submit()">
-<option value="" selected><&|/l&>-</&></option>
-% while (my $article = $hotlist->Next) {
-<option value="<% $article->Id %>"><%$article->Name|| loc('(no name)')%>: <%$article->Summary || ''%></option>
-% }
-</select>
-</td>
-<td><input type="submit" name="Go" value="Go" /></td>
-</tr>
-% }
-% my %dedupe_articles;
-% while (my $article = $articles_content->Next) {
-%   $dedupe_articles{$article->Id}++;
-<tr>
-<td> </td>
-<td><%$article->Name|| loc('(no name)')%>: <%$article->Summary%></td>
-<td><input type="submit" name="<% $name_prefix %>Articles-Include-Article-<%$article->Id%>" value="Go" /></td>
-</tr>
-% }
-% while (my $article = $articles_basics->Next) {
-%   next if $dedupe_articles{$article->Id};
-<tr>
-<td> </td>
-<td><%$article->Name || loc('(no name)')%>: <%$article->Summary || ''%></td>
-<td><input type="submit" name="<% $name_prefix %>Articles-Include-Article-<%$article->Id%>" value="Go" /></td>
+<td><& /Elements/SelectArticle, QueueObj => $QueueObj, AutoSubmit => 1 &></td>
 </tr>
 % }
 % if ( @$topics ) {
@@ -114,7 +79,7 @@
 <&|/l, $included_topic->Name &>Select an Article from [_1]</&>
 </td>
 <td>
-<select name="<% $name_prefix %>Articles-Include-Article" onchange="this.form.submit()">
+<select name="IncludeArticleId" onchange="this.form.submit()">
 <option value="" selected>-</option>
 % while ( my $art = $topic_articles->Next ) {
 <option value="<% $art->id %>"><%$art->Name||loc('(no name)')%>: <%$art->Summary%></option>
diff --git a/share/html/Articles/Elements/IncludeArticle b/share/html/Articles/Elements/IncludeArticle
index b9d41c874..f27663a8b 100644
--- a/share/html/Articles/Elements/IncludeArticle
+++ b/share/html/Articles/Elements/IncludeArticle
@@ -46,62 +46,39 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <%INIT>
+# Nothing to do if we don't get an article id
+$IncludeArticleId //= $DECODED_ARGS->{'IncludeArticleId'};
+return unless $IncludeArticleId;
 
-my $parent_args = $m->caller_args(-1);
-my @articles;
+my $article = RT::Article->new($session{'CurrentUser'});
+my ($ret, $msg) = $article->Load($IncludeArticleId);
 
-my $name_prefix = '';
-$name_prefix = $ARGS{'Name'} .'-'
-    if $ARGS{'Name'}
-    && grep rindex($_, "$ARGS{'Name'}-Articles-", 0) == 0,
-        keys %$parent_args;
+if ( $ret && $article->Id ){
 
-my $Ticket = $ARGS{Ticket};
-if ( !$Ticket and $parent_args->{id} and $parent_args->{id} ne 'new' ) {
-    $Ticket = RT::Ticket->new($session{'CurrentUser'});
-    $Ticket->Load($parent_args->{id});
-    unless ( $Ticket->id ) {
-        $RT::Logger->error("Couldn't load ticket ". $parent_args->{id} )
-    }
-}
-
-foreach my $arg ( keys %$parent_args ) {
-    next if $name_prefix && substr($arg, 0, length($name_prefix)) ne $name_prefix;
+    my $Ticket = $ARGS{Ticket};
+    my $parent_args = $m->caller_args(-1);
 
-    my $Queue = RT::Queue->new($session{CurrentUser});
-    if ($Ticket && $Ticket->Id) {
-        $Queue = $Ticket->QueueObj;
+    if ( !$Ticket and $parent_args->{id} and $parent_args->{id} ne 'new' ) {
+        $Ticket = RT::Ticket->new($session{'CurrentUser'});
+        $Ticket->Load($parent_args->{id});
+        unless ( $Ticket->id ) {
+            $RT::Logger->error("Couldn't load ticket ".  $parent_args->{id} );
+        }
     }
 
-    my $article = RT::Article->new($session{'CurrentUser'});
-    $article->LoadByInclude(
-        Field => substr($arg, length($name_prefix)),
-        Value => $parent_args->{$arg},
-        Queue => $Queue->Id,
-    );
-    next unless $article && $article->id;
-    push (@articles, $article);
-}
-
-if ( !@articles && ( !$parent_args->{id} || $parent_args->{id} eq 'new' ) && $parent_args->{'Queue'} ) {
-    my $queue_id = $parent_args->{'Queue'};
-    my $QueueObj = RT::Queue->new($session{'CurrentUser'});
-    my ($ret, $msg) = $QueueObj->Load( $queue_id );
-    $RT::Logger->error($msg) unless ($ret);
-
-    if ( $QueueObj->id && $QueueObj->DefaultValue('Article') ) {
-        my $article = RT::Article->new($session{'CurrentUser'});
-        my ($ret, $msg) = $article->Load( $QueueObj->DefaultValue('Article') );
-        $RT::Logger->error($msg) unless ($ret);
-        if ($ret) {
-            push (@articles, $article);
-        }
+    my $queue_id;
+    $queue_id = $QueueObj->id if $QueueObj && $QueueObj->id;
+    $queue_id ||= $Ticket->Queue if $Ticket && $Ticket->Queue;
+    if (   $queue_id
+        && !$article->ClassObj->IsApplied(0)
+        && !$article->ClassObj->IsApplied($queue_id) )
+    {
+        RT->Logger->warning( "The Class of the Article #$IncludeArticleId is not applied to the Queue #$queue_id" );
+        return;
     }
-}
 
-foreach my $article (@articles) {
     my $formatted_article = $m->scomp('/Articles/Article/Elements/Preformatted',
-        Article => $article, Ticket => $Ticket
+        Article => $article
     );
 
     $m->callback( Article => $article, Ticket => $Ticket, formatted_article => \$formatted_article, ARGSRef => \%ARGS );
@@ -113,7 +90,12 @@ foreach my $article (@articles) {
         $formatted_article =~ s/\n/\n<br \/>/g;
     }
     $m->print($formatted_article);
-
 }
-return;
+else {
+    RT::Logger->error("Unable to load article $IncludeArticleId: $msg");
+}
 </%INIT>
+<%ARGS>
+$IncludeArticleId => undef
+$QueueObj => undef
+</%ARGS>
diff --git a/share/html/Elements/MessageBox b/share/html/Elements/MessageBox
index 0da3468cc..42c3e26e1 100644
--- a/share/html/Elements/MessageBox
+++ b/share/html/Elements/MessageBox
@@ -46,7 +46,7 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <textarea autocomplete="off" class="messagebox <% $Type eq 'text/html' ? 'richtext' : '' %>" <% $width_attr %>="<% $Width %>" rows="<% $Height %>" <% $wrap_type |n %> name="<% $Name %>" id="<% $Name %>" placeholder="<% $Placeholder %>">
-% $m->comp('/Articles/Elements/IncludeArticle', %ARGS, ArticleId => $article_id) if $IncludeArticle;
+% $m->comp('/Articles/Elements/IncludeArticle', %ARGS, IncludeArticleId => $article_id, QueueObj => $QueueObj) if $IncludeArticle;
 % $m->callback( %ARGS, SignatureRef => \$signature, DefaultRef => \$Default, MessageRef => \$message );
 % if (RT->Config->Get("SignatureAboveQuote", $session{'CurrentUser'})) {
 <% $Default || '' %><% $signature %><% $message %></textarea>
@@ -103,8 +103,13 @@ if ( $IncludeSignature and $signature =~ /\S/ ) {
 
 my $article_id;
 if ( $IncludeDefaultArticle && defined $QueueObj && $QueueObj->Id ) {
+    # Load a default article
     $article_id = $QueueObj->DefaultValue('Article') if $QueueObj->DefaultValue('Article');
 }
+else {
+    # Load from the page, if provided
+    $article_id = $ARGS{'IncludeArticleId'} if $ARGS{'IncludeArticleId'};
+}
 
 # wrap="something" seems to really break IE + richtext
 my $wrap_type = $Type eq 'text/html' ? '' : 'wrap="soft"';
@@ -130,6 +135,6 @@ $IncludeArticle            => 1;
 $Type                      => RT->Config->Get('MessageBoxRichText',  $session{'CurrentUser'}) ? 'text/html' : 'text/plain';
 $SuppressAttachmentWarning => 0
 $Placeholder               => ''
-$IncludeDefaultArticle            => 0  # Preload a default article based on queue settings
+$IncludeDefaultArticle     => 0  # Preload a default article based on queue settings
 $QueueObj                  => undef
 </%ARGS>
diff --git a/share/html/Elements/SelectArticle b/share/html/Elements/SelectArticle
index b65116f7b..c143ddc1b 100644
--- a/share/html/Elements/SelectArticle
+++ b/share/html/Elements/SelectArticle
@@ -49,12 +49,13 @@
 % if ( $autocomplete ) {
 <& "SelectArticleAutocomplete", QueueObj => $QueueObj, Default => $Default, Name => $Name &>
 % } else {
-<select name="<% $Name %>">
+<select name="<% $Name %>" <% $AutoSubmit ? 'onchange="this.form.submit()"' : '' |n%>>
 <option value="">-</option>
 % while (my $article = $articles->Next) {
 <option <% ( $article->Name eq $Default) ? qq[ selected="selected"] : '' |n %>
-    value="<%$article->Id%>"
-><% $article->Name %></option>
+    value="<%$article->Id%>">
+<%$article->Name || loc('(no name)')%><% $IncludeSummary ? ': ' . $article->Summary || '' : '' %>
+</option>
 % }
 </select>
 % }
@@ -86,6 +87,8 @@ $Default //= '';
 
 <%ARGS>
 $QueueObj
-$Name => 'Article'
-$Default => ''
+$Name           => 'IncludeArticleId'
+$Default        => ''
+$AutoSubmit     => 0
+$IncludeSummary => 1
 </%ARGS>
diff --git a/share/html/Elements/SelectArticleAutocomplete b/share/html/Elements/SelectArticleAutocomplete
index e1c36e9cd..7ecd11348 100644
--- a/share/html/Elements/SelectArticleAutocomplete
+++ b/share/html/Elements/SelectArticleAutocomplete
@@ -45,10 +45,12 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<input data-autocomplete="Articles" <% $QueueObj && $QueueObj->id ? q{data-autocomplete-queue="} . $QueueObj->id . q{"} : '' |n %> data-autocomplete-return="Name" name="<% $Name %>" value="<% $Default %>">
+<input data-autocomplete="Articles" <% $QueueObj && $QueueObj->id ? q{data-autocomplete-queue="} . $QueueObj->id . q{"} : '' |n %> data-autocomplete-return="id" name="<% $Name %>" value="<% $Default %>"
+<% $AutoSubmit ? 'data-autocomplete-autosubmit=1' : '' %>>
 
 <%ARGS>
 $QueueObj => undef
 $Default => undef
 $Name => 'IncludeArticleId'
+$AutoSubmit => 1
 </%ARGS>
diff --git a/share/html/Ticket/Create.html b/share/html/Ticket/Create.html
index f2cb01733..025032046 100644
--- a/share/html/Ticket/Create.html
+++ b/share/html/Ticket/Create.html
@@ -241,9 +241,9 @@
 % }
 % $m->callback( %ARGS, QueueObj => $QueueObj, CallbackName => 'BeforeMessageBox' );
 % if (exists $ARGS{Content}) {
-<& /Elements/MessageBox, Default => $ARGS{Content}, IncludeSignature => 0, IncludeDefaultArticle => 0 &>
+<& /Elements/MessageBox, QueueObj => $QueueObj, Default => $ARGS{Content}, IncludeSignature => 0, IncludeDefaultArticle => 0 &>
 % } elsif ( $QuoteTransaction ) {
-<& /Elements/MessageBox, QuoteTransaction => $QuoteTransaction, IncludeDefaultArticle => 0 &>
+<& /Elements/MessageBox, QueueObj => $QueueObj, QuoteTransaction => $QuoteTransaction, IncludeDefaultArticle => 0 &>
 % } else {
 <& /Elements/MessageBox, QueueObj => $QueueObj, IncludeDefaultArticle => 1 &>
 %}
diff --git a/t/articles/queue-specific-class.t b/t/articles/queue-specific-class.t
index 5cd042910..1ae8205c4 100644
--- a/t/articles/queue-specific-class.t
+++ b/t/articles/queue-specific-class.t
@@ -2,9 +2,10 @@
 use strict;
 use warnings;
 
-use RT::Test tests => 56;
+use RT::Test tests => undef;
 
 my ( $url, $m ) = RT::Test->started_ok;
+diag "Running server at: $url";
 $m->login;
 
 my %class = map { $_ => '' } qw/foo bar/;
@@ -73,36 +74,8 @@ diag "update ticket to see if there is article foo"
 {
     $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
         'ticket update page' );
-    $m->content_contains( 'article foo:', 'got article foo in hotlist' );
-    $m->content_lacks( 'article bar:', 'no article bar in hotlist' );
-
-    $m->submit_form(
-        form_number => 3,
-        fields      => { 'Articles_Content' => 'article' },
-        button      => 'Go',
-    );
-    $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
-    $m->content_lacks( 'article bar', 'no article bar' );
-
-    $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
-        'ticket update page' );
-    $m->submit_form(
-        form_number => 3,
-        fields      => { 'Articles-Include-Article-Named' => 'article foo' },
-        button      => 'Go',
-    );
-    $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
-    $m->content_lacks( 'article bar', 'no article bar' );
-
-    $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
-        'ticket update page' );
-    $m->submit_form(
-        form_number => 3,
-        fields      => { 'Articles-Include-Article-Named' => 'articlei bar' },
-        button      => 'Go',
-    );
-    $m->content_unlike( qr/article foo.*article foo/s, 'no article foo' );
-    $m->content_lacks( 'article bar', 'no article bar' );
+    $m->content_contains( 'article foo:', 'got article foo in dropdown' );
+    $m->content_lacks( 'article bar:', 'no article bar in dropdown' );
 }
 
 diag "apply bar to globally" if $ENV{TEST_VERBOSE};
@@ -123,36 +96,14 @@ diag "update ticket to see if there are both article foo and bar"
 {
     $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
         'ticket update page' );
-    $m->content_contains( 'article foo:', 'got article foo in hotlist' );
-    $m->content_contains( 'article bar:', 'got article bar in hotlist' );
-
-    $m->submit_form(
-        form_number => 3,
-        fields      => { 'Articles_Content' => 'article' },
-        button      => 'Go',
-    );
-    $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
-    $m->content_like( qr/article bar.*article bar/s, 'selected article bar' );
+    $m->content_contains( 'article foo:', 'got article foo in dropdown' );
+    $m->content_contains( 'article bar:', 'got article bar in dropdown' );
 
-    $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
-        'ticket update page' );
     $m->submit_form(
         form_number => 3,
-        fields      => { 'Articles-Include-Article-Named' => 'article foo' },
-        button      => 'Go',
+        fields      => { 'IncludeArticleId' => '1' },
     );
     $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
-    $m->content_unlike( qr/article bar.*article bar/s, 'no article bar' );
-
-    $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket_id,
-        'ticket update page' );
-    $m->submit_form(
-        form_number => 3,
-        fields      => { 'Articles-Include-Article-Named' => 'article bar' },
-        button      => 'Go',
-    );
-    $m->content_like( qr/article bar.*article bar/s, 'selected article bar' );
-    $m->content_unlike( qr/article foo.*article foo/s, 'no article foo' );
 }
 
 
@@ -174,7 +125,7 @@ diag "remove both foo and bar" if $ENV{TEST_VERBOSE};
         fields      => { 'RemoveClass-' . $class{bar} => 0 },
         button      => 'UpdateObjs',
     );
-    $m->content_contains( 'Object deleted', 'remoked bar' );
+    $m->content_contains( 'Object deleted', 'removed bar' );
 }
 
 diag "update ticket to see if there are both article foo and bar"
@@ -189,7 +140,6 @@ diag "update ticket to see if there are both article foo and bar"
     $m->submit_form(
         form_number => 3,
         fields      => { 'Articles_Content' => 'article' },
-        button      => 'Go',
     );
     $m->content_lacks( 'article foo', 'no article foo' );
     $m->content_lacks( 'article bar', 'no article bar' );
@@ -199,7 +149,6 @@ diag "update ticket to see if there are both article foo and bar"
     $m->submit_form(
         form_number => 3,
         fields      => { 'Articles-Include-Article-Named' => 'article foo' },
-        button      => 'Go',
     );
     $m->content_lacks( 'article foo', 'no article foo' );
     $m->content_lacks( 'article bar', 'no article bar' );
@@ -209,9 +158,9 @@ diag "update ticket to see if there are both article foo and bar"
     $m->submit_form(
         form_number => 3,
         fields      => { 'Articles-Include-Article-Named' => 'article bar' },
-        button      => 'Go',
     );
     $m->content_lacks( 'article foo', 'no article foo' );
     $m->content_lacks( 'article bar', 'no article bar' );
 }
 
+done_testing();
diff --git a/t/articles/set-subject.t b/t/articles/set-subject.t
index 5ba1af845..04124da31 100644
--- a/t/articles/set-subject.t
+++ b/t/articles/set-subject.t
@@ -85,7 +85,6 @@ is($m->form_number(3)->find_input('UpdateSubject')->value,$ticket->Subject,'Tick
 $m->submit_form(
     form_number => 3,
     fields      => { 'Articles-Include-Article-Named' => $article->Id },
-    button      => 'Go',
 );
 is($m->form_number(3)->find_input('UpdateSubject')->value,$ticket->Subject,'Ticket Subject Not Clobbered');
 
@@ -103,7 +102,6 @@ is($m->form_number(3)->find_input('UpdateSubject')->value,$ticket->Subject,'Tick
 $m->submit_form(
     form_number => 3,
     fields      => { 'Articles-Include-Article-Named' => $article->Name },
-    button      => 'Go',
 );
 is($m->form_number(3)->find_input('UpdateSubject')->value,$article->FirstCustomFieldValue("Subject-$$"),'Ticket Subject Clobbered');
 

commit 72c3f3bbbe11ac8dd9af0271d4f74509ef85fc78
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Sun Jun 24 13:13:10 2018 -0400

    Add articles notes to upgrading docs

diff --git a/devel/docs/UPGRADING-4.6 b/devel/docs/UPGRADING-4.6
new file mode 100644
index 000000000..747e45e3d
--- /dev/null
+++ b/devel/docs/UPGRADING-4.6
@@ -0,0 +1,17 @@
+=head1 UPGRADING FROM RT 4.4.0 and greater
+
+This documentation notes internals changes between the 4.4 and 4.6
+series that are primarily of interest to developers writing extensions
+or local customizations.  It is not an exhaustive list.
+
+=over
+
+=item *
+
+The default callback in C<Articles/Elements/IncludeArticle> provides a ticket
+object. However, the template itself does not need this ticket object, so it
+is no longer guaranteed to be loaded when it is passed.
+
+=back
+
+=cut
diff --git a/docs/UPGRADING-4.6 b/docs/UPGRADING-4.6
index 6755ffa17..54a97f9fc 100644
--- a/docs/UPGRADING-4.6
+++ b/docs/UPGRADING-4.6
@@ -18,6 +18,12 @@ The variables which alter the set of HTML elements allowed in HTML
 scrubbing have moved; they have been renamed, and are now found under
 L<RT::Interface::Web::Scrubber>.
 
+=item *
+
+The articles interface on tickets has been simplified, now showing only
+a dropdown for selecting articles. This dropdown converts to an autocomplete
+box when the dropdown contains more than C<$DropdownMenuLimit> items.
+
 =back
 
 =cut

commit 529176dc9db1bb135915d783f7e070a5aca0326a
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Sun Jun 24 15:42:01 2018 -0400

    Remove article loading now handled in SelectArticle

diff --git a/share/html/Articles/Elements/BeforeMessageBox b/share/html/Articles/Elements/BeforeMessageBox
index 6ff902eaf..34692beba 100644
--- a/share/html/Articles/Elements/BeforeMessageBox
+++ b/share/html/Articles/Elements/BeforeMessageBox
@@ -112,11 +112,6 @@ if ( $ARGS{'MessageBoxName'} ) {
     $name_prefix = $ARGS{'MessageBoxName'} .'-';
 }
 
-# convert Articles-Include-Article => $id to Articles-Include-Article-$id
-if ( my $tmp = $ARGS{$name_prefix ."Articles-Include-Article"} ) {
-    $ARGS{$name_prefix ."Articles-Include-Article-$tmp"}++;
-}
-
 my %uri;
 if ( $ARGS{id} && $ARGS{id} ne 'new' ) {
     $uri{$_}++ for split ' ', ($ARGS{$ARGS{'id'}.'-RefersTo'} || '');
@@ -135,34 +130,6 @@ if ( $ARGS{id} && $ARGS{id} ne 'new' ) {
     }
 }
 
-use RT::Articles;
-
-my $articles_content =
-  RT::Articles->new( $session{'CurrentUser'} );
-my $articles_basics = RT::Articles->new( $session{'CurrentUser'} );
-if ( my $tmp = $ARGS{ $name_prefix ."Articles_Content" } ) {
-    $articles_content->LimitCustomField(
-        VALUE => $tmp, OPERATOR => 'LIKE'
-    );
-    $articles_content->LimitAppliedClasses( Queue => $QueueObj );
-
-    $articles_basics->Limit( SUBCLAUSE       => 'all',
-                             FIELD           => 'Name',
-                             OPERATOR        => 'LIKE',
-                             VALUE           => $tmp,
-                             ENTRYAGGREGATOR => "OR" );
-    $articles_basics->Limit( SUBCLAUSE       => 'all',
-                             FIELD           => 'Summary',
-                             OPERATOR        => 'LIKE',
-                             VALUE           => $tmp,
-                             ENTRYAGGREGATOR => "OR" );
-    $articles_basics->LimitAppliedClasses( Queue => $QueueObj );
-}
-
-my $hotlist = RT::Articles->new( $session{'CurrentUser'} );
-$hotlist->LimitHotlistClasses;
-$hotlist->LimitAppliedClasses( Queue => $QueueObj );
-
 my ( $topic_articles, $topics, $included_topic );
 $topic_articles = RT::Articles->new( $session{CurrentUser} );
 $topics = [];

commit 0bf47b163d6fe7d095f86a5195f9a3af8fdfed53
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Sun Jun 24 15:45:37 2018 -0400

    Update article to ticket linking with new args

diff --git a/share/html/Articles/Elements/BeforeMessageBox b/share/html/Articles/Elements/BeforeMessageBox
index 34692beba..23d3547e5 100644
--- a/share/html/Articles/Elements/BeforeMessageBox
+++ b/share/html/Articles/Elements/BeforeMessageBox
@@ -116,15 +116,11 @@ my %uri;
 if ( $ARGS{id} && $ARGS{id} ne 'new' ) {
     $uri{$_}++ for split ' ', ($ARGS{$ARGS{'id'}.'-RefersTo'} || '');
 
-    foreach my $arg (keys %ARGS) {
-        next if $name_prefix && substr($arg, 0, length($name_prefix)) ne $name_prefix;
-
-        my $article = RT::Article->new($session{'CurrentUser'});
-        $article->LoadByInclude(
-            Field => substr($arg, length($name_prefix)),
-            Value => $ARGS{$arg},
-        );
-        if ($article->Id) {
+    my $article = RT::Article->new($session{'CurrentUser'});
+    my ($ret, $msg) = $article->Load($ARGS{'IncludeArticleId'});
+
+    if ($ret && $article->Id) {
+        unless ( $QueueObj && !$article->ClassObj->IsApplied(0) && !$article->ClassObj->IsApplied( $QueueObj->id ) ) {
             $uri{$article->URI}++;
         }
     }

commit e673409fece6ac11b496fab164ea1fdac2300b73
Author: Jim Brandt <jbrandt at bestpractical.com>
Date:   Sun Jun 24 15:31:31 2018 -0400

    Update tests for new articles configuration

diff --git a/t/articles/queue-specific-class.t b/t/articles/queue-specific-class.t
index 1ae8205c4..770e73711 100644
--- a/t/articles/queue-specific-class.t
+++ b/t/articles/queue-specific-class.t
@@ -36,7 +36,9 @@ for my $name ( keys %class ) {
 
     $m->submit_form(
         form_number => 2,
-        fields      => { Name => "article $name" }
+        fields      => { Name => "article $name",
+                         'Summary' => "$name summary",
+                         'Object-RT::Article--CustomField-1-Values' => "$name content"}
     );
 
     $m->content_like( qr/Article \d+ created/, "created article $name" );
@@ -103,7 +105,7 @@ diag "update ticket to see if there are both article foo and bar"
         form_number => 3,
         fields      => { 'IncludeArticleId' => '1' },
     );
-    $m->content_like( qr/article foo.*article foo/s, 'selected article foo' );
+    $m->content_like( qr/foo summary/s, 'article included' );
 }
 
 
diff --git a/t/articles/set-subject.t b/t/articles/set-subject.t
index 04124da31..6eff89d1d 100644
--- a/t/articles/set-subject.t
+++ b/t/articles/set-subject.t
@@ -101,7 +101,7 @@ $m->get_ok( '/Ticket/Update.html?Action=Comment&id=' . $ticket->id,
 is($m->form_number(3)->find_input('UpdateSubject')->value,$ticket->Subject,'Ticket Subject Found');
 $m->submit_form(
     form_number => 3,
-    fields      => { 'Articles-Include-Article-Named' => $article->Name },
+    fields      => { 'IncludeArticleId' => $article->id },
 );
 is($m->form_number(3)->find_input('UpdateSubject')->value,$article->FirstCustomFieldValue("Subject-$$"),'Ticket Subject Clobbered');
 
diff --git a/t/web/articles-links.t b/t/web/articles-links.t
index 4aa8f9133..018f71c0b 100644
--- a/t/web/articles-links.t
+++ b/t/web/articles-links.t
@@ -29,7 +29,7 @@ $m->goto_ticket($ticket->id);
 $m->follow_link_ok({text => 'Reply'});
 
 $m->form_name('TicketUpdate');
-$m->field('Articles-Include-Article-Named' => $article->Name);
+$m->field('IncludeArticleId' => $article->Id);
 $m->submit;
 
 $m->content_contains('instance of ticket #17421', 'got the name of the article in the ticket');

commit b583b1aa18ca0b42765c201d71c3717e35b7b936
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Tue Nov 6 10:47:59 2018 +0800

    Drop HotList column for Classes
    
    With the new SelectArticle UI, all the articles applied will show up.

diff --git a/etc/initialdata b/etc/initialdata
index e65066185..74951a5b8 100644
--- a/etc/initialdata
+++ b/etc/initialdata
@@ -929,7 +929,6 @@ Hour:         { $SubscriptionObj->SubValue('Hour') }
     {
         Name              => 'General',
         Description       => 'The default class',
-        HotList           => 1,
     },
 );
 
diff --git a/etc/schema.Oracle b/etc/schema.Oracle
index b3e677b82..102f134dd 100644
--- a/etc/schema.Oracle
+++ b/etc/schema.Oracle
@@ -422,8 +422,7 @@ Disabled NUMBER(11,0) DEFAULT 0 NOT NULL,
 Creator NUMBER(11,0) DEFAULT 0 NOT NULL,
 Created DATE,
 LastUpdatedBy NUMBER(11,0) DEFAULT 0 NOT NULL,
-LastUpdated DATE,
-HotList NUMBER(11,0) DEFAULT 0 NOT NULL
+LastUpdated DATE
 );
 
 CREATE SEQUENCE Articles_seq;
diff --git a/etc/schema.Pg b/etc/schema.Pg
index aa4b437e0..3836c2667 100644
--- a/etc/schema.Pg
+++ b/etc/schema.Pg
@@ -656,7 +656,6 @@ Creator integer NOT NULL DEFAULT 0,
 Created TIMESTAMP NULL,
 LastUpdatedBy integer NOT NULL DEFAULT 0,
 LastUpdated TIMESTAMP NULL,
-HotList smallint NOT NULL DEFAULT 0,
 PRIMARY KEY (id)
 );
 
diff --git a/etc/schema.SQLite b/etc/schema.SQLite
index f8e6ae932..b6d286727 100644
--- a/etc/schema.SQLite
+++ b/etc/schema.SQLite
@@ -463,8 +463,7 @@ Disabled smallint NOT NULL DEFAULT 0,
 Creator integer NOT NULL DEFAULT 0,
 Created TIMESTAMP NULL,
 LastUpdatedBy integer NOT NULL DEFAULT 0,
-LastUpdated TIMESTAMP NULL,
-HotList smallint NOT NULL DEFAULT 0
+LastUpdated TIMESTAMP NULL
 );
 
 CREATE TABLE Articles (
diff --git a/etc/schema.mysql b/etc/schema.mysql
index eefc145ca..cb87d86a3 100644
--- a/etc/schema.mysql
+++ b/etc/schema.mysql
@@ -448,7 +448,6 @@ CREATE TABLE Classes (
   Created datetime default NULL,
   LastUpdatedBy int(11) NOT NULL default '0',
   LastUpdated datetime default NULL,
-  HotList int(2) NOT NULL default '0',
   PRIMARY KEY  (id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
diff --git a/etc/upgrade/4.5.0/schema.Oracle b/etc/upgrade/4.5.0/schema.Oracle
new file mode 100644
index 000000000..b18ad9c97
--- /dev/null
+++ b/etc/upgrade/4.5.0/schema.Oracle
@@ -0,0 +1 @@
+ALTER TABLE Classes DROP( HotList );
diff --git a/etc/upgrade/4.5.0/schema.Pg b/etc/upgrade/4.5.0/schema.Pg
new file mode 100644
index 000000000..3dae347fa
--- /dev/null
+++ b/etc/upgrade/4.5.0/schema.Pg
@@ -0,0 +1 @@
+ALTER TABLE Scrips DROP COLUMN HotList;
diff --git a/etc/upgrade/4.5.0/schema.mysql b/etc/upgrade/4.5.0/schema.mysql
new file mode 100644
index 000000000..3dae347fa
--- /dev/null
+++ b/etc/upgrade/4.5.0/schema.mysql
@@ -0,0 +1 @@
+ALTER TABLE Scrips DROP COLUMN HotList;
diff --git a/lib/RT/Articles.pm b/lib/RT/Articles.pm
index 1c1b0fa6a..d2dc97418 100644
--- a/lib/RT/Articles.pm
+++ b/lib/RT/Articles.pm
@@ -479,24 +479,6 @@ sub LimitReferredToBy {
 
 # }}}
 
-=head2 LimitHostlistClasses
-
-Only fetch Articles from classes where Hotlist is true.
-
-=cut
-
-sub LimitHotlistClasses {
-    my $self = shift;
-
-    my $classes = $self->Join(
-        ALIAS1 => 'main',
-        FIELD1 => 'Class',
-        TABLE2 => 'Classes',
-        FIELD2 => 'id',
-    );
-    $self->Limit( ALIAS => $classes, FIELD => 'HotList', VALUE => 1 );
-}
-
 =head2 LimitAppliedClasses Queue => QueueObj
 
 Takes a Queue and limits articles returned to classes which are applied to that Queue
diff --git a/lib/RT/Class.pm b/lib/RT/Class.pm
index 443dd0cc8..8e9b8bf0f 100644
--- a/lib/RT/Class.pm
+++ b/lib/RT/Class.pm
@@ -117,7 +117,6 @@ sub Create {
         Name        => '',
         Description => '',
         SortOrder   => '0',
-        HotList     => 0,
         @_
     );
 
@@ -135,7 +134,6 @@ sub Create {
         Name        => $args{'Name'},
         Description => $args{'Description'},
         SortOrder   => $args{'SortOrder'},
-        HotList     => $args{'HotList'},
     );
 
 }
@@ -474,24 +472,6 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
 =cut
 
 
-=head2 HotList
-
-Returns the current value of HotList. 
-(In the database, HotList is stored as int(2).)
-
-
-
-=head2 SetHotList VALUE
-
-
-Set HotList to VALUE. 
-Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
-(In the database, HotList will be stored as a int(2).)
-
-
-=cut
-
-
 =head2 Creator
 
 Returns the current value of Creator. 
@@ -542,8 +522,6 @@ sub _CoreAccessible {
                 {read => 1, write => 1, type => 'int(11)', default => '0'},
         Disabled => 
                 {read => 1, write => 1, type => 'int(2)', default => '0'},
-        HotList => 
-                {read => 1, write => 1, type => 'int(2)', default => '0'},
         Creator => 
                 {read => 1, auto => 1, type => 'int(11)', default => '0'},
         Created => 
diff --git a/share/html/Admin/Articles/Classes/Modify.html b/share/html/Admin/Articles/Classes/Modify.html
index 43857a705..67c1811d4 100644
--- a/share/html/Admin/Articles/Classes/Modify.html
+++ b/share/html/Admin/Articles/Classes/Modify.html
@@ -73,13 +73,6 @@
     <label for="Enabled"><&|/l&>Enabled (Unchecking this box disables this class)</&></label>
 </td>
 </tr>
-<tr>
-<td> </td>
-<td>
-    <input type="checkbox" id="HotList" name="HotList" value="1" <%$HotListChecked%>>
-    <label for="HotList"><&|/l&>All Articles in this class should be listed in a dropdown of the ticket reply page</&></label>
-</td>
-</tr>
 </table>
 
 <h3><&|/l&>When inserting articles in this class into emails:</&></h3>
@@ -176,8 +169,7 @@ if ($ClassObj->Id()) {
         );
     }
 
-    $ARGS{HotList} ||= 0 if $Submitted;
-    my @attribs= qw(Description Name HotList SubjectOverride);
+    my @attribs= qw(Description Name SubjectOverride);
     $m->callback( CallbackName => 'AttributeList', Attributes => \@attribs, ARGSRef => \%ARGS );
     push @results, UpdateRecordObject( AttributesRef => \@attribs,
                                        Object => $ClassObj,
@@ -234,7 +226,6 @@ if ( $ClassObj->id ) {
 $include{$_} = $include{$_} ? " CHECKED" : "" for keys %include;
 
 my $EnabledChecked = ($Create ? $Disabled : $ClassObj->Disabled()) ? "" : "CHECKED";
-my $HotListChecked = $ClassObj->id && $ClassObj->HotList ? "CHECKED" : "";
 </%INIT>
 
 
diff --git a/t/articles/queue-specific-class.t b/t/articles/queue-specific-class.t
index 770e73711..83570e0a8 100644
--- a/t/articles/queue-specific-class.t
+++ b/t/articles/queue-specific-class.t
@@ -18,7 +18,7 @@ for my $name ( keys %class ) {
 
     $m->submit_form(
         form_number => 3,
-        fields      => { Name => $name, HotList => 1 },
+        fields      => { Name => $name },
     );
 
     $m->content_contains( "Modify the Class $name",

commit c00dddbc410293868356d02f90c0ef5719f9df29
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Apr 19 02:58:25 2019 +0800

    Update SubjectOverride for new SelectArticle UI

diff --git a/share/html/Articles/Elements/SubjectOverride b/share/html/Articles/Elements/SubjectOverride
index 5c925fe03..ec966bf81 100644
--- a/share/html/Articles/Elements/SubjectOverride
+++ b/share/html/Articles/Elements/SubjectOverride
@@ -46,7 +46,7 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <%INIT>
-foreach my $arg ( keys %$ARGSRef) {
+if ( my $id = $ARGSRef->{IncludeArticleId} ) {
 
     my $Queue = $QueueObj || RT::Queue->new($session{CurrentUser});
     if (!$Queue->Id && $Ticket && $Ticket->Id) {
@@ -54,22 +54,19 @@ foreach my $arg ( keys %$ARGSRef) {
     }
 
     my $article = RT::Article->new($session{'CurrentUser'});
-    $article->LoadByInclude(
-        Field => $arg,
-        Value => $ARGSRef->{$arg},
-        Queue => $Queue->Id,
-    );
-    next unless $article && $article->id;
+    $article->Load($id);
+    return unless $article->id;
 
     my $class = $article->ClassObj;
+    return unless $class->IsApplied(0) || $class->IsApplied($Queue->id);
 
-    next unless $class->SubjectOverride;
+    return unless $class->SubjectOverride;
 
     my $cfs = $class->ArticleCustomFields;
     $cfs->Limit( FIELD => 'id', VALUE => $class->SubjectOverride );
 
     my $subjectCF = $cfs->First;
-    next unless $subjectCF;
+    return unless $subjectCF;
 
     my $subject = $article->CustomFieldValuesAsString($subjectCF->Id);
 
@@ -81,7 +78,6 @@ foreach my $arg ( keys %$ARGSRef) {
         $ARGSRef->{Subject} = $subject;
     }
 }
-return;
 </%INIT>
 <%ARGS>
 $Ticket => undef

commit 02fb0b1e3639ccb4a58824a5e286857aa994989c
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Apr 19 04:58:09 2019 +0800

    Update CheckSkipCreate for new SelectArticle UI

diff --git a/share/html/Articles/Elements/CheckSkipCreate b/share/html/Articles/Elements/CheckSkipCreate
index 41cb8588c..ce960db78 100644
--- a/share/html/Articles/Elements/CheckSkipCreate
+++ b/share/html/Articles/Elements/CheckSkipCreate
@@ -51,17 +51,10 @@ return if $checks_failure; # we're already skipping Create
 return unless RT->Config->Get('ArticleOnTicketCreate');
 
 
-my $article = RT::Article->new($session{'CurrentUser'});
-foreach my $arg ( keys %$ARGSRef) {
-
-    if ( $ARGSRef->{Articles_Content} ||              # search for an article
-         $ARGSRef->{'Articles-Include-Topic'} ||      # using Queue Topics
-         ( $article->LoadByInclude( Field => $arg, Value => $ARGSRef->{$arg} ) &&
-           $article->id ) ) {                     # including an article
-
-        $$skip_create = 1;
-        last;
-    }
+if ( $ARGSRef->{IncludeArticleId} ) {
+    my $article = RT::Article->new($session{'CurrentUser'});
+    $article->Load($ARGSRef->{IncludeArticleId});
+    $$skip_create = 1 if $article->id;
 }
 return;
 

commit 1e1f275084abbd5ec5bc6f703b53a393bcd62fda
Author: sunnavy <sunnavy at bestpractical.com>
Date:   Fri Apr 19 02:59:27 2019 +0800

    Deprecate RT::Article::LoadByInclude that was for old article selection UI

diff --git a/lib/RT/Article.pm b/lib/RT/Article.pm
index 7d086c981..f0b6ef674 100644
--- a/lib/RT/Article.pm
+++ b/lib/RT/Article.pm
@@ -541,6 +541,8 @@ the Article's Class is applied to that Queue.
 
 sub LoadByInclude {
     my $self = shift;
+    RT->Deprecated( Remove  => '5.2' );
+
     my %args = @_;
     my $Field = $args{Field};
     my $Value = $args{Value};

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


More information about the rt-commit mailing list