[Rt-commit] rt branch, 5.0/self-service-homepage-dashboard, created. rt-5.0.0-23-g72a7e4285b

Dianne Skoll dianne at bestpractical.com
Thu Sep 17 09:51:13 EDT 2020


The branch, 5.0/self-service-homepage-dashboard has been created
        at  72a7e4285b755f361b98e6947335c5f2eec95609 (commit)

- Log -----------------------------------------------------------------
commit e8ba9cb0acc38fbeb59e27ccb7250630a458b16f
Author: Dianne Skoll <dianne at bestpractical.com>
Date:   Thu Sep 3 14:43:11 2020 -0400

    Add ability to serve a custom dashboard as the SelfService home page.

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index a7301b3436..884f9bc34c 100644
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -2070,8 +2070,6 @@ Set(
 =back
 
 
-
-
 =head2 Ticket search
 
 =over 4
@@ -2948,6 +2946,41 @@ on self service pages.
 
 Set($SelfServiceShowGroupTickets, 0);
 
+=item C<$SelfServicePageComponents>
+
+C<$SelfServicePageComponents> is an arrayref of allowed components on
+the SelfService page, if you have set $SelfServiceUseDashboard to true.
+If this is not set at all, then $HomepageComponents is used instead.
+
+=cut
+
+Set(
+    $SelfServicePageComponents,
+    [
+        qw(QuickCreate QueueList MyAdminQueues MySupportQueues MyReminders RefreshHomepage Dashboards SavedSearches FindUser MyAssets FindAsset FindGroup SelfServiceTopArticles ) # loc_qw
+    ]
+);
+
+=item C<$SelfServiceUseDashboard>
+
+C<$SelfServiceUseDashboard> is a flag indicating whether or not to use
+a dashboard for the Self Service home page.  If it is set to false,
+then the normal Open Tickets / Closed Tickets menu is shown rather
+than a dashboard.
+
+=cut
+
+Set($SelfServiceUseDashboard, 0);
+
+=item C<$SelfServiceArticleClass>
+
+C<$SelfServiceArticleClass> limits the articles shown to self-service
+users to the specified class.
+
+=cut
+
+Set($SelfServiceArticleClass, "SelfService");
+
 =back
 
 =head2 Articles
diff --git a/lib/RT/Config.pm b/lib/RT/Config.pm
index 400dd5ac22..59ce078f1c 100644
--- a/lib/RT/Config.pm
+++ b/lib/RT/Config.pm
@@ -1591,6 +1591,9 @@ our %META;
     SearchResultsAutoRedirect => {
         Widget => '/Widgets/Form/Boolean',
     },
+    SelfServiceUseDashboard => {
+        Widget => '/Widgets/Form/Boolean',
+    },
     ShowBccHeader => {
         Widget => '/Widgets/Form/Boolean',
     },
diff --git a/lib/RT/Dashboard/SelfService.pm b/lib/RT/Dashboard/SelfService.pm
new file mode 100644
index 0000000000..e20ffb76fa
--- /dev/null
+++ b/lib/RT/Dashboard/SelfService.pm
@@ -0,0 +1,101 @@
+# BEGIN BPS TAGGED BLOCK {{{
+#
+# COPYRIGHT:
+#
+# This software is Copyright (c) 1996-2020 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 }}}
+
+=head1 NAME
+
+  RT::Dashboard::SelfService - dashboard for the Self-Service Home Page
+
+=head1 SYNOPSIS
+
+  See RT::Dashboard
+
+=cut
+
+package RT::Dashboard::SelfService;
+
+use strict;
+use warnings;
+
+use base qw/RT::Dashboard/;
+
+=head2 ObjectName
+
+An object of this class is called "selfservicedashboard"
+
+=cut
+
+sub ObjectName { "selfservicedashboard" } # loc
+
+=head2 PostLoadValidate
+
+Ensure that the ID corresponds to an actual dashboard object, since it's all
+attributes under the hood.
+
+=cut
+
+sub PostLoadValidate {
+    my $self = shift;
+    return (0, "Invalid object type") unless $self->{'Attribute'}->Name eq 'SelfServiceDashboard';
+    return 1;
+}
+
+sub SaveAttribute {
+    my $self   = shift;
+    my $object = shift;
+    my $args   = shift;
+
+    return $object->AddAttribute(
+        'Name'        => 'SelfServiceDashboard',
+        'Description' => $args->{'Name'},
+        'Content'     => {Panes => $args->{'Panes'}},
+    );
+}
+
+RT::Base->_ImportOverlays();
+
+1;
diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index ce7c78f679..de32934bbb 100644
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -4718,7 +4718,8 @@ sub UpdateDashboard {
             return ( $ok, $msg ) = $user->SetPreferences( 'HomepageSettings', $data->{panes} );
         }
     } else {
-        my $Dashboard = RT::Dashboard->new( $session{'CurrentUser'} );
+        my $class = $args->{self_service_dashboard} ? 'RT::Dashboard::SelfService' : 'RT::Dashboard';
+        my $Dashboard = $class->new( $session{'CurrentUser'} );
         ( $ok, $msg ) = $Dashboard->LoadById($id);
 
         # report error at the bottom
diff --git a/lib/RT/Interface/Web/MenuBuilder.pm b/lib/RT/Interface/Web/MenuBuilder.pm
index 17eac59cb7..65ce0ee7ce 100644
--- a/lib/RT/Interface/Web/MenuBuilder.pm
+++ b/lib/RT/Interface/Web/MenuBuilder.pm
@@ -1229,6 +1229,16 @@ sub _BuildAdminMenu {
         description => loc('Modify the default "RT at a glance" view'),
         path        => '/Admin/Global/MyRT.html',
     );
+    if (RT->Config->Get('SelfServiceUseDashboard')) {
+        my $self_service = $admin_global->child( selfservice_home =>
+                                                 title       => loc('Self-Service Home Page'),
+                                                 description => loc('Edit self-service home page dashboard'),
+                                                 path        => '/Admin/Global/SelfServiceHomePage.html');
+        if ( $request_path =~ m{^/Admin/Global/SelfServiceHomePage} ) {
+            $page->child(content => title => loc('Content'), path => '/Admin/Global/SelfServiceHomePage.html');
+            $page->child(show    => title => loc('Show'), path => '/SelfService');
+        }
+    }
     $admin_global->child( 'dashboards-in-menu' =>
         title       => loc('Modify Reports menu'),
         description => loc('Customize dashboards in menu'),
@@ -1571,6 +1581,7 @@ sub _BuildAdminMenu {
     }
 }
 
+#'
 sub BuildSelfServiceNav {
     my $request_path = shift;
     my $top          = shift;
@@ -1581,6 +1592,15 @@ sub BuildSelfServiceNav {
 
     my $current_user = $HTML::Mason::Commands::session{CurrentUser};
 
+    if (RT->Config->Get('SelfServiceUseDashboard')) {
+        if ($request_path =~ m{^/SelfService/index\.html$}) {
+            if ($current_user->HasRight( Right => 'ShowConfigTab',
+                                         Object => RT->System)) {
+                $page->child(content => title => loc('Content'), path => '/Admin/Global/SelfServiceHomePage.html');
+                $page->child(show    => title => loc('Show'), path => '/SelfService');
+            }
+        }
+    }
     my $queues = RT::Queues->new( $current_user );
     $queues->UnLimit;
 
@@ -1600,8 +1620,13 @@ sub BuildSelfServiceNav {
     } elsif ( $queue_id ) {
         $top->child( new => title => loc('New ticket'), path => '/SelfService/Create.html?Queue=' . $queue_id );
     }
-    my $tickets = $top->child( tickets => title => loc('Tickets'), path => '/SelfService/' );
-    $tickets->child( open   => title => loc('Open tickets'),   path => '/SelfService/' );
+
+    my $menu_label = loc('Tickets');
+    if (RT->Config->Get('SelfServiceUseDashboard')) {
+        $menu_label = loc('Self-Service');
+    }
+    my $tickets = $top->child( tickets => title => $menu_label, path => '/SelfService/' );
+    $tickets->child( open   => title => loc('Open tickets'),   path => '/SelfService/Open.html' );
     $tickets->child( closed => title => loc('Closed tickets'), path => '/SelfService/Closed.html' );
 
     $top->child( "assets", title => loc("Assets"), path => "/SelfService/Asset/" )
diff --git a/share/html/SelfService/index.html b/share/html/Admin/Global/SelfServiceHomePage.html
similarity index 55%
copy from share/html/SelfService/index.html
copy to share/html/Admin/Global/SelfServiceHomePage.html
index 78d6b95a7b..3969dd4280 100644
--- a/share/html/SelfService/index.html
+++ b/share/html/Admin/Global/SelfServiceHomePage.html
@@ -45,30 +45,51 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<& /SelfService/Elements/Header, Title => loc('Open tickets') &>
+%#<& /Elements/Header, Title => $title &>
+%#<& /Elements/Tabs &>
+%#<& /Elements/ListActions, actions => \@results &>
 
-% $m->callback(CallbackName => 'BeforeMyRequests', ARGSRef => \%ARGS, Page => $Page);
+<%INIT>
+# If custom self-service page disabled, redirect to /Admin/Global
+if (!RT->Config->Get('SelfServiceUseDashboard')) {
+    RT::Interface::Web::Redirect(RT->Config->Get('WebURL') . 'Admin/Global');
+}
 
-<& /SelfService/Elements/MyRequests,
-    %ARGS,
-    status  => '__Active__',
-    title   => loc('My open tickets'),
-    BaseURL => RT->Config->Get('WebPath') ."/SelfService/?",
-    Page    => $Page, 
-&>
+my $title = loc('Self-Service Home Page');
+my @results;
 
-% $m->callback(CallbackName => 'AfterMyRequests', ARGSRef => \%ARGS, Page => $Page);
+use RT::Dashboard::SelfService;
+my $Dashboard = RT::Dashboard::SelfService->new($session{'CurrentUser'});
 
-<& /SelfService/Elements/MyGroupRequests,
-    %ARGS,
-    status  => '__Active__',
-    title   => loc('My group\'s tickets'),
-    BaseURL => RT->Config->Get('WebPath') ."/SelfService/?",
-    Page    => $Page,
-&>
+my $dashboard_id;
 
-% $m->callback(CallbackName => 'AfterMyGroupRequests', ARGSRef => \%ARGS, Page => $Page);
+# The Self-Service Home Page dashboard is special; its attribute is
+# named "selfservicedashboard" instead of "dashboard".  We just
+# need to get an ID to reuse the rest of the dashboard code.
+my $attr = RT::Attribute->new(RT->SystemUser);
+my ($ok, $msg) = $attr->LoadByNameAndObject(Object => $RT::System,
+                                            Name => 'SelfServiceDashboard');
+if (!$ok) {
+    my $blank_dashboard = {
+        Panes => {
+            body    => [],
+            sidebar => [],
+        }
+    };
+    # Doesn't exist... try creating an empty one
+    ($ok, $msg) = $Dashboard->Save(
+        Privacy => $RT::System,
+        Description => 'Self-Service Home Page Dashboard',
+        Object => $RT::System,
+        Content => $blank_dashboard);
+    unless ($ok) {
+        RT::Logger->error("Unable to create self-service home page dashboard: $msg");
+        Abort(loc("Could not create self-service home page dashboard"));
+    }
+    $dashboard_id = $Dashboard->id;
+} else {
+    $dashboard_id = $attr->Id;
+}
+$m->comp('/Dashboards/Queries.html', id => $dashboard_id, self_service_dashboard => 1, %ARGS);
 
-<%ARGS>
-$Page => 1
-</%ARGS>
+</%INIT>
diff --git a/share/html/Articles/Article/Edit.html b/share/html/Articles/Article/Edit.html
index b51e0eda55..007350bace 100644
--- a/share/html/Articles/Article/Edit.html
+++ b/share/html/Articles/Article/Edit.html
@@ -122,6 +122,14 @@ if ( $ARGS{SetEnabled} ) {
     $ARGS{Disabled} = $ARGS{Enabled} ? 0 : 1;
 }
 
+my $sortorder_ok = 1;
+if ($ARGS{SortOrder}) {
+    if ($ARGS{SortOrder} !~ /^-?\d+$/) {
+        push @results, (0, loc('Sort Order must be an integer'));
+        $sortorder_ok = 0;
+    }
+}
+
 if ( !$id ) {
     $title = loc('Create a new article');
     foreach my $arg ( sort keys %ARGS ) {
@@ -148,25 +156,30 @@ elsif ( $id eq 'new' ) {
           split( /\s+/, $ARGS{'new-RefersTo'} );
     }
 
-    my %cfs = ProcessObjectCustomFieldUpdatesForCreate(
-        ARGSRef         => \%ARGS,
-        ContextObject   => $ClassObj,
-    );
-
-    my $msg;
-    ( $id, $msg ) = $ArticleObj->Create(
-        Summary => $ARGS{'Summary'},
-        Name    => $ARGS{'Name'},
-        Class   => $ARGS{'Class'},
-        Topics  => $ARGS{'Topics'},
-        Disabled => $ARGS{'Disabled'},
-        %create_args,
-        %cfs
-    );
-    push( @results, $msg );
-    if ($id) {
+    my %cfs;
+    if ($sortorder_ok) {
+        %cfs = ProcessObjectCustomFieldUpdatesForCreate(
+            ARGSRef         => \%ARGS,
+            ContextObject   => $ClassObj,
+            );
 
+        my $msg;
+        ( $id, $msg ) = $ArticleObj->Create(
+            Summary => $ARGS{'Summary'},
+            SortOrder => $ARGS{'SortOrder'},
+            Name    => $ARGS{'Name'},
+            Class   => $ARGS{'Class'},
+            Topics  => $ARGS{'Topics'},
+            Disabled => $ARGS{'Disabled'},
+            %create_args,
+            %cfs
+            );
+        push( @results, $msg );
+    } else {
+        $id = 0;
+    }
 
+    if ($id) {
         $ArticleObj->Load($id);
 
         $title = loc( 'Modify article #[_1]', $ArticleObj->Id );
@@ -199,11 +212,13 @@ else {
 
     my @attribs = qw(Name Summary Class Disabled);
 
-    @results = UpdateRecordObject(
-        AttributesRef => \@attribs,
-        Object        => $ArticleObj,
-        ARGSRef       => \%ARGS
-    );
+    if ($sortorder_ok) {
+        @results = UpdateRecordObject(
+            AttributesRef => \@attribs,
+            Object        => $ArticleObj,
+            ARGSRef       => \%ARGS
+            );
+    }
 
     my @cf_results = ProcessObjectCustomFieldUpdates(
         Object  => $ArticleObj,
diff --git a/share/html/Dashboards/Elements/ShowPortlet/component b/share/html/Dashboards/Elements/ShowPortlet/component
index cead432fb2..b3258fe706 100644
--- a/share/html/Dashboards/Elements/ShowPortlet/component
+++ b/share/html/Dashboards/Elements/ShowPortlet/component
@@ -56,7 +56,14 @@ $HasResults
 my $full_path = $Portlet->{path};
 (my $path = $full_path) =~ s{^/Elements/}{};
 
-my $allowed = grep { $_ eq $path } @{RT->Config->Get('HomepageComponents')};
+my $allowed;
+
+if ($m->request_path =~ m{/SelfService}) {
+    $allowed = grep { $_ eq $path } @{RT->Config->Get('SelfServicePageComponents') || RT->Config->Get('HomepageComponents')};
+} else {
+    $allowed = grep { $_ eq $path } @{RT->Config->Get('HomepageComponents')};
+}
+
 </%init>
 % if (!$allowed) {
 %     $m->out( $m->interp->apply_escapes( loc("Invalid portlet [_1]", $path), "h" ) );
diff --git a/share/html/Dashboards/Queries.html b/share/html/Dashboards/Queries.html
index 379e7b1976..c0b47d1ed2 100644
--- a/share/html/Dashboards/Queries.html
+++ b/share/html/Dashboards/Queries.html
@@ -61,19 +61,38 @@
 <%INIT>
 my @results;
 
-use RT::Dashboard;
-my $Dashboard = RT::Dashboard->new($session{'CurrentUser'});
+# Don't permit someone to supply "self_service_dashboard=1" on the URL line
+if ($m->request_path ne '/Admin/Global/SelfServiceHomePage.html') {
+    $self_service_dashboard = 0;
+}
+
+my $class = $self_service_dashboard ? 'RT::Dashboard::SelfService' : 'RT::Dashboard';
+eval "use $class;";
+my $Dashboard = $class->new($session{'CurrentUser'});
 my ($ok, $msg) = $Dashboard->LoadById($id);
 unless ($ok) {
     RT::Logger->error("Unable to load dashboard with $id: $msg");
     Abort(loc("Could not load dashboard [_1]", $id), Code => HTTP::Status::HTTP_NOT_FOUND);
 }
-my $title = loc("Modify the content of dashboard [_1]", $Dashboard->Name);
+
+my $title;
+
+if ($self_service_dashboard) {
+    $title = loc("Modify the self-service home page");
+} else {
+    $title = loc("Modify the content of dashboard [_1]", $Dashboard->Name);
+}
 
 my @sections;
 my %item_for;
 
-my @components = map { type => "component", name => $_, label => loc($_) }, @{RT->Config->Get('HomepageComponents')};
+my @components;
+
+if ($self_service_dashboard) {
+    @components = map { type => "component", name => $_, label => loc($_) }, @{RT->Config->Get('SelfServicePageComponents') || RT->Config->Get('HomepageComponents')};
+} else {
+    @components = map { type => "component", name => $_, label => loc($_) }, @{RT->Config->Get('HomepageComponents')};
+}
 
 $item_for{ $_->{type} }{ $_->{name} } = $_ for @components;
 
@@ -214,17 +233,32 @@ $m->callback(
 
 if ( $ARGS{UpdateSearches} ) {
     $ARGS{dashboard_id} = $id;
+    $ARGS{self_service_dashboard} = $self_service_dashboard;
     my ($ok, $msg) = UpdateDashboard( \%ARGS, \%item_for );
-    push @results, $ok ? loc('Dashboard updated') : $msg;
+    if ($self_service_dashboard) {
+        push @results, $ok ? loc('Self-service home page updated') : $msg;
+    } else {
+        push @results, $ok ? loc('Dashboard updated') : $msg;
+    }
 
+    my $path;
+    my $args;
+    if ($self_service_dashboard) {
+        $path = '/Admin/Global/SelfServiceHomePage.html';
+        $args = { };
+    } else {
+        $path = '/Dashboards/Queries.html';
+        $args = { id => $id };
+    }
     MaybeRedirectForResults(
         Actions   => \@results,
-        Path      => "/Dashboards/Queries.html",
-        Arguments => { id => $id },
+        Path      => $path,
+        Arguments => $args,
     );
 }
 
 </%INIT>
 <%ARGS>
 $id => '' unless defined $id
+$self_service_dashboard => 0 unless defined $self_service_dashboard;
 </%ARGS>
diff --git a/share/html/Dashboards/Render.html b/share/html/Dashboards/Render.html
index 18aaec7572..350ed44026 100644
--- a/share/html/Dashboards/Render.html
+++ b/share/html/Dashboards/Render.html
@@ -110,13 +110,20 @@
 my @results;
 my $skip_create = 0;
 
+# Don't permit someone to supply "self_service_dashboard=1" directly
+# on the URL line
+if ($m->request_path ne '/SelfService/index.html') {
+    $self_service_dashboard = 0;
+}
+
 $m->callback(ARGSRef => \%ARGS,
              results => \@results,
              CallbackName => 'Initial',
              skip_create => \$skip_create);
 
-use RT::Dashboard;
-my $Dashboard = RT::Dashboard->new($session{'CurrentUser'});
+my $class = $self_service_dashboard ? 'RT::Dashboard::SelfService' : 'RT::Dashboard';
+eval "use $class;";
+my $Dashboard = $class->new($session{'CurrentUser'});
 my ($ok, $msg) = $Dashboard->LoadById($id);
 unless ($ok) {
     RT::Logger->error("Unable to load dashboard with $id: $msg");
@@ -146,7 +153,12 @@ unless (defined($rows)) {
     $rows = defined($prefs->{'RowsPerPage'}) ? $prefs->{'RowsPerPage'} : 50;
 }
 
-my $title = loc '[_1] Dashboard', $Dashboard->Name;
+my $title;
+if ($self_service_dashboard) {
+    $title = loc('Self-service Dashboard');
+} else {
+    $title = loc '[_1] Dashboard', $Dashboard->Name;
+}
 
 my $show_cb = sub {
     my $pane = shift;
@@ -171,5 +183,6 @@ my $Refresh = $Preview
 $id => undef
 $Preview => 1
 $HasResults => undef
+$self_service_dashboard => 0
 </%ARGS>
 
diff --git a/share/html/SelfService/index.html b/share/html/Elements/SelfServiceTopArticles
similarity index 73%
copy from share/html/SelfService/index.html
copy to share/html/Elements/SelfServiceTopArticles
index 78d6b95a7b..79c3a50081 100644
--- a/share/html/SelfService/index.html
+++ b/share/html/Elements/SelfServiceTopArticles
@@ -45,30 +45,12 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<& /SelfService/Elements/Header, Title => loc('Open tickets') &>
 
-% $m->callback(CallbackName => 'BeforeMyRequests', ARGSRef => \%ARGS, Page => $Page);
-
-<& /SelfService/Elements/MyRequests,
-    %ARGS,
-    status  => '__Active__',
-    title   => loc('My open tickets'),
-    BaseURL => RT->Config->Get('WebPath') ."/SelfService/?",
-    Page    => $Page, 
-&>
-
-% $m->callback(CallbackName => 'AfterMyRequests', ARGSRef => \%ARGS, Page => $Page);
-
-<& /SelfService/Elements/MyGroupRequests,
-    %ARGS,
-    status  => '__Active__',
-    title   => loc('My group\'s tickets'),
-    BaseURL => RT->Config->Get('WebPath') ."/SelfService/?",
-    Page    => $Page,
-&>
-
-% $m->callback(CallbackName => 'AfterMyGroupRequests', ARGSRef => \%ARGS, Page => $Page);
+<& /Elements/TopArticles,
+   title => $title,
+   display_path => 'SelfService/Article',
+   classname => (RT->Config->Get('SelfServiceArticleClass') || 'SelfService') &>
 
 <%ARGS>
-$Page => 1
+$title => undef
 </%ARGS>
diff --git a/share/html/SelfService/index.html b/share/html/Elements/TopArticles
similarity index 58%
copy from share/html/SelfService/index.html
copy to share/html/Elements/TopArticles
index 78d6b95a7b..824e7d7cbb 100644
--- a/share/html/SelfService/index.html
+++ b/share/html/Elements/TopArticles
@@ -45,30 +45,54 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<& /SelfService/Elements/Header, Title => loc('Open tickets') &>
 
-% $m->callback(CallbackName => 'BeforeMyRequests', ARGSRef => \%ARGS, Page => $Page);
+<&| /Widgets/TitleBox, title => $title &>
 
-<& /SelfService/Elements/MyRequests,
-    %ARGS,
-    status  => '__Active__',
-    title   => loc('My open tickets'),
-    BaseURL => RT->Config->Get('WebPath') ."/SelfService/?",
-    Page    => $Page, 
-&>
+% while (my $article = $articles->Next) {
+  <div class="form-row">
+    <span class="value col-auto">
+      <a href="<% RT->Config->Get('WebPath') %>/<% $display_path %>/Display.html?id=<%$article->Id%>"><%$article->Name || loc('(no name)')%>: <%$article->Summary%></a>
+    </span>
+  </div>
+% }
+</&>
 
-% $m->callback(CallbackName => 'AfterMyRequests', ARGSRef => \%ARGS, Page => $Page);
+<%INIT>
+$title = loc('Articles');
+# Figure out which class of articles applies, if a classname was given
+my $class;
 
-<& /SelfService/Elements/MyGroupRequests,
-    %ARGS,
-    status  => '__Active__',
-    title   => loc('My group\'s tickets'),
-    BaseURL => RT->Config->Get('WebPath') ."/SelfService/?",
-    Page    => $Page,
-&>
+if ($classname) {
+    $class = RT::Class->new( $session{'CurrentUser'} );
+    my ($ok, $msg) = $class->LoadByCols( Name => RT->Config->Get('SelfServiceArticleClass') );
+    if (!$ok || !$class->Id) {
+        # Could not find the class... bail?
+        return;
+    }
+}
 
-% $m->callback(CallbackName => 'AfterMyGroupRequests', ARGSRef => \%ARGS, Page => $Page);
+# Get the articles
+my $articles = RT::Articles->new( $session{'CurrentUser'} );
+
+$articles->RowsPerPage($rows);
+
+if ($class) {
+    $articles->Search(Class   => $class->Id,
+                      OrderBy => ['SortOrder', 'LastUpdated'],
+                      Order   => ['ASC',       'DESC'       ]);
+} else {
+    $articles->Search(OrderBy => ['SortOrder', 'LastUpdated'],
+                      Order   => ['ASC',       'DESC'       ]);
+}
+
+</%INIT>
 
 <%ARGS>
-$Page => 1
+$title => undef
+$rows => 10
+# Unfortunately, the directory hierarchy under SelfService
+# is just "Article" instead of "Articles/Article", so we have
+# to make to path for displaying an article a parameter.
+$display_path => 'Articles/Article'
+$classname => undef
 </%ARGS>
diff --git a/share/html/SelfService/index.html b/share/html/SelfService/Open.html
similarity index 98%
copy from share/html/SelfService/index.html
copy to share/html/SelfService/Open.html
index 78d6b95a7b..83e9f768a5 100644
--- a/share/html/SelfService/index.html
+++ b/share/html/SelfService/Open.html
@@ -46,7 +46,7 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <& /SelfService/Elements/Header, Title => loc('Open tickets') &>
-
+<& /Elements/PageLayout, show_menu => 0 &>
 % $m->callback(CallbackName => 'BeforeMyRequests', ARGSRef => \%ARGS, Page => $Page);
 
 <& /SelfService/Elements/MyRequests,
diff --git a/share/html/SelfService/index.html b/share/html/SelfService/index.html
index 78d6b95a7b..0ddf61c486 100644
--- a/share/html/SelfService/index.html
+++ b/share/html/SelfService/index.html
@@ -45,30 +45,34 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<& /SelfService/Elements/Header, Title => loc('Open tickets') &>
+<%INIT>
+use RT::Dashboard::SelfService;
+if (RT->Config->Get('SelfServiceUseDashboard')) {
+    # Check if we have a self-service dashboard
+    my $Dashboard = RT::Dashboard::SelfService->new($session{'CurrentUser'});
 
-% $m->callback(CallbackName => 'BeforeMyRequests', ARGSRef => \%ARGS, Page => $Page);
+    my $dashboard_id;
 
-<& /SelfService/Elements/MyRequests,
-    %ARGS,
-    status  => '__Active__',
-    title   => loc('My open tickets'),
-    BaseURL => RT->Config->Get('WebPath') ."/SelfService/?",
-    Page    => $Page, 
-&>
+    # The Self-Service Home Page dashboard is special; its attribute is
+    # named "selfservicedashboard" instead of "dashboard".  We just
+    # need to get an ID to reuse the rest of the dashboard code.
+    my $attr = RT::Attribute->new(RT->SystemUser);
+    my ($ok, $msg) = $attr->LoadByNameAndObject(Object => $RT::System,
+                                                Name => 'SelfServiceDashboard');
+    if ($ok && $attr->Id) {
+        # Try to load the dashboard
+        my ($ok, $msg) = $Dashboard->LoadById($attr->Id);
+        if ($ok) {
+            $m->comp('/Dashboards/Render.html', id => $attr->Id, self_service_dashboard => 1);
+            return;
+        }
+    }
+}
 
-% $m->callback(CallbackName => 'AfterMyRequests', ARGSRef => \%ARGS, Page => $Page);
-
-<& /SelfService/Elements/MyGroupRequests,
-    %ARGS,
-    status  => '__Active__',
-    title   => loc('My group\'s tickets'),
-    BaseURL => RT->Config->Get('WebPath') ."/SelfService/?",
-    Page    => $Page,
-&>
-
-% $m->callback(CallbackName => 'AfterMyGroupRequests', ARGSRef => \%ARGS, Page => $Page);
+# Default to old-style "My Open Tickets"
+$m->comp('/SelfService/Open.html', Page => $Page);
 
+</%INIT>
 <%ARGS>
 $Page => 1
 </%ARGS>

commit 72a7e4285b755f361b98e6947335c5f2eec95609
Author: Dianne Skoll <dianne at bestpractical.com>
Date:   Wed Sep 9 12:16:46 2020 -0400

    Add UI for editing and displaying the SortOrder associated with an article.

diff --git a/lib/RT/Article.pm b/lib/RT/Article.pm
index af1e628784..ba7375efca 100644
--- a/lib/RT/Article.pm
+++ b/lib/RT/Article.pm
@@ -777,7 +777,7 @@ sub _CoreAccessible {
         Summary => 
                 {read => 1, write => 1, type => 'varchar(255)', default => ''},
         SortOrder => 
-                {read => 1, write => 1, type => 'int(11)', default => '0'},
+                {read => 1, write => 1, type => 'int(11)', default => '0', is_numeric => 1},
         Class => 
                 {read => 1, write => 1, type => 'int(11)', default => '0'},
         Parent => 
diff --git a/share/html/Articles/Article/Display.html b/share/html/Articles/Article/Display.html
index 6f841d430a..aee001f5c5 100644
--- a/share/html/Articles/Article/Display.html
+++ b/share/html/Articles/Article/Display.html
@@ -58,6 +58,15 @@
     </div>
   </div>
 
+  <div class="form-row">
+    <div class="label col-3">
+      <&|/l&>Sort Order</&>:
+    </div>
+    <div class="value col-9">
+      <span class="current-value"><%$article->SortOrder%></span>
+    </div>
+  </div>
+
   <div class="form-row">
     <div class="label col-3">
       <&|/l&>Class</&>:
diff --git a/share/html/Articles/Article/Edit.html b/share/html/Articles/Article/Edit.html
index 007350bace..4116610c29 100644
--- a/share/html/Articles/Article/Edit.html
+++ b/share/html/Articles/Article/Edit.html
@@ -163,6 +163,20 @@ elsif ( $id eq 'new' ) {
             ContextObject   => $ClassObj,
             );
 
+        my $msg;
+        ( $id, $msg ) = $ArticleObj->Create(
+            Summary => $ARGS{'Summary'},
+            SortOrder => $ARGS{'SortOrder'},
+            Name    => $ARGS{'Name'},
+            Class   => $ARGS{'Class'},
+            Topics  => $ARGS{'Topics'},
+            Disabled => $ARGS{'Disabled'},
+            %create_args,
+            %cfs
+            );
+        push( @results, $msg );
+    }
+    if ($id) {
         my $msg;
         ( $id, $msg ) = $ArticleObj->Create(
             Summary => $ARGS{'Summary'},
@@ -210,7 +224,7 @@ else {
             Why => loc("Unable to load article") );
     }
 
-    my @attribs = qw(Name Summary Class Disabled);
+    my @attribs = qw(Name Summary Class Disabled SortOrder);
 
     if ($sortorder_ok) {
         @results = UpdateRecordObject(
diff --git a/share/html/Articles/Article/Elements/EditBasics b/share/html/Articles/Article/Elements/EditBasics
index 73c5a7f5a1..a898a9cbd1 100644
--- a/share/html/Articles/Article/Elements/EditBasics
+++ b/share/html/Articles/Article/Elements/EditBasics
@@ -61,6 +61,14 @@
     <input class="form-control" type="text" name="Summary" value="<%($ARGS{'id'} eq 'new' ? '' : $ArticleObj->Summary) || $ARGS{'Summary'} ||'' |h%>" size="50" />
   </div>
 </div>
+<div class="form-row">
+  <div class="label col-3">
+    <&|/l&>Sort Order</&>:
+  </div>
+  <div class="value col-9">
+    <input class="form-control" type="text" name="SortOrder" value="<%($ARGS{'id'} eq 'new' ? '0' : $ArticleObj->SortOrder) || $ARGS{'SortOrder'} || '0' |h%>" size="50" />
+  </div>
+</div>
 <div class="form-row">
   <div class="label col-3">
     <&|/l&>Class</&>:

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


More information about the rt-commit mailing list