[Rt-commit] rtir branch, 5.0/search-selection, created. 4.0.1rc1-176-gcddeff2a

Craig Kaiser craig at bestpractical.com
Thu Jun 4 13:48:26 EDT 2020


The branch, 5.0/search-selection has been created
        at  cddeff2a674ac640da4bed60787e5ad2d01c7be9 (commit)

- Log -----------------------------------------------------------------
commit f1ed00589a13b11a1f9bdbf7679999eed046e2bf
Author: craig kaiser <craig at bestpractical.com>
Date:   Thu Jun 4 13:16:08 2020 -0400

    Use new search selection interface for editing RTIR home page

diff --git a/html/RTIR/Prefs/Home.html b/html/RTIR/Prefs/Home.html
index 7081f86d..7cfb8ec8 100644
--- a/html/RTIR/Prefs/Home.html
+++ b/html/RTIR/Prefs/Home.html
@@ -49,79 +49,186 @@
 <& /Elements/Tabs &>
 <& /Elements/ListActions, actions => \@results &>
 
-% foreach my $pane ( @panes ) {
-<&|/Widgets/TitleBox,
-    title => loc('RTIR at a glance') .': '. loc( $pane->{Name} ),
-    bodyclass => ""
-&>
-<& /Widgets/SelectionBox:show, self => $pane &>
-</&>
-% }
+<form method="post" name="UpdateSearches" class="mx-auto max-width-lg">
+  <& /Widgets/SearchSelection,
+    pane_name => \%pane_name,
+    sections  => \@sections,
+    selected  => \%selected,
+    filters   => \@filters,
+  &>
+  <input type="hidden" name="dashboard_id" value="MyRT">
+  <& /Elements/Submit, Name => "UpdateSearches", Label => loc('Save') &>
+</form>
 
 <%INIT>
-# XXX: copy&past of the similar RT's page
-
 my @results;
+my $title = loc("Customize").' '.loc("RT at a glance");
 my $user = $session{'CurrentUser'}->UserObj;
 
-unless (exists $session{'my_rtir_portlets'}) {
-    my ($d_portlets) = RT::System->new($session{'CurrentUser'})->Attributes->Named('RTIR_HomepageSettings');
-    $session{'my_rtir_portlets'} = $user->Preferences('RTIR_HomepageSettings', $d_portlets->Content);
-}
-my $portlets = $session{'my_rtir_portlets'};
-
-my %seen;
-
-my @items;
-foreach my $comp ( grep !$seen{$_}++, (RT->Config->Get('RTIR_HomepageComponents')) ) {
-    my $desc;
-    my $obj = $m->fetch_comp($comp);
-    $desc = $obj->attr_if_exists('Description') if $obj;
-    unless( $desc ) {
-        $desc = $comp;
-        $desc =~ s/^.*\///;
-    }
-    push @items, ["component-$comp", $desc];
+my $portlets = $user->Preferences('RTIR_HomepageSettings');
+unless ($portlets) {
+    my ($defaults) = RT::System->new($session{'CurrentUser'})->Attributes->Named('RTIR_HomepageSettings');
+    $portlets = $defaults ? $defaults->Content : {};
 }
 
+my @sections;
+my %item_for;
+
+my @components = map { type => "component", name => $_, label => loc($_) }, @{RT->Config->Get('RTIR_HomepageComponents')};
+
+$item_for{ $_->{type} }{ $_->{name} } = $_ for @components;
+
+push @sections, {
+    id    => 'components',
+    label => loc("Components"),
+    items => \@components,
+};
+
 my $sys = RT::System->new($session{'CurrentUser'});
 my @objs = ($sys);
 
-push @objs, RT::SavedSearch->new( $session{'CurrentUser'} )->_PrivacyObjects
+push @objs, RT::SavedSearch->new( $session{CurrentUser} )->ObjectsForLoading
     if $session{'CurrentUser'}->HasRight( Right  => 'LoadSavedSearch',
-                                          Object => $RT::System );
+                                            Object => $RT::System );
 
 for my $object (@objs) {
+    my @items;
+    my $object_id = ref($object) . '-' . $object->Id;
+    $object_id = 'system' if $object eq $sys;
+
     for ($m->comp("/Search/Elements/SearchesForObject", Object => $object)) {
         my ($desc, $loc_desc, $search) = @$_;
-        my $SearchType = $search->Content->{'SearchType'} || 'Ticket';
+
+        my $SearchType = 'Ticket';
+        if ((ref($search->Content)||'') eq 'HASH') {
+            $SearchType = $search->Content->{'SearchType'}
+                if $search->Content->{'SearchType'};
+        }
+        else {
+            $RT::Logger->debug("Search ".$search->id." ($desc) appears to have no Content");
+        }
+
+        my $item;
         if ($object eq $sys && $SearchType eq 'Ticket') {
-            push @items, ["system-$desc", $loc_desc];
+            $item = { type => 'system', name => $desc, label => $loc_desc };
         }
         else {
-            my $oid = ref($object).'-'.$object->Id.'-SavedSearch-'.$search->Id;
-            my $type = ($SearchType eq 'Ticket')
-                ? 'Saved Search' : $SearchType; # loc
-            push @items, ["saved-$oid", loc($type).": $loc_desc"];
+            my $oid = $object_id.'-SavedSearch-'.$search->Id;
+            $item = { type => 'saved', name => $oid, search_type => $SearchType, label => $loc_desc };
         }
+
+        $item_for{ $item->{type} }{ $item->{name} } = $item;
+        push @items, $item;
     }
+
+    my $label = $object eq $sys           ? loc('System')
+                : $object->isa('RT::Group') ? $object->Label
+                                            : $object->Name;
+
+    push @sections, {
+        id    => $object_id,
+        label => $label,
+        items => [ sort { lc($a->{label}) cmp lc($b->{label}) } @items ],
+    };
 }
 
-my @panes = $m->comp(
-    '/Admin/Elements/ConfigureMyRT',
-    panes  => ['body', 'sidebar'],
-    Action => 'Home.html',
-    items => \@items,
-    current_portlets => $portlets,
-    OnSave => sub {
-        my ( $conf, $pane ) = @_;
-        my ($ok, $msg) = $user->SetPreferences( 'RTIR_HomepageSettings', $conf );
-        push @results, $ok ? loc('Preferences saved for [_1].', $pane) : $msg;
-        delete $session{'my_rtir_portlets'};
+my %selected;
+for my $pane (keys %$portlets) {
+    my @items;
+
+    for my $saved (@{ $portlets->{$pane} }) {
+        my $item = $item_for{ $saved->{type} }{ $saved->{name} };
+        if ($item) {
+            push @items, $item;
+        }
+        else {
+            push @results, loc('Unable to find [_1] [_2]', $saved->{type}, $saved->{name});
+        }
     }
+
+    $selected{$pane} = \@items;
+}
+
+my %pane_name = (
+    'body'    => loc('Body'),
+    'sidebar' => loc('Sidebar'),
 );
 
-$m->comp ('/Widgets/SelectionBox:process', %ARGS, self => $_ ) for @panes;
+my @filters = (
+    [ 'component' => loc('Components') ],
+    [ 'ticket'    => loc('Tickets') ],
+    [ 'chart'     => loc('Charts') ],
+);
 
-MaybeRedirectForResults( Actions => \@results );
+$m->callback(
+    CallbackName => 'Default',
+    pane_name    => \%pane_name,
+    sections     => \@sections,
+    selected     => \%selected,
+    filters      => \@filters,
+);
+
+if ($ARGS{UpdateSearches}) {
+    my $data = {
+        "panes"        => {
+            "body"    => [],
+            "sidebar" => []
+        }
+    };
+
+    foreach my $arg (qw{ body sidebar }) {
+        my $pane   = $arg;
+        my $values = $ARGS{$pane};
+
+        next unless $values;
+
+        # force value to an arrayref so we can handle both single and multiple members of each pane.
+        $values = [$values] unless ref $values;
+
+        foreach my $value ( @{$values} ) {
+            $value =~ m/^(\w+)-(.+)$/i;
+            my $type = $1;
+            my $name = $2;
+            push @{ $data->{panes}->{$pane} }, { type => $type, name => $name };
+        }
+    }
+
+    my ( $ok, $msg );
+    my $user = $session{CurrentUser};
+
+    if ( my $user_id = $ARGS{user_id} ) {
+        my $UserObj = RT::User->new( $session{'CurrentUser'} );
+        ( $ok, $msg ) = $UserObj->Load($user_id);
+        ( $ok, $msg ) = $UserObj->SetPreferences( 'RTIR_HomepageSettings', $data->{panes} );
+        if ( $ok ) {
+            push @results, loc("Preferences saved.");
+        }
+        else {
+            push @results, loc("Could not save preferences.");
+        }
+    } elsif ( $ARGS{is_global} ) {
+        my $sys = RT::System->new( $session{'CurrentUser'} );
+        my ($default_portlets) = $sys->Attributes->Named('RTIR_HomepageSettings');
+        ( $ok, $msg ) = $default_portlets->SetContent( $data->{panes} );
+        if ( $ok ) {
+            push @results, loc("Preferences saved.");
+        }
+        else {
+            push @results, loc("Could not save preferences.");
+        }
+    } else {
+        ( $ok, $msg ) = $user->SetPreferences( 'RTIR_HomepageSettings', $data->{panes} );
+        if ( $ok ) {
+            push @results, loc("Preferences saved.");
+        }
+        else {
+            push @results, loc("Could not save preferences.");
+        }
+    }
+
+    MaybeRedirectForResults(
+        Actions   => \@results,
+        Path      => "/RTIR/Prefs/Home.html",
+    );
+}
 </%INIT>
diff --git a/html/RTIR/index.html b/html/RTIR/index.html
index 77909674..0b855c80 100644
--- a/html/RTIR/index.html
+++ b/html/RTIR/index.html
@@ -51,14 +51,11 @@
 <& /Elements/MyRT, Portlets => $portlets &>
 <%INIT>
 
-# XXX: this should be automated!!!
-unless ( exists $session{'my_rtir_portlets'} ) {
-    my ($d_portlets) = RT::System->new( $session{'CurrentUser'} )->Attributes->Named('RTIR_HomepageSettings');
-    $session{'my_rtir_portlets'} = $session{'CurrentUser'}->UserObj->Preferences(
-        'RTIR_HomepageSettings', $d_portlets->Content
-    );
+my $portlets = $session{'CurrentUser'}->Preferences('RTIR_HomepageSettings');
+unless ($portlets) {
+    my ($defaults) = RT::System->new($session{'CurrentUser'})->Attributes->Named('RTIR_HomepageSettings');
+    $portlets = $defaults ? $defaults->Content : {};
 }
-my $portlets = $session{'my_rtir_portlets'};
 
 if ( defined $q && length $q ) {
 

commit cddeff2a674ac640da4bed60787e5ad2d01c7be9
Author: craig kaiser <craig at bestpractical.com>
Date:   Thu Jun 4 13:30:20 2020 -0400

    Add tests for new search selection UI for RTIR homepage

diff --git a/t/web/custom_frontpage.t b/t/web/custom_frontpage.t
new file mode 100644
index 00000000..437c8e37
--- /dev/null
+++ b/t/web/custom_frontpage.t
@@ -0,0 +1,138 @@
+use strict;
+use warnings;
+
+use RT::IR::Test tests => undef;
+my ($baseurl, $m) = RT::IR::Test->started_ok;
+
+my $url = $m->rt_base_url;
+
+my $user_obj = RT::User->new(RT->SystemUser);
+my ($ret, $msg) = $user_obj->LoadOrCreateByEmail('customer at example.com');
+ok($ret, 'ACL test user creation');
+$user_obj->SetName('customer');
+$user_obj->SetPrivileged(1);
+($ret, $msg) = $user_obj->SetPassword('customer');
+$user_obj->PrincipalObj->GrantRight(Right => 'LoadSavedSearch');
+$user_obj->PrincipalObj->GrantRight(Right => 'EditSavedSearches');
+$user_obj->PrincipalObj->GrantRight(Right => 'CreateSavedSearch');
+$user_obj->PrincipalObj->GrantRight(Right => 'ModifySelf');
+
+ok $m->login( customer => 'customer' ), "logged in";
+
+$m->get ( $url."Search/Build.html");
+
+#create a saved search
+$m->form_name ('BuildQuery');
+
+$m->field ( "ValueOfAttachment" => 'stupid');
+$m->field ( "SavedSearchDescription" => 'stupid tickets');
+$m->click_button (name => 'SavedSearchSave');
+
+$m->get ( $url.'RTIR/Prefs/Home.html' );
+$m->content_contains('stupid tickets', 'saved search listed in rt at a glance items');
+
+ok $m->login('root', 'password', logout => 1), 'we did log in as root';
+
+my $args = {
+    UpdateSearches => "Save",
+    dashboard_id   => "RTIR_HomepageSettings",
+    body           => [],
+    sidebar        => [],
+};
+
+# remove all portlets from the body pane except 'newest unowned tickets'
+push(
+    @{$args->{body}},
+    ( "system-Unowned Tickets", )
+);
+
+my $res = $m->post(
+    $url . 'RTIR/Prefs/Home.html',
+    $args,
+);
+
+is( $res->code, 200, "remove all portlets from body except 'newest unowned tickets'" );
+like( $m->uri, qr/results=[A-Za-z0-9]{32}/, 'URL redirected for results' );
+$m->content_contains( 'Preferences saved' );
+
+$m->get( $url."RTIR/" );
+$m->content_contains( 'newest unowned tickets', "'newest unowned tickets' is present" );
+$m->content_lacks( 'highest priority tickets', "'highest priority tickets' is not present" );
+$m->content_lacks( 'Bookmarked Tickets<span class="results-count">', "'Bookmarked Tickets' is not present" );  # 'Bookmarked Tickets' also shows up in the nav, so we need to be more specific
+$m->content_lacks( 'Quick ticket creation', "'Quick ticket creation' is not present" );
+
+# add back the previously removed portlets
+push(
+    @{$args->{body}},
+    ( "system-My Tickets", "system-Bookmarked Tickets", "component-QuickCreate" )
+);
+
+push(
+    @{$args->{sidebar}},
+    ( "component-MyReminders", "component-QueueList", "component-Dashboards", "component-RefreshHomepage", )
+);
+
+$res = $m->post(
+    $url . 'RTIR/Prefs/Home.html',
+    $args,
+);
+
+is( $res->code, 200, 'add back previously removed portlets' );
+like( $m->uri, qr/results=[A-Za-z0-9]{32}/, 'URL redirected for results' );
+$m->content_contains( 'Preferences saved' );
+
+$m->get( $url."RTIR/" );
+$m->content_contains( 'newest unowned tickets', "'newest unowned tickets' is present" );
+$m->content_contains( 'highest priority tickets', "'highest priority tickets' is present" );
+$m->content_contains( 'Bookmarked Tickets<span class="results-count">', "'Bookmarked Tickets' is present" );
+$m->content_contains( 'Quick ticket creation', "'Quick ticket creation' is present" );
+
+#create a saved search with special chars
+$m->get( $url . "Search/Build.html" );
+$m->form_name('BuildQuery');
+$m->field( "ValueOfAttachment"      => 'stupid' );
+$m->field( "SavedSearchDescription" => 'special chars [test] [_1] ~[_1~]' );
+$m->click_button( name => 'SavedSearchSave' );
+my ($name) = $m->content =~ /value="(RT::User-\d+-SavedSearch-\d+)"/;
+ok( $name, 'saved search name' );
+$m->get( $url . 'RTIR/Prefs/Home.html' );
+$m->content_contains( 'special chars [test] [_1] ~[_1~]',
+    'saved search listed in rt at a glance items' );
+
+# add saved search to body
+push(
+    @{$args->{body}},
+    ( "saved-" . $name )
+);
+
+$res = $m->post(
+    $url . 'RTIR/Prefs/Home.html',
+    $args,
+);
+
+is( $res->code, 200, 'add saved search to body' );
+like( $m->uri, qr/results=[A-Za-z0-9]{32}/, 'URL redirected for results' );
+$m->content_contains( 'Preferences saved' );
+
+$m->get( $url."RTIR/" );
+$m->content_like( qr/special chars \[test\] \d+ \[_1\]/,
+    'special chars in titlebox' );
+
+# Edit a system saved search to contain "[more]"
+{
+    my $search = RT::Attribute->new( RT->SystemUser );
+    $search->LoadByNameAndObject( Name => 'Search - My Tickets', Object => RT->System );
+    my ($id, $desc) = ($search->id, RT->SystemUser->loc($search->Description, '"N"'));
+    ok $id, 'loaded search attribute';
+
+    $m->get( $url."RTIR/" );
+    $m->follow_link_ok({ url_regex => qr"Prefs/Search\.html\?name=.+?Attribute-$id" }, 'Edit link');
+    $m->content_contains($desc, "found description: $desc");
+
+    ok +($search->SetDescription( $search->Description . " [more]" ));
+
+    $m->get_ok($m->uri); # "reload_ok"
+    $m->content_contains($desc . " [more]", "found description: $desc");
+}
+
+done_testing;

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


More information about the rt-commit mailing list