[Rt-commit] rt branch, master, updated. rt-4.4.1-236-gfb54c65

Shawn Moore shawn at bestpractical.com
Tue Dec 27 13:36:56 EST 2016


The branch, master has been updated
       via  fb54c659901e73eee3e377385d1774bb39cd4123 (commit)
       via  cb9c3d6210d338353d6ae30a541564b739c727ec (commit)
       via  2171a89ff9a083838e2eec6bc25dba655e5c39ec (commit)
       via  a670d25b4b565601020102e27cd63728c3e763f4 (commit)
       via  d77fa0177dae3ca9b002728698544d27cf74d1c2 (commit)
       via  0ce4d256d5e05a88121e9e5a91a27f07bbdd8d5c (commit)
       via  fe57de4991594a27b0d16dbaa5a6d323556eb7e4 (commit)
       via  50a9dbc6ecfad862e9fb9a386e5f8a690188bc10 (commit)
       via  9a9dedca32bff22c13359e23a8a1525ab06abc02 (commit)
       via  602fd00650c4d15c1e53cde8a258e056abe342cb (commit)
       via  40bd0e1e60d79fcd6a665d2c457ca28fc9b12d51 (commit)
       via  523fabb14cb2c722602dae2e516a3a2c7f2be9b3 (commit)
       via  06362de3b6cd3451aca2eda009b0d2137a876a05 (commit)
       via  496865ab2a04eb344d69a0909a4dceb27595ee17 (commit)
       via  d88a99937fef4a2dc8e03c66d0f653c31efb9c7b (commit)
       via  a4fe91084f768a07094265af3133bdb1a1697cae (commit)
       via  193312de2822d942f5ffa39dd5d30ab32a26e453 (commit)
       via  b3793935243914ffd8ed11143e0504f355a03ba8 (commit)
       via  f9eb378c579e141c05e9846f21f2ddbeeb1359b0 (commit)
       via  d83ce00ed5b8d697a8e6d681ce4d8de0d67a0949 (commit)
       via  398ec1b9a1b86ad5d66c209dec07825ab95648dd (commit)
       via  0b81e2ad0b33b8fb101bd70ef95eac0e00e62803 (commit)
       via  d1effcf01b39c5a3992561092bbac0833891c7b0 (commit)
       via  988f7133a9a6de15956ae006648512b4f4be5dc1 (commit)
       via  a3e11d047dc6cfa5c5c9e5b9dd48f68e11a4b91a (commit)
       via  d9feec6fa4685efc9b229e3e5e7f314d41e45df9 (commit)
       via  f1c247a2b029d15cc9b6fc738d5a2b645b6aff86 (commit)
       via  a24f4358480d8665b985f9ccddbec2d1cb724388 (commit)
       via  165e965af7b83f8630b6f95ece2f8e34228f4443 (commit)
       via  01e8ae5c511c76ba5f8e0e66f1e60f32a49c9bbe (commit)
       via  73e9b63197d109ec18f1fd81f2765056d5d08a57 (commit)
       via  af1e5ace42efbf5804f22d790723548f4ca15491 (commit)
       via  a0f38800f21edbaed3e6a5e29a6a0ecaa6978c37 (commit)
       via  43aa03582cddc23aee38a52a4aeacf042766176e (commit)
       via  4f0066c82ad24d2366901f5d9059e3e296cd94ed (commit)
       via  54430537c6e28107ea41207496b47c3e8a5c7a36 (commit)
       via  e649ec2af5f00a41006b4c9de1c86138d0683b9e (commit)
       via  19f8d5225fcfa109cd3c3ab20f08ddcf93e0cce6 (commit)
       via  2adef2d212ba351c9bee31b04df080a8933c3a8d (commit)
       via  7e3e17cf1d9162ff827cb7c86c6f6a68a8a57a8c (commit)
       via  c317aced32f31c6f8f8f9769fa16c9522f6c6e3e (commit)
       via  8b2474ae84dcb5a3685423d1d01d41e7d9eaf2e5 (commit)
       via  5549b229405f9236bd1a37d433979c1ce12f93ed (commit)
       via  c9774928c6da3757b266e305a2794f0b4122ac47 (commit)
       via  99c08c1141c9a38cb727073d70d95d92243df1ef (commit)
       via  cfeadd0831c301a794a034f68d4d6a0ccb36c6ef (commit)
       via  65a7c031dc285d80520e16fa447357a0fb7608cc (commit)
       via  b0e6ea916eca77ba07ea722e6d2c8e736254cb20 (commit)
       via  d0f00c0da56475083098f8907f98078ab474524b (commit)
       via  9ea1b16f17a70e0136e704a0d95e7d9021063533 (commit)
       via  c9934435c149ab3833e0c8585e65125551626477 (commit)
       via  18cc75db4638cb9b7e6117217f5ee9d4a945fdf9 (commit)
       via  cbd5ed469f41db880ad041c56e547f5a8fb4a95d (commit)
       via  05ddb1844560bc8153e9ccf52e7956c506fc33c7 (commit)
       via  d6cdacb638315ae2772ba97d0c5894e9daa22e6d (commit)
       via  fd91b5b5c37af455414b96b05241a6183ff79d48 (commit)
       via  b00a27fdb942e033bc6eaa83cac228298da425c0 (commit)
       via  095caac2a4b4fc7baba0d7878a79f8b486579854 (commit)
       via  3da2bf2868ff72f5e13b19eba4f02eb8f5a85f70 (commit)
       via  fb4bdf2d6fe2742fe1c510af7446e1dd6b888e92 (commit)
       via  40d289bbc0b41ceadecc50e4b2a50d5c7be96432 (commit)
       via  bdd6bd96ece4faebb5a067bdd787b8e2e4fec755 (commit)
       via  8cd8411090e783a460d84a4725e7f33a81145d2f (commit)
       via  f3df1c32fb11acbc87cceed0c309b1fc4a2e4c45 (commit)
       via  f56d238f62bd60e572a374523b6fc7e526b73b95 (commit)
       via  9b4705611e637604a3c00b7c3f036196928c581f (commit)
       via  74c6ea0f9adcf8cfcc1f5d8de5849bf7abe55a0c (commit)
       via  69474c481897f655239467077976fbdc11b6879d (commit)
       via  b34993b69bbb8480f2759950a926995b0fae7aed (commit)
       via  1e3010c6bffdbf4923edf0cdc439fba39655acc0 (commit)
       via  148773b084f567555559249e1fad67330ce0132b (commit)
       via  fc7fd6b4eefaccd4550d9869da149ea3ee1d5e90 (commit)
       via  f815e22ff4861eadeb77a0eca9faccb761ee465f (commit)
       via  ad59123af04971e43f13da0de457db65d63b5429 (commit)
       via  5f4c8a2e4311ade309d109cb59682fa8ac0c3f6d (commit)
       via  14c420dc448fadbf97d925928f70ab3f006edca3 (commit)
       via  434613b4a64a43edce7fd825720b063633f769c1 (commit)
       via  6df28d54e2fd06adfb32b34ec30a90f19b2d521c (commit)
       via  34a629893c3459f77705c23a7d4672ba501fddfd (commit)
       via  40d29f995084845ed029c7650935ffaa47173dd5 (commit)
       via  6862e956520730d55604a411076e05cf92dc30ea (commit)
       via  bee6259f3b2de401709237c574885b95442d74c7 (commit)
       via  a99b566793518b051577d685432115140bec85d0 (commit)
       via  c491c12593663489e49ab1ccd523f17821f98bbe (commit)
       via  4eea9a99e2deb8012cd047c487d92f7468f314d6 (commit)
       via  2e50209edb4ba798790d69cf27466bdad01cb2de (commit)
       via  542ffc5412bf8293c67420a7801a66e7868d77d9 (commit)
       via  51f6226fa546f6e67f190977bd7d6981763f62c7 (commit)
       via  4ed0f4e647d4d1243c7aa3d1da649ae57d36b98c (commit)
       via  7bdd183b11be1b24d137115454d6de55818de42e (commit)
       via  a3988c716512dbc11da5dc48cb5affcfc8b10ca6 (commit)
       via  e56326444ffaa560926610c52c8391cbc21196ea (commit)
       via  d82a3f9b49d9349ce569a1f5da5f385d2ba3f536 (commit)
       via  f94b7adcf95cb89cdec16351530b42e35290bbde (commit)
       via  9f5b8613d97b73bf5e0b3a0980cac3addd36b4a7 (commit)
       via  910d0e1d94de9e29ec9508543c76bdf6d9ef969a (commit)
       via  2472f6f8627c7c708c4afdff324eb2f1aa580f64 (commit)
       via  fadf6d42733753ac597aa5c5265a45d206d201bd (commit)
       via  a382b3bc2f84fe571d824a37c24e036330dbb3d7 (commit)
       via  dec44b12a87a5711e24b166c2ecee4abc9d2fddb (commit)
       via  e78766c9d29e7010a95b64b6297baf9287e8309f (commit)
       via  45340e2509dd1983add59edae03824483ad0280b (commit)
       via  6ba90ec2a176f0429ee4babf81e694f908385b9b (commit)
       via  b4f82e954efd0057863fbaba6bef0322579ad2bb (commit)
       via  4b8d65e12d5e787f2fa4525b7467110c021d9c92 (commit)
       via  fef4c5d699d05f7f4539ee7de34c74a2f1fd7ac1 (commit)
       via  aa5ff92eb5dab3d065e2a446d6a0573ffb08471a (commit)
       via  f6a78a2f754a2f67631c6c66775359f1e2671a87 (commit)
       via  6cec0e78ecf911064f7f1fc2a8ccd24e0e0c46f7 (commit)
       via  803da618e41839a38fa05fc03c86bc2bc9f24eb9 (commit)
       via  b41a13e8555e98283e5e5ad6721931c819ca09d1 (commit)
       via  877b88b07f34e39ac0d0c82a938a31faff4edc7a (commit)
       via  deb8019a0d83b37499c9094a860538dcfadc3685 (commit)
       via  84ec669470f5b550fc5bfc8175393e644e7c2870 (commit)
       via  05db56f2b375b6219859a627731f344f34c95489 (commit)
       via  1bb578722e7d0a7c57134db82b7ed801cf9d79e8 (commit)
       via  6b877623854cee199a61826f868b3ac730fd30e1 (commit)
       via  4333c9c6ac258626bdf348189eb5fd553c90d648 (commit)
      from  927b64d034d3ef66767fc4642d3bf9d58091bc99 (commit)

Summary of changes:
 etc/RT_Config.pm.in                                | 148 +++++++++++++++------
 lib/RT.pm                                          |   1 +
 .../{SetPriority.pm => SetCustomFieldToNow.pm}     |  20 +--
 lib/RT/Config.pm                                   |   9 ++
 lib/RT/Crypt/SMIME.pm                              |   8 ++
 lib/RT/Dashboards.pm                               |  16 +++
 lib/RT/Date.pm                                     |   2 +-
 lib/RT/ExternalStorage/AmazonS3.pm                 |  45 ++++++-
 lib/RT/ExternalStorage/Disk.pm                     |   2 +-
 lib/RT/ExternalStorage/Dropbox.pm                  |   2 +-
 lib/RT/I18N.pm                                     |   9 +-
 lib/RT/Interface/Email.pm                          |  60 ++++++---
 lib/RT/Interface/Web.pm                            |  94 ++++++++++++-
 lib/RT/Interface/Web/MenuBuilder.pm                |  24 +++-
 lib/RT/PlackRunner.pm                              |   9 ++
 lib/RT/Plugin.pm                                   |  11 ++
 lib/RT/Record/Role/Roles.pm                        |   5 +-
 lib/RT/System.pm                                   |   2 +
 lib/RT/Test.pm                                     |   5 +-
 lib/RT/Test/GnuPG.pm                               |  10 +-
 lib/RT/Ticket.pm                                   |   9 +-
 lib/RT/User.pm                                     |  58 ++++++++
 sbin/rt-externalize-attachments.in                 |   5 +-
 sbin/rt-server.in                                  |   3 +
 share/html/Admin/Scrips/index.html                 |  30 ++++-
 share/html/Admin/Tools/Configuration.html          |  17 +++
 share/html/Admin/Users/Modify.html                 |   5 +
 share/html/Articles/Elements/BeforeMessageBox      |   2 +-
 share/html/Dashboards/Elements/ShowDashboards      |   1 +
 share/html/Dashboards/Render.html                  |  13 ++
 share/html/Elements/ColumnMap                      |   2 +-
 share/html/Elements/Crypt/SignEncryptWidget        |   3 +
 share/html/Elements/EditCustomFieldSelect          |   6 +
 share/html/Elements/EditCustomFields               |   9 +-
 share/html/Elements/Header                         |   8 +-
 share/html/Elements/JavascriptConfig               |   3 +-
 share/html/Elements/QuickCreate                    |   2 +-
 share/html/Elements/ShowCustomFields               |   9 +-
 share/html/Elements/ShowHistoryHeader              |  11 ++
 share/html/Elements/ShowHistoryPage                |   6 +-
 share/html/Elements/ShowTransaction                |   2 +
 share/html/Helpers/PreviewScrips                   |   2 +-
 share/html/Helpers/ShowSimplifiedRecipients        |   2 +-
 share/html/Helpers/TicketHistoryPage               |   3 +-
 share/html/Search/Chart                            |  10 +-
 share/html/SelfService/Create.html                 |   1 +
 share/html/SelfService/Prefs.html                  |   2 +
 share/html/Ticket/Display.html                     |   9 +-
 share/html/Ticket/Elements/ScrollShowHistory       |  28 +++-
 share/html/Ticket/Elements/UpdateCc                |  48 ++++++-
 share/html/Ticket/Forward.html                     |  33 ++++-
 share/html/Ticket/History.html                     |   2 +
 share/html/Ticket/Modify.html                      |   6 +-
 share/html/Ticket/ModifyAll.html                   |   1 +
 share/html/Ticket/ModifyDates.html                 |   7 +-
 share/html/Ticket/ModifyLinks.html                 |   3 +
 share/html/Ticket/ModifyPeople.html                |   9 ++
 share/html/Ticket/Reminders.html                   |   3 +
 share/html/Ticket/Update.html                      |   3 +
 share/html/index.html                              |  66 +--------
 share/static/css/base/ticket-form.css              |  10 ++
 share/static/js/util.js                            |   4 +
 t/lifecycles/basics.t                              |   2 +-
 t/lifecycles/dates.t                               |   2 +-
 t/lifecycles/moving.t                              |   2 +-
 t/lifecycles/types.t                               |   2 +-
 t/lifecycles/unresolved-deps.t                     |   2 +-
 t/mail/gnupg-outgoing-encrypted-plaintext.t        |   6 +-
 t/mail/gnupg-outgoing-encrypted.t                  |   6 +-
 t/mail/gnupg-outgoing-plain-plaintext.t            |   6 +-
 t/mail/gnupg-outgoing-plain.t                      |   6 +-
 t/mail/gnupg-outgoing-signed-plaintext.t           |   6 +-
 t/mail/gnupg-outgoing-signed.t                     |   6 +-
 t/mail/gnupg-outgoing-signed_encrypted-plaintext.t |   6 +-
 t/mail/gnupg-outgoing-signed_encrypted.t           |   6 +-
 t/mail/mime_decoding.t                             |  10 ++
 t/mail/outgoing-mail-from.t                        |  56 ++++++++
 t/mail/precedence-outgoing.t                       |  59 ++++++++
 t/web/cf_datetime.t                                |   4 +-
 t/web/cf_groupings.t                               |   2 +-
 t/web/cf_select_one.t                              |   7 +
 t/web/gnupg-select-keys-on-create.t                |  43 +++---
 t/web/gnupg-select-keys-on-update.t                |  45 ++++---
 t/web/installer.t                                  |   5 +-
 84 files changed, 975 insertions(+), 252 deletions(-)
 copy lib/RT/Action/{SetPriority.pm => SetCustomFieldToNow.pm} (81%)
 create mode 100644 t/mail/outgoing-mail-from.t
 create mode 100644 t/mail/precedence-outgoing.t

- Log -----------------------------------------------------------------
commit fb54c659901e73eee3e377385d1774bb39cd4123
Merge: 927b64d cb9c3d6
Author: Shawn M Moore <shawn at bestpractical.com>
Date:   Tue Dec 27 13:36:44 2016 -0500

    Merge branch '4.4-trunk'

diff --cc lib/RT/Interface/Web/MenuBuilder.pm
index b4b6e0e,8579f67..d68ad6c
--- a/lib/RT/Interface/Web/MenuBuilder.pm
+++ b/lib/RT/Interface/Web/MenuBuilder.pm
@@@ -64,185 -57,335 +64,202 @@@ sub QueryString 
      my $u    = URI->new();
      $u->query_form(map { $_ => $args{$_} } sort keys %args);
      return $u->query;
 -};
 +}
  
 -my $build_admin_menu = sub {
 -    my $top = shift;
 -    my $admin = $top->child( admin => title => loc('Admin'), path => '/Admin/' );
 -    if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminUsers' ) ) {
 -        my $users = $admin->child( users =>
 -            title       => loc('Users'),
 -            description => loc('Manage users and passwords'),
 -            path        => '/Admin/Users/',
 -        );
 -        $users->child( select => title => loc('Select'), path => "/Admin/Users/" );
 -        $users->child( create => title => loc('Create'), path => "/Admin/Users/Modify.html?Create=1" );
 -    }
 -    my $groups = $admin->child( groups =>
 -        title       => loc('Groups'),
 -        description => loc('Manage groups and group membership'),
 -        path        => '/Admin/Groups/',
 -    );
 -    $groups->child( select => title => loc('Select'), path => "/Admin/Groups/" );
 -    $groups->child( create => title => loc('Create'), path => "/Admin/Groups/Modify.html?Create=1" );
 +sub BuildMainNav {
 +    my $request_path = shift;
 +    my $top          = shift;
 +    my $widgets      = shift;
 +    my $page         = shift;
  
 -    my $queues = $admin->child( queues =>
 -        title       => loc('Queues'),
 -        description => loc('Manage queues and queue-specific properties'),
 -        path        => '/Admin/Queues/',
 -    );
 -    $queues->child( select => title => loc('Select'), path => "/Admin/Queues/" );
 -    $queues->child( create => title => loc('Create'), path => "/Admin/Queues/Modify.html?Create=1" );
 +    my %args = ( @_ );
  
 -    if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminCustomField' ) ) {
 -        my $cfs = $admin->child( 'custom-fields' =>
 -            title       => loc('Custom Fields'),
 -            description => loc('Manage custom fields and custom field values'),
 -            path        => '/Admin/CustomFields/',
 -        );
 -        $cfs->child( select => title => loc('Select'), path => "/Admin/CustomFields/" );
 -        $cfs->child( create => title => loc('Create'), path => "/Admin/CustomFields/Modify.html?Create=1" );
 +    my $query_string = $args{QueryString};
 +    my $query_args = $args{QueryArgs};
 +
 +    my $current_user = $HTML::Mason::Commands::session{CurrentUser};
 +
 +    if ($request_path =~ m{^/Asset/}) {
 +        $widgets->child( asset_search => raw_html => $HTML::Mason::Commands::m->scomp('/Asset/Elements/Search') );
 +    } else {
 +        $widgets->child( simple_search => raw_html => $HTML::Mason::Commands::m->scomp('SimpleSearch') );
 +        $widgets->child( create_ticket => raw_html => $HTML::Mason::Commands::m->scomp('CreateTicket') );
      }
  
 -    if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminCustomRoles' ) ) {
 -        my $roles = $admin->child( 'custom-roles' =>
 -            title       => loc('Custom Roles'),
 -            description => loc('Manage custom roles'),
 -            path        => '/Admin/CustomRoles/',
 +    my $home = $top->child( home => title => loc('Homepage'), path => '/' );
 +    unless ($HTML::Mason::Commands::session{'dashboards_in_menu'}) {
 +        my $dashboards_in_menu = $current_user->UserObj->Preferences(
 +            'DashboardsInMenu',
 +            {},
          );
 -        $roles->child( select => title => loc('Select'), path => "/Admin/CustomRoles/" );
 -        $roles->child( create => title => loc('Create'), path => "/Admin/CustomRoles/Modify.html?Create=1" );
 +
 +        unless ($dashboards_in_menu->{dashboards}) {
 +            my ($default_dashboards) =
 +                RT::System->new( $current_user )
 +                    ->Attributes
 +                    ->Named('DashboardsInMenu');
 +            if ($default_dashboards) {
 +                $dashboards_in_menu = $default_dashboards->Content;
 +            }
 +        }
 +
 +        $HTML::Mason::Commands::session{'dashboards_in_menu'} = $dashboards_in_menu->{dashboards} || [];
      }
  
 -    if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'ModifyScrips' ) ) {
 -        my $scrips = $admin->child( 'scrips' =>
 -            title       => loc('Scrips'),
 -            description => loc('Manage scrips'),
 -            path        => '/Admin/Scrips/',
 -        );
 -        $scrips->child( select => title => loc('Select'), path => "/Admin/Scrips/" );
 -        $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html" );
 +    my @dashboards;
 +    for my $id ( @{$HTML::Mason::Commands::session{'dashboards_in_menu'}} ) {
 +        my $dash = RT::Dashboard->new( $current_user );
 +        my ( $status, $msg ) = $dash->LoadById($id);
 +        if ( $status ) {
 +            push @dashboards, $dash;
 +        } else {
 +            $RT::Logger->warning( "Failed to load dashboard $id: $msg" );
 +        }
      }
  
 -    my $admin_global = $admin->child( global =>
 -        title       => loc('Global'),
 -        description => loc('Manage properties and configuration which apply to all queues'),
 -        path        => '/Admin/Global/',
 -    );
 +    my $dashes = $top->child('home');
 +    if (@dashboards) {
 +        for my $dash (@dashboards) {
 +            $home->child( 'dashboard-' . $dash->id,
 +                title => $dash->Name,
 +                path  => '/Dashboards/' . $dash->id . '/' . $dash->Name
 +            );
 +        }
 +    }
 +    $dashes->child( edit => title => loc('Update This Menu'), path => 'Prefs/DashboardsInMenu.html' );
 +    $dashes->child( more => title => loc('All Dashboards'),   path => 'Dashboards/index.html' );
 +    my $dashboard = RT::Dashboard->new( $current_user );
 +    if ( $dashboard->CurrentUserCanCreateAny ) {
 +        $dashes->child('dashboard_create' => title => loc('New Dashboard'), path => "/Dashboards/Modify.html?Create=1" );
 +    }
  
 -    my $scrips = $admin_global->child( scrips =>
 -        title       => loc('Scrips'),
 -        description => loc('Modify scrips which apply to all queues'),
 -        path        => '/Admin/Global/Scrips.html',
 -    );
 -    $scrips->child( select => title => loc('Select'), path => "/Admin/Global/Scrips.html" );
 -    $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html?Global=1" );
 +    my $search = $top->child( search => title => loc('Search'), path => '/Search/Simple.html' );
  
 -    my $templates = $admin_global->child( templates =>
 -        title       => loc('Templates'),
 -        description => loc('Edit system templates'),
 -        path        => '/Admin/Global/Templates.html',
 -    );
 -    $templates->child( select => title => loc('Select'), path => "/Admin/Global/Templates.html" );
 -    $templates->child( create => title => loc('Create'), path => "/Admin/Global/Template.html?Create=1" );
 +    my $tickets = $search->child( tickets => title => loc('Tickets'), path => '/Search/Build.html' );
 +    $tickets->child( simple => title => loc('Simple Search'), path => "/Search/Simple.html" );
 +    $tickets->child( new    => title => loc('New Search'),    path => "/Search/Build.html?NewQuery=1" );
  
 -    my $cfadmin = $admin_global->child( 'custom-fields' =>
 -        title       => loc('Custom Fields'),
 -        description => loc('Modify global custom fields'),
 -        path        => '/Admin/Global/CustomFields/index.html',
 -    );
 -    $cfadmin->child( users =>
 -        title       => loc('Users'),
 -        description => loc('Select custom fields for all users'),
 -        path        => '/Admin/Global/CustomFields/Users.html',
 -    );
 -    $cfadmin->child( groups =>
 -        title       => loc('Groups'),
 -        description => loc('Select custom fields for all user groups'),
 -        path        => '/Admin/Global/CustomFields/Groups.html',
 -    );
 -    $cfadmin->child( queues =>
 -        title       => loc('Queues'),
 -        description => loc('Select custom fields for all queues'),
 -        path        => '/Admin/Global/CustomFields/Queues.html',
 -    );
 -    $cfadmin->child( tickets =>
 -        title       => loc('Tickets'),
 -        description => loc('Select custom fields for tickets in all queues'),
 -        path        => '/Admin/Global/CustomFields/Queue-Tickets.html',
 -    );
 -    $cfadmin->child( transactions =>
 -        title       => loc('Ticket Transactions'),
 -        description => loc('Select custom fields for transactions on tickets in all queues'),
 -        path        => '/Admin/Global/CustomFields/Queue-Transactions.html',
 -    );
 -    $cfadmin->child( 'custom-fields' =>
 -        title       => loc('Articles'),
 -        description => loc('Select Custom Fields for Articles in all Classes'),
 -        path        => '/Admin/Global/CustomFields/Class-Article.html',
 -    );
 -    $cfadmin->child( 'assets' =>
 -        title       => loc('Assets'),
 -        description => loc('Select Custom Fields for Assets in all Catalogs'),
 -        path        => '/Admin/Global/CustomFields/Catalog-Assets.html',
 -    );
++    my $recents = $tickets->child( recent => title => loc('Recently Viewed'));
++    for ($current_user->RecentlyViewedTickets) {
++        my ($ticketId, $timestamp) = @$_;
++        my $ticket = RT::Ticket->new($current_user);
++        $ticket->Load($ticketId);
++        if ($ticket->Id) {
++            my $title = $ticket->Subject || loc("(No subject)");
++            if (length $title > 50) {
++                $title = substr($title, 0, 47);
++                $title =~ s/\s+$//;
++                $title .= "...";
++            }
++            $title = "#$ticketId: " . $title;
++            $recents->child( "$ticketId" => title => $title, path => "/Ticket/Display.html?id=" . $ticket->Id );
++        }
++    }
+ 
 -    my $article_admin = $admin->child( articles => title => loc('Articles'), path => "/Admin/Articles/index.html" );
 -    my $class_admin = $article_admin->child(classes => title => loc('Classes'), path => '/Admin/Articles/Classes/' );
 -    $class_admin->child( select =>
 -        title       => loc('Select'),
 -        description => loc('Modify and Create Classes'),
 -        path        => '/Admin/Articles/Classes/',
 -    );
 -    $class_admin->child( create =>
 -        title       => loc('Create'),
 -        description => loc('Modify and Create Custom Fields for Articles'),
 -        path        => '/Admin/Articles/Classes/Modify.html?Create=1',
 -    );
 +    $search->child( articles => title => loc('Articles'),   path => "/Articles/Article/Search.html" )
 +        if $current_user->HasRight( Right => 'ShowArticlesMenu', Object => RT->System );
  
 +    $search->child( users => title => loc('Users'),   path => "/User/Search.html" );
  
 -    my $cfs = $article_admin->child( 'custom-fields' =>
 -        title => loc('Custom Fields'),
 -        path  => '/Admin/CustomFields/index.html?'.$m->comp('/Elements/QueryString', Type => 'RT::Class-RT::Article'),
 -    );
 -    $cfs->child( select =>
 -        title => loc('Select'),
 -        path => '/Admin/CustomFields/index.html?'.$m->comp('/Elements/QueryString', Type => 'RT::Class-RT::Article'),
 -    );
 -    $cfs->child( create =>
 -        title => loc('Create'),
 -        path => '/Admin/CustomFields/Modify.html?'.$m->comp("/Elements/QueryString", Create=>1, LookupType=> "RT::Class-RT::Article" ),
 -    );
 +    $search->child( assets => title => loc("Assets"), path => "/Asset/Search/" )
 +        if $current_user->HasRight( Right => 'ShowAssetsMenu', Object => RT->System );
  
 -    my $assets_admin = $admin->child( assets => title => loc("Assets"), path => '/Admin/Assets/' );
 -    my $catalog_admin = $assets_admin->child( catalogs =>
 -        title       => loc("Catalogs"),
 -        description => loc("Modify asset catalogs"),
 -        path        => "/Admin/Assets/Catalogs/"
 -    );
 -    $catalog_admin->child( "select", title => loc("Select"), path => $catalog_admin->path );
 -    $catalog_admin->child( "create", title => loc("Create"), path => "Create.html" );
 +    if ($current_user->HasRight( Right => 'ShowArticlesMenu', Object => RT->System )) {
 +        my $articles = $top->child( articles => title => loc('Articles'), path => "/Articles/index.html");
 +        $articles->child( articles => title => loc('Overview'), path => "/Articles/index.html" );
 +        $articles->child( topics   => title => loc('Topics'),   path => "/Articles/Topics.html" );
 +        $articles->child( create   => title => loc('Create'),   path => "/Articles/Article/PreCreate.html" );
 +        $articles->child( search   => title => loc('Search'),   path => "/Articles/Article/Search.html" );
 +    }
  
 +    if ($current_user->HasRight( Right => 'ShowAssetsMenu', Object => RT->System )) {
 +        my $assets = $top->child( "assets", title => loc("Assets"), path => "/Asset/Search/" );
 +        $assets->child( "create", title => loc("Create"), path => "/Asset/CreateInCatalog.html" );
 +        $assets->child( "search", title => loc("Search"), path => "/Asset/Search/" );
 +    }
  
 -    my $assets_cfs = $assets_admin->child( "cfs",
 -        title => loc("Custom Fields"),
 -        description => loc("Modify asset custom fields"),
 -        path => "/Admin/CustomFields/?Type=" . RT::Asset->CustomFieldLookupType
 -    );
 -    $assets_cfs->child( "select", title => loc("Select"), path => $assets_cfs->path );
 -    $assets_cfs->child( "create", title => loc("Create"), path => "/Admin/CustomFields/Modify.html?Create=1&LookupType=" . RT::Asset->CustomFieldLookupType);
 +    my $tools = $top->child( tools => title => loc('Tools'), path => '/Tools/index.html' );
  
 -    $admin_global->child( 'group-rights' =>
 -        title       => loc('Group Rights'),
 -        description => loc('Modify global group rights'),
 -        path        => '/Admin/Global/GroupRights.html',
 -    );
 -    $admin_global->child( 'user-rights' =>
 -        title       => loc('User Rights'),
 -        description => loc('Modify global user rights'),
 -        path        => '/Admin/Global/UserRights.html',
 -    );
 -    $admin_global->child( 'my-rt' =>
 -        title       => loc('RT at a glance'),
 -        description => loc('Modify the default "RT at a glance" view'),
 -        path        => '/Admin/Global/MyRT.html',
 -    );
 -    $admin_global->child( 'dashboards-in-menu' =>
 -        title       => loc('Dashboards in menu'),
 -        description => loc('Customize dashboards in menu'),
 -        path        => '/Admin/Global/DashboardsInMenu.html',
 +    $tools->child( my_day =>
 +        title       => loc('My Day'),
 +        description => loc('Easy updating of your open tickets'),
 +        path        => '/Tools/MyDay.html',
      );
 -    $admin_global->child( 'topics' =>
 -        title       => loc('Topics'),
 -        description => loc('Modify global article topics'),
 -        path        => '/Admin/Global/Topics.html',
 +
 +    if ( RT->Config->Get('EnableReminders') ) {
 +        $tools->child( my_reminders =>
 +            title       => loc('My Reminders'),
 +            description => loc('Easy viewing of your reminders'),
 +            path        => '/Tools/MyReminders.html',
 +        );
 +    }
 +
 +    if ( $current_user->HasRight( Right => 'ShowApprovalsTab', Object => RT->System ) ) {
 +        $tools->child( approval =>
 +            title       => loc('Approval'),
 +            description => loc('My Approvals'),
 +            path        => '/Approvals/',
 +        );
 +    }
 +
 +    if ( $current_user->HasRight( Right => 'ShowConfigTab', Object => RT->System ) )
 +    {
 +        _BuildAdminMenu( $request_path, $top, $widgets, $page, %args );
 +    }
 +
 +    my $username = '<span class="current-user">'
 +                 . $HTML::Mason::Commands::m->interp->apply_escapes($current_user->Name, 'h')
 +                 . '</span>';
 +    my $about_me = $top->child( 'preferences' =>
 +        title        => loc('Logged in as [_1]', $username),
 +        escape_title => 0,
 +        path         => '/User/Summary.html?id=' . $current_user->id,
 +        sort_order   => 99,
      );
  
 -    my $admin_tools = $admin->child( tools =>
 -        title       => loc('Tools'),
 -        description => loc('Use other RT administrative tools'),
 -        path        => '/Admin/Tools/',
 -    );
 -    $admin_tools->child( configuration =>
 -        title       => loc('System Configuration'),
 -        description => loc('Detailed information about your RT setup'),
 -        path        => '/Admin/Tools/Configuration.html',
 -    );
 -    $admin_tools->child( theme =>
 -        title       => loc('Theme'),
 -        description => loc('Customize the look of your RT'),
 -        path        => '/Admin/Tools/Theme.html',
 -    );
 -    if (RT->Config->Get('StatementLog')
 -        && $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System )) {
 -       $admin_tools->child( 'sql-queries' =>
 -           title       => loc('SQL Queries'),
 -           description => loc('Browse the SQL queries made in this process'),
 -           path        => '/Admin/Tools/Queries.html',
 -       );
 -    }
 -    $admin_tools->child( shredder =>
 -        title       => loc('Shredder'),
 -        description => loc('Permanently wipeout data from RT'),
 -        path        => '/Admin/Tools/Shredder',
 -    );
 -
 -    if ( $request_path =~ m{^/Admin/(Queues|Users|Groups|CustomFields|CustomRoles)} ) {
 -        my $type = $1;
 -        my $tabs = PageMenu();
  
 -        my %labels = (
 -            Queues       => loc("Queues"),
 -            Users        => loc("Users"),
 -            Groups       => loc("Groups"),
 -            CustomFields => loc("Custom Fields"),
 -            CustomRoles  => loc("Custom Roles"),
 +    if ( $current_user->UserObj
 +         && $current_user->HasRight( Right => 'ModifySelf', Object => RT->System )) {
 +        my $settings = $about_me->child( settings => title => loc('Settings'), path => '/Prefs/Other.html' );
 +        $settings->child( options        => title => loc('Preferences'),        path => '/Prefs/Other.html' );
 +        $settings->child( about_me       => title => loc('About me'),       path => '/Prefs/AboutMe.html' );
 +        $settings->child( search_options => title => loc('Search options'), path => '/Prefs/SearchOptions.html' );
 +        $settings->child( myrt           => title => loc('RT at a glance'), path => '/Prefs/MyRT.html' );
 +        $settings->child( dashboards_in_menu =>
 +            title => loc('Dashboards in menu'),
 +            path  => '/Prefs/DashboardsInMenu.html',
          );
 +        $settings->child( queue_list    => title => loc('Queue list'),   path => '/Prefs/QueueList.html' );
  
 -        my $section;
 -        if ( $request_path =~ m|^/Admin/$type/?(?:index.html)?$|
 -             || (    $request_path =~ m|^/Admin/$type/(?:Modify.html)$|
 -                  && $DECODED_ARGS->{'Create'} )
 -           )
 -        {
 -            $section = $tabs;
 -
 -        } else {
 -            $section = $tabs->child( select => title => $labels{$type},
 -                                     path => "/Admin/$type/" );
 -        }
 -
 -        $section->child( select => title => loc('Select'), path => "/Admin/$type/" );
 -        $section->child( create => title => loc('Create'), path => "/Admin/$type/Modify.html?Create=1" );
 -    }
 -
 -    if ( $request_path =~ m{^/Admin/Queues} ) {
 -        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/
 -                ||
 -              $DECODED_ARGS->{'Queue'} && $DECODED_ARGS->{'Queue'} =~ /^\d+$/
 -                ) {
 -            my $id = $DECODED_ARGS->{'Queue'} || $DECODED_ARGS->{'id'};
 -            my $queue_obj = RT::Queue->new( $session{'CurrentUser'} );
 -            $queue_obj->Load($id);
 -
 -            if ( $queue_obj and $queue_obj->id ) {
 -                my $queue = PageMenu();
 -                $queue->child( basics => title => loc('Basics'),   path => "/Admin/Queues/Modify.html?id=" . $id );
 -                $queue->child( people => title => loc('Watchers'), path => "/Admin/Queues/People.html?id=" . $id );
 -
 -                my $templates = $queue->child(templates => title => loc('Templates'), path => "/Admin/Queues/Templates.html?id=" . $id);
 -                $templates->child( select => title => loc('Select'), path => "/Admin/Queues/Templates.html?id=".$id);
 -                $templates->child( create => title => loc('Create'), path => "/Admin/Queues/Template.html?Create=1;Queue=".$id);
 -
 -                my $scrips = $queue->child( scrips => title => loc('Scrips'), path => "/Admin/Queues/Scrips.html?id=" . $id);
 -                $scrips->child( select => title => loc('Select'), path => "/Admin/Queues/Scrips.html?id=" . $id );
 -                $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html?Queue=" . $id);
 -
 -                my $cfs = $queue->child( 'custom-fields' => title => loc('Custom Fields') );
 -                my $ticket_cfs = $cfs->child( 'tickets' => title => loc('Tickets'),
 -                    path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket&id=' . $id );
 -
 -                my $txn_cfs = $cfs->child( 'transactions' => title => loc('Transactions'),
 -                    path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket-RT::Transaction&id='.$id );
 +        my $search_menu = $settings->child( 'saved-searches' => title => loc('Saved Searches') );
 +        my $searches = [ $HTML::Mason::Commands::m->comp( "/Search/Elements/SearchesForObject",
 +                          Object => RT::System->new( $current_user )) ];
 +        my $i = 0;
  
 -                $queue->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Queues/GroupRights.html?id=".$id );
 -                $queue->child( 'user-rights' => title => loc('User Rights'), path => "/Admin/Queues/UserRights.html?id=" . $id );
 -                $queue->child( 'history' => title => loc('History'), path => "/Admin/Queues/History.html?id=" . $id );
 -                $queue->child( 'default-values' => title => loc('Default Values'), path => "/Admin/Queues/DefaultValues.html?id=" . $id );
 +        for my $search (@$searches) {
 +            $search_menu->child( "search-" . $i++ =>
 +                title => $search->[1],
 +                path  => "/Prefs/Search.html?"
 +                       . QueryString( name => ref( $search->[2] ) . '-' . $search->[2]->Id ),
 +            );
  
 -                $m->callback( CallbackName => 'PrivilegedQueue', queue_id => $id, page_menu => $queue);
 -            }
          }
      }
 -    if ( $request_path =~ m{^(/Admin/Users|/User/(Summary|History)\.html)} and $admin->child("users") ) {
 -        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
 -            my $id = $DECODED_ARGS->{'id'};
 -            my $obj = RT::User->new( $session{'CurrentUser'} );
 -            $obj->Load($id);
 -
 -            if ( $obj and $obj->id ) {
 -                my $tabs = PageMenu();
 -                $tabs->child( basics      => title => loc('Basics'),         path => "/Admin/Users/Modify.html?id=" . $id );
 -                $tabs->child( memberships => title => loc('Memberships'),    path => "/Admin/Users/Memberships.html?id=" . $id );
 -                $tabs->child( history     => title => loc('History'),        path => "/Admin/Users/History.html?id=" . $id );
 -                $tabs->child( 'my-rt'     => title => loc('RT at a glance'), path => "/Admin/Users/MyRT.html?id=" . $id );
 -                $tabs->child( 'dashboards-in-menu' =>
 -                    title => loc('Dashboards in menu'),
 -                    path  => '/Admin/Users/DashboardsInMenu.html?id=' . $id,
 -                );
 -                if ( RT->Config->Get('Crypt')->{'Enable'} ) {
 -                    $tabs->child( keys    => title => loc('Private keys'),   path => "/Admin/Users/Keys.html?id=" . $id );
 -                }
 -                $tabs->child( 'summary'   => title => loc('User Summary'),   path => "/User/Summary.html?id=" . $id );
 -            }
 -        }
 -
 +    if ( $current_user->Name
 +         && (   !RT->Config->Get('WebRemoteUserAuth')
 +              || RT->Config->Get('WebFallbackToRTLogin') )) {
 +        $about_me->child( logout => title => loc('Logout'), path => '/NoAuth/Logout.html' );
      }
 -
 -    if ( $request_path =~ m{^/Admin/Groups} ) {
 -        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
 -            my $id = $DECODED_ARGS->{'id'};
 -            my $obj = RT::Group->new( $session{'CurrentUser'} );
 -            $obj->Load($id);
 -
 +    if ( $request_path =~ m{^/Dashboards/(\d+)?}) {
 +        if ( my $id = ( $1 || $HTML::Mason::Commands::DECODED_ARGS->{'id'} ) ) {
 +            my $obj = RT::Dashboard->new( $current_user );
 +            $obj->LoadById($id);
              if ( $obj and $obj->id ) {
 -                my $tabs = PageMenu();
 -                $tabs->child( basics         => title => loc('Basics'),       path => "/Admin/Groups/Modify.html?id=" . $obj->id );
 -                $tabs->child( members        => title => loc('Members'),      path => "/Admin/Groups/Members.html?id=" . $obj->id );
 -                $tabs->child( memberships    => title => loc('Memberships'),  path => "/Admin/Groups/Memberships.html?id=" . $obj->id );
 -                $tabs->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Groups/GroupRights.html?id=" . $obj->id );
 -                $tabs->child( 'user-rights'  => title => loc('User Rights'),  path => "/Admin/Groups/UserRights.html?id=" . $obj->id );
 -                $tabs->child( history        => title => loc('History'),      path => "/Admin/Groups/History.html?id=" . $obj->id );
 +                $page->child( basics       => title => loc('Basics'),       path => "/Dashboards/Modify.html?id=" . $obj->id);
 +                $page->child( content      => title => loc('Content'),      path => "/Dashboards/Queries.html?id=" . $obj->id);
 +                $page->child( subscription => title => loc('Subscription'), path => "/Dashboards/Subscription.html?id=" . $obj->id)
 +                    if $obj->CurrentUserCanSubscribe;
 +                $page->child( show         => title => loc('Show'),         path => "/Dashboards/" . $obj->id . "/" . $obj->Name)
              }
          }
      }
@@@ -389,648 -842,139 +406,649 @@@
          }
      }
  
 -    # Scope here so we can share in the Privileged callback
 -    my $args      = '';
 -    my $has_query = '';
 -    if (
 -        (
 -               $request_path =~ m{^/(?:Ticket|Search)/}
 -            && $request_path !~ m{^/Search/Simple\.html}
 -        )
 -        || (   $request_path =~ m{^/Search/Simple\.html}
 -            && $DECODED_ARGS->{'q'} )
 -      )
 -    {
 -        my $search = Menu()->child('search')->child('tickets');
 -        my $current_search = $session{"CurrentSearchHash"} || {};
 -        my $search_id = $DECODED_ARGS->{'SavedSearchLoad'} || $DECODED_ARGS->{'SavedSearchId'} || $current_search->{'SearchId'} || '';
 -        my $chart_id = $DECODED_ARGS->{'SavedChartSearchId'} || $current_search->{SavedChartSearchId};
 -
 -        $has_query = 1 if ( $DECODED_ARGS->{'Query'} or $current_search->{'Query'} );
++    # Scope here so we can share in the Privileged callback
++    my $args      = '';
++    my $has_query = '';
 +    if (
 +        (
 +               $request_path =~ m{^/(?:Ticket|Search)/}
 +            && $request_path !~ m{^/Search/Simple\.html}
 +        )
 +        || (   $request_path =~ m{^/Search/Simple\.html}
 +            && $HTML::Mason::Commands::DECODED_ARGS->{'q'} )
 +      )
 +    {
 +        my $search = $top->child('search')->child('tickets');
-         my $args      = '';
-         my $has_query = '';
 +        my $current_search = $HTML::Mason::Commands::session{"CurrentSearchHash"} || {};
 +        my $search_id = $HTML::Mason::Commands::DECODED_ARGS->{'SavedSearchLoad'} || $HTML::Mason::Commands::DECODED_ARGS->{'SavedSearchId'} || $current_search->{'SearchId'} || '';
 +        my $chart_id = $HTML::Mason::Commands::DECODED_ARGS->{'SavedChartSearchId'} || $current_search->{SavedChartSearchId};
 +
 +        $has_query = 1 if ( $HTML::Mason::Commands::DECODED_ARGS->{'Query'} or $current_search->{'Query'} );
 +
 +        my %query_args;
 +        my %fallback_query_args = (
 +            SavedSearchId => ( $search_id eq 'new' ) ? undef : $search_id,
 +            SavedChartSearchId => $chart_id,
 +            (
 +                map {
 +                    my $p = $_;
 +                    $p => $HTML::Mason::Commands::DECODED_ARGS->{$p} || $current_search->{$p}
 +                } qw(Query Format OrderBy Order Page)
 +            ),
 +            RowsPerPage => (
 +                defined $HTML::Mason::Commands::DECODED_ARGS->{'RowsPerPage'}
 +                ? $HTML::Mason::Commands::DECODED_ARGS->{'RowsPerPage'}
 +                : $current_search->{'RowsPerPage'}
 +            ),
 +        );
 +
 +        if ($query_string) {
 +            $args = '?' . $query_string;
 +        }
 +        else {
 +            my %final_query_args = ();
 +            # key => callback to avoid unnecessary work
 +
 +            for my $param (keys %fallback_query_args) {
 +                $final_query_args{$param} = defined($query_args->{$param})
 +                                          ? $query_args->{$param}
 +                                          : $fallback_query_args{$param};
 +            }
 +
 +            for my $field (qw(Order OrderBy)) {
 +                if ( ref( $final_query_args{$field} ) eq 'ARRAY' ) {
 +                    $final_query_args{$field} = join( "|", @{ $final_query_args{$field} } );
 +                } elsif (not defined $final_query_args{$field}) {
 +                    delete $final_query_args{$field};
 +                }
 +                else {
 +                    $final_query_args{$field} ||= '';
 +                }
 +            }
 +
 +            $args = '?' . QueryString(%final_query_args);
 +        }
 +
 +        my $current_search_menu;
 +        if ( $request_path =~ m{^/Ticket} ) {
 +            $current_search_menu = $search->child( current_search => title => loc('Current Search') );
 +            $current_search_menu->path("/Search/Results.html$args") if $has_query;
 +        } else {
 +            $current_search_menu = $page;
 +        }
 +
 +        $current_search_menu->child( edit_search =>
 +            title => loc('Edit Search'), path => "/Search/Build.html" . ( ($has_query) ? $args : '' ) );
 +        $current_search_menu->child( advanced =>
 +            title => loc('Advanced'),    path => "/Search/Edit.html$args" );
 +        if ($has_query) {
 +            $current_search_menu->child( results => title => loc('Show Results'), path => "/Search/Results.html$args" );
 +        }
 +
 +        if ( $has_query ) {
 +            $current_search_menu->child( bulk  => title => loc('Bulk Update'), path => "/Search/Bulk.html$args" );
 +            $current_search_menu->child( chart => title => loc('Chart'),       path => "/Search/Chart.html$args" );
 +
 +            my $more = $current_search_menu->child( more => title => loc('Feeds') );
 +
 +            $more->child( spreadsheet => title => loc('Spreadsheet'), path => "/Search/Results.tsv$args" );
 +
 +            my %rss_data = map {
 +                $_ => $query_args->{$_} || $fallback_query_args{$_} || '' }
 +                    qw(Query Order OrderBy);
 +            my $RSSQueryString = "?"
 +                . QueryString( Query   => $rss_data{Query},
 +                                   Order   => $rss_data{Order},
 +                                   OrderBy => $rss_data{OrderBy}
 +                                 );
 +            my $RSSPath = join '/', map $HTML::Mason::Commands::m->interp->apply_escapes( $_, 'u' ),
 +                $current_user->UserObj->Name,
 +                $current_user
 +                ->UserObj->GenerateAuthString(   $rss_data{Query}
 +                                               . $rss_data{Order}
 +                                               . $rss_data{OrderBy} );
 +
 +            $more->child( rss => title => loc('RSS'), path => "/NoAuth/rss/$RSSPath/$RSSQueryString");
 +            my $ical_path = join '/', map $HTML::Mason::Commands::m->interp->apply_escapes($_, 'u'),
 +                $current_user->UserObj->Name,
 +                $current_user->UserObj->GenerateAuthString( $rss_data{Query} ),
 +                $rss_data{Query};
 +            $more->child( ical => title => loc('iCal'), path => '/NoAuth/iCal/'.$ical_path);
 +
 +            if ($request_path =~ m{^/Search/Results.html}
 +                &&                        #XXX TODO better abstraction
 +                $current_user->HasRight( Right => 'SuperUser', Object => RT->System )) {
 +                my $shred_args = QueryString(
 +                    Search          => 1,
 +                    Plugin          => 'Tickets',
 +                    'Tickets:query' => $rss_data{'Query'},
 +                    'Tickets:limit' => $query_args->{'Rows'},
 +                );
 +
 +                $more->child( shredder => title => loc('Shredder'), path => '/Admin/Tools/Shredder/?' . $shred_args);
 +            }
 +
 +        }
 +    }
 +
 +    if ( $request_path =~ m{^/Article/} ) {
 +        if ( $HTML::Mason::Commands::DECODED_ARGS->{'id'} && $HTML::Mason::Commands::DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
 +            my $id = $HTML::Mason::Commands::DECODED_ARGS->{'id'};
 +            $page->child( display => title => loc('Display'), path => "/Articles/Article/Display.html?id=".$id );
 +            $page->child( history => title => loc('History'), path => "/Articles/Article/History.html?id=".$id );
 +            $page->child( modify  => title => loc('Modify'),  path => "/Articles/Article/Edit.html?id=".$id );
 +        }
 +    }
 +
 +    if ( $request_path =~ m{^/Articles/} ) {
 +        $widgets->child( article_search => raw_html => $HTML::Mason::Commands::m->scomp('/Articles/Elements/GotoArticle') );
 +        $widgets->delete('create_ticket');
 +        $widgets->delete('simple_search');
 +
 +        $page->child( search => title => loc("Search"),       path => "/Articles/Article/Search.html" );
 +        $page->child( create => title => loc("New Article" ), path => "/Articles/Article/PreCreate.html" );
 +        if ( $request_path =~ m{^/Articles/Article/} and ( $HTML::Mason::Commands::DECODED_ARGS->{'id'} || '' ) =~ /^(\d+)$/ ) {
 +            my $id  = $1;
 +            my $obj = RT::Article->new( $current_user );
 +            $obj->Load($id);
 +
 +            if ( $obj and $obj->id ) {
 +                $page->child( display => title => loc("Display"), path => "/Articles/Article/Display.html?id=" . $id );
 +                $page->child( history => title => loc('History'), path => '/Articles/Article/History.html?id=' . $id );
 +
 +                if ( $obj->CurrentUserHasRight('ModifyArticle') ) {
 +                    $page->child(modify => title => loc('Modify'), path => '/Articles/Article/Edit.html?id=' . $id );
 +                }
 +            }
 +        }
 +
 +    }
 +
 +    if ($request_path =~ m{^/Asset/} and $HTML::Mason::Commands::DECODED_ARGS->{id} and $HTML::Mason::Commands::DECODED_ARGS->{id} !~ /\D/) {
 +        _BuildAssetMenu( $request_path, $top, $widgets, $page, %args );
 +    } elsif ($request_path =~ m{^/Asset/Search/}) {
 +        my %search = map @{$_},
 +            grep defined $_->[1] && length $_->[1],
 +            map {ref $HTML::Mason::Commands::DECODED_ARGS->{$_} ? [$_, $HTML::Mason::Commands::DECODED_ARGS->{$_}[0]] : [$_, $HTML::Mason::Commands::DECODED_ARGS->{$_}] }
 +            grep /^(?:q|SearchAssets|!?(Name|Description|Catalog|Status|Role\..+|CF\..+)|Order(?:By)?|Page)$/,
 +            keys %$HTML::Mason::Commands::DECODED_ARGS;
 +        if ( $request_path =~ /Bulk/) {
 +            $page->child('search',
 +                title => loc('Show Results'),
 +                path => '/Asset/Search/?' . (keys %search ? QueryString(%search) : ''),
 +            );
 +        } else {
 +            $page->child('bulk',
 +                title => loc('Bulk Update'),
 +                path => '/Asset/Search/Bulk.html?' . (keys %search ? QueryString(%search) : ''),
 +            );
 +        }
 +        $page->child('csv',
 +            title => loc('Download Spreadsheet'),
 +            path  => '/Asset/Search/Results.tsv?' . (keys %search ? QueryString(%search) : ''),
 +        );
 +    } elsif ($request_path =~ m{^/Admin/Global/CustomFields/Catalog-Assets\.html$}) {
 +        $page->child("create", title => loc("Create New"), path => "/Admin/CustomFields/Modify.html?Create=1;LookupType=" . RT::Asset->CustomFieldLookupType);
 +    } elsif ($request_path =~ m{^/Admin/CustomFields(/|/index\.html)?$}
 +            and $HTML::Mason::Commands::DECODED_ARGS->{'Type'} and $HTML::Mason::Commands::DECODED_ARGS->{'Type'} eq RT::Asset->CustomFieldLookupType) {
 +        $page->child("create")->path( $page->child("create")->path . "&LookupType=" . RT::Asset->CustomFieldLookupType );
 +    } elsif ($request_path =~ m{^/Admin/Assets/Catalogs/}) {
 +        my $actions = $request_path =~ m{/((index|Create)\.html)?$}
 +            ? $page
 +            : $page->child("catalogs", title => loc("Catalogs"), path => "/Admin/Assets/Catalogs/");
 +
 +        $actions->child("select", title => loc("Select"), path => "/Admin/Assets/Catalogs/");
 +        $actions->child("create", title => loc("Create"), path => "/Admin/Assets/Catalogs/Create.html");
 +
 +        my $catalog = RT::Catalog->new( $current_user );
 +        $catalog->Load($HTML::Mason::Commands::DECODED_ARGS->{id}) if $HTML::Mason::Commands::DECODED_ARGS->{id};
 +
 +        if ($catalog->id and $catalog->CurrentUserCanSee) {
 +            my $query = "id=" . $catalog->id;
 +            $page->child("modify", title => loc("Basics"), path => "/Admin/Assets/Catalogs/Modify.html?$query");
 +            $page->child("people", title => loc("Roles"),  path => "/Admin/Assets/Catalogs/Roles.html?$query");
 +
 +            $page->child("cfs", title => loc("Asset Custom Fields"), path => "/Admin/Assets/Catalogs/CustomFields.html?$query");
 +
 +            $page->child("group-rights", title => loc("Group Rights"), path => "/Admin/Assets/Catalogs/GroupRights.html?$query");
 +            $page->child("user-rights",  title => loc("User Rights"),  path => "/Admin/Assets/Catalogs/UserRights.html?$query");
 +
 +            $page->child("default-values", title => loc('Default Values'), path => "/Admin/Assets/Catalogs/DefaultValues.html?$query");
 +        }
 +    }
 +
 +    if ( $request_path =~ m{^/User/(Summary|History)\.html} ) {
 +        if ($page->child('summary')) {
 +            # Already set up from having AdminUser and ShowConfigTab;
 +            # but rename "Basics" to "Edit" in this context
 +            $page->child( 'basics' )->title( loc('Edit') );
 +        } elsif ( $current_user->HasRight( Object => $RT::System, Right => 'ShowUserHistory' ) ) {
 +            $page->child( display => title => loc('Summary'), path => '/User/Summary.html?id=' . $HTML::Mason::Commands::DECODED_ARGS->{'id'} );
 +            $page->child( history => title => loc('History'), path => '/User/History.html?id=' . $HTML::Mason::Commands::DECODED_ARGS->{'id'} );
 +        }
 +    }
 +
 +    if ( $request_path =~ /^\/(?:index.html|$)/ ) {
 +        $page->child( edit => title => loc('Edit'), path => '/Prefs/MyRT.html' );
 +    }
 +
 +    # due to historical reasons of always having been in /Elements/Tabs
-     $HTML::Mason::Commands::m->callback( CallbackName => 'Privileged', Path => $request_path, ARGSRef => \%args, CallbackPage => '/Elements/Tabs' );
++    $HTML::Mason::Commands::m->callback( CallbackName => 'Privileged', Path => $request_path, Search_Args => $args, Has_Query => $has_query, ARGSRef => \%args, CallbackPage => '/Elements/Tabs' );
 +}
 +
 +sub _BuildAssetMenu {
 +    my $request_path = shift;
 +    my $top          = shift;
 +    my $widgets      = shift;
 +    my $page         = shift;
 +
 +    my %args = ( @_ );
 +
 +    my $current_user = $HTML::Mason::Commands::session{CurrentUser};
 +
 +    my $id    = $HTML::Mason::Commands::DECODED_ARGS->{id};
 +    my $asset = RT::Asset->new( $current_user );
 +    $asset->Load($id);
 +
 +    if ($asset->id) {
 +        $page->child("display",     title => HTML::Mason::Commands::loc("Display"),        path => "/Asset/Display.html?id=$id");
 +        $page->child("history",     title => HTML::Mason::Commands::loc("History"),        path => "/Asset/History.html?id=$id");
 +        $page->child("basics",      title => HTML::Mason::Commands::loc("Basics"),         path => "/Asset/Modify.html?id=$id");
 +        $page->child("links",       title => HTML::Mason::Commands::loc("Links"),          path => "/Asset/ModifyLinks.html?id=$id");
 +        $page->child("people",      title => HTML::Mason::Commands::loc("People"),         path => "/Asset/ModifyPeople.html?id=$id");
 +        $page->child("dates",       title => HTML::Mason::Commands::loc("Dates"),          path => "/Asset/ModifyDates.html?id=$id");
 +
 +        for my $grouping (RT::CustomField->CustomGroupings($asset)) {
 +            my $cfs = $asset->CustomFields;
 +            $cfs->LimitToGrouping( $asset => $grouping );
 +            next unless $cfs->Count;
 +            $page->child(
 +                "cf-grouping-$grouping",
 +                title   => HTML::Mason::Commands::loc($grouping),
 +                path    => "/Asset/ModifyCFs.html?id=$id;Grouping=" . $HTML::Mason::Commands::m->interp->apply_escapes($grouping, 'u'),
 +            );
 +        }
 +
 +        _BuildAssetMenuActionSubmenu( $request_path, $top, $widgets, $page, %args, Asset => $asset );
 +    }
 +}
 +
 +sub _BuildAssetMenuActionSubmenu {
 +    my $request_path = shift;
 +    my $top          = shift;
 +    my $widgets      = shift;
 +    my $page         = shift;
 +
 +    my %args = (
 +        Asset => undef,
 +        @_
 +    );
 +
 +    my $asset = $args{Asset};
 +    my $id    = $asset->id;
 +
 +    my $actions = $page->child("actions", title => HTML::Mason::Commands::loc("Actions"));
 +    $actions->child("create-linked-ticket", title => HTML::Mason::Commands::loc("Create linked ticket"), path => "/Asset/CreateLinkedTicket.html?Asset=$id");
 +
 +    my $status    = $asset->Status;
 +    my $lifecycle = $asset->LifecycleObj;
 +    for my $action ( $lifecycle->Actions($status) ) {
 +        my $next = $action->{'to'};
 +        next unless $lifecycle->IsTransition( $status => $next );
 +
 +        my $check = $lifecycle->CheckRight( $status => $next );
 +        next unless $asset->CurrentUserHasRight($check);
 +
 +        my $label = $action->{'label'} || ucfirst($next);
 +        $actions->child(
 +            $label,
 +            title   => HTML::Mason::Commands::loc($label),
 +            path    => "/Asset/Modify.html?id=$id;Update=1;DisplayAfter=1;Status="
 +                        . $HTML::Mason::Commands::m->interp->apply_escapes($next, 'u'),
 +
 +            class       => "asset-lifecycle-action",
 +            attributes  => {
 +                'data-current-status'   => $status,
 +                'data-next-status'      => $next,
 +            },
 +        );
 +    }
 +}
 +
 +sub _BuildAdminMenu {
 +    my $request_path = shift;
 +    my $top          = shift;
 +    my $widgets      = shift;
 +    my $page         = shift;
 +
 +    my %args = ( @_ );
 +
 +    my $current_user = $HTML::Mason::Commands::session{CurrentUser};
 +
 +    my $admin = $top->child( admin => title => loc('Admin'), path => '/Admin/' );
 +    if ( $current_user->HasRight( Object => RT->System, Right => 'AdminUsers' ) ) {
 +        my $users = $admin->child( users =>
 +            title       => loc('Users'),
 +            description => loc('Manage users and passwords'),
 +            path        => '/Admin/Users/',
 +        );
 +        $users->child( select => title => loc('Select'), path => "/Admin/Users/" );
 +        $users->child( create => title => loc('Create'), path => "/Admin/Users/Modify.html?Create=1" );
 +    }
 +    my $groups = $admin->child( groups =>
 +        title       => loc('Groups'),
 +        description => loc('Manage groups and group membership'),
 +        path        => '/Admin/Groups/',
 +    );
 +    $groups->child( select => title => loc('Select'), path => "/Admin/Groups/" );
 +    $groups->child( create => title => loc('Create'), path => "/Admin/Groups/Modify.html?Create=1" );
 +
 +    my $queues = $admin->child( queues =>
 +        title       => loc('Queues'),
 +        description => loc('Manage queues and queue-specific properties'),
 +        path        => '/Admin/Queues/',
 +    );
 +    $queues->child( select => title => loc('Select'), path => "/Admin/Queues/" );
 +    $queues->child( create => title => loc('Create'), path => "/Admin/Queues/Modify.html?Create=1" );
 +
 +    if ( $current_user->HasRight( Object => RT->System, Right => 'AdminCustomField' ) ) {
 +        my $cfs = $admin->child( 'custom-fields' =>
 +            title       => loc('Custom Fields'),
 +            description => loc('Manage custom fields and custom field values'),
 +            path        => '/Admin/CustomFields/',
 +        );
 +        $cfs->child( select => title => loc('Select'), path => "/Admin/CustomFields/" );
 +        $cfs->child( create => title => loc('Create'), path => "/Admin/CustomFields/Modify.html?Create=1" );
 +    }
 +
 +    if ( $current_user->HasRight( Object => RT->System, Right => 'AdminCustomRoles' ) ) {
 +        my $roles = $admin->child( 'custom-roles' =>
 +            title       => loc('Custom Roles'),
 +            description => loc('Manage custom roles'),
 +            path        => '/Admin/CustomRoles/',
 +        );
 +        $roles->child( select => title => loc('Select'), path => "/Admin/CustomRoles/" );
 +        $roles->child( create => title => loc('Create'), path => "/Admin/CustomRoles/Modify.html?Create=1" );
 +    }
 +
 +    if ( $current_user->HasRight( Object => RT->System, Right => 'ModifyScrips' ) ) {
 +        my $scrips = $admin->child( 'scrips' =>
 +            title       => loc('Scrips'),
 +            description => loc('Manage scrips'),
 +            path        => '/Admin/Scrips/',
 +        );
 +        $scrips->child( select => title => loc('Select'), path => "/Admin/Scrips/" );
 +        $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html" );
 +    }
 +
 +    my $admin_global = $admin->child( global =>
 +        title       => loc('Global'),
 +        description => loc('Manage properties and configuration which apply to all queues'),
 +        path        => '/Admin/Global/',
 +    );
 +
 +    my $scrips = $admin_global->child( scrips =>
 +        title       => loc('Scrips'),
 +        description => loc('Modify scrips which apply to all queues'),
 +        path        => '/Admin/Global/Scrips.html',
 +    );
 +    $scrips->child( select => title => loc('Select'), path => "/Admin/Global/Scrips.html" );
 +    $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html?Global=1" );
 +
 +    my $templates = $admin_global->child( templates =>
 +        title       => loc('Templates'),
 +        description => loc('Edit system templates'),
 +        path        => '/Admin/Global/Templates.html',
 +    );
 +    $templates->child( select => title => loc('Select'), path => "/Admin/Global/Templates.html" );
 +    $templates->child( create => title => loc('Create'), path => "/Admin/Global/Template.html?Create=1" );
 +
 +    my $cfadmin = $admin_global->child( 'custom-fields' =>
 +        title       => loc('Custom Fields'),
 +        description => loc('Modify global custom fields'),
 +        path        => '/Admin/Global/CustomFields/index.html',
 +    );
 +    $cfadmin->child( users =>
 +        title       => loc('Users'),
 +        description => loc('Select custom fields for all users'),
 +        path        => '/Admin/Global/CustomFields/Users.html',
 +    );
 +    $cfadmin->child( groups =>
 +        title       => loc('Groups'),
 +        description => loc('Select custom fields for all user groups'),
 +        path        => '/Admin/Global/CustomFields/Groups.html',
 +    );
 +    $cfadmin->child( queues =>
 +        title       => loc('Queues'),
 +        description => loc('Select custom fields for all queues'),
 +        path        => '/Admin/Global/CustomFields/Queues.html',
 +    );
 +    $cfadmin->child( tickets =>
 +        title       => loc('Tickets'),
 +        description => loc('Select custom fields for tickets in all queues'),
 +        path        => '/Admin/Global/CustomFields/Queue-Tickets.html',
 +    );
 +    $cfadmin->child( transactions =>
 +        title       => loc('Ticket Transactions'),
 +        description => loc('Select custom fields for transactions on tickets in all queues'),
 +        path        => '/Admin/Global/CustomFields/Queue-Transactions.html',
 +    );
 +    $cfadmin->child( 'custom-fields' =>
 +        title       => loc('Articles'),
 +        description => loc('Select Custom Fields for Articles in all Classes'),
 +        path        => '/Admin/Global/CustomFields/Class-Article.html',
 +    );
 +    $cfadmin->child( 'assets' =>
 +        title       => loc('Assets'),
 +        description => loc('Select Custom Fields for Assets in all Catalogs'),
 +        path        => '/Admin/Global/CustomFields/Catalog-Assets.html',
 +    );
 +
 +    my $article_admin = $admin->child( articles => title => loc('Articles'), path => "/Admin/Articles/index.html" );
 +    my $class_admin = $article_admin->child(classes => title => loc('Classes'), path => '/Admin/Articles/Classes/' );
 +    $class_admin->child( select =>
 +        title       => loc('Select'),
 +        description => loc('Modify and Create Classes'),
 +        path        => '/Admin/Articles/Classes/',
 +    );
 +    $class_admin->child( create =>
 +        title       => loc('Create'),
 +        description => loc('Modify and Create Custom Fields for Articles'),
 +        path        => '/Admin/Articles/Classes/Modify.html?Create=1',
 +    );
 +
 +
 +    my $cfs = $article_admin->child( 'custom-fields' =>
 +        title => loc('Custom Fields'),
 +        path  => '/Admin/CustomFields/index.html?'.$HTML::Mason::Commands::m->comp('/Elements/QueryString', Type => 'RT::Class-RT::Article'),
 +    );
 +    $cfs->child( select =>
 +        title => loc('Select'),
 +        path => '/Admin/CustomFields/index.html?'.$HTML::Mason::Commands::m->comp('/Elements/QueryString', Type => 'RT::Class-RT::Article'),
 +    );
 +    $cfs->child( create =>
 +        title => loc('Create'),
 +        path => '/Admin/CustomFields/Modify.html?'.$HTML::Mason::Commands::m->comp("/Elements/QueryString", Create=>1, LookupType=> "RT::Class-RT::Article" ),
 +    );
 +
 +    my $assets_admin = $admin->child( assets => title => loc("Assets"), path => '/Admin/Assets/' );
 +    my $catalog_admin = $assets_admin->child( catalogs =>
 +        title       => loc("Catalogs"),
 +        description => loc("Modify asset catalogs"),
 +        path        => "/Admin/Assets/Catalogs/"
 +    );
 +    $catalog_admin->child( "select", title => loc("Select"), path => $catalog_admin->path );
 +    $catalog_admin->child( "create", title => loc("Create"), path => "Create.html" );
 +
 +
 +    my $assets_cfs = $assets_admin->child( "cfs",
 +        title => loc("Custom Fields"),
 +        description => loc("Modify asset custom fields"),
 +        path => "/Admin/CustomFields/?Type=" . RT::Asset->CustomFieldLookupType
 +    );
 +    $assets_cfs->child( "select", title => loc("Select"), path => $assets_cfs->path );
 +    $assets_cfs->child( "create", title => loc("Create"), path => "/Admin/CustomFields/Modify.html?Create=1&LookupType=" . RT::Asset->CustomFieldLookupType);
 +
 +    $admin_global->child( 'group-rights' =>
 +        title       => loc('Group Rights'),
 +        description => loc('Modify global group rights'),
 +        path        => '/Admin/Global/GroupRights.html',
 +    );
 +    $admin_global->child( 'user-rights' =>
 +        title       => loc('User Rights'),
 +        description => loc('Modify global user rights'),
 +        path        => '/Admin/Global/UserRights.html',
 +    );
 +    $admin_global->child( 'my-rt' =>
 +        title       => loc('RT at a glance'),
 +        description => loc('Modify the default "RT at a glance" view'),
 +        path        => '/Admin/Global/MyRT.html',
 +    );
 +    $admin_global->child( 'dashboards-in-menu' =>
 +        title       => loc('Dashboards in menu'),
 +        description => loc('Customize dashboards in menu'),
 +        path        => '/Admin/Global/DashboardsInMenu.html',
 +    );
 +    $admin_global->child( 'topics' =>
 +        title       => loc('Topics'),
 +        description => loc('Modify global article topics'),
 +        path        => '/Admin/Global/Topics.html',
 +    );
 +
 +    my $admin_tools = $admin->child( tools =>
 +        title       => loc('Tools'),
 +        description => loc('Use other RT administrative tools'),
 +        path        => '/Admin/Tools/',
 +    );
 +    $admin_tools->child( configuration =>
 +        title       => loc('System Configuration'),
 +        description => loc('Detailed information about your RT setup'),
 +        path        => '/Admin/Tools/Configuration.html',
 +    );
 +    $admin_tools->child( theme =>
 +        title       => loc('Theme'),
 +        description => loc('Customize the look of your RT'),
 +        path        => '/Admin/Tools/Theme.html',
 +    );
 +    if (RT->Config->Get('StatementLog')
 +        && $current_user->HasRight( Right => 'SuperUser', Object => RT->System )) {
 +       $admin_tools->child( 'sql-queries' =>
 +           title       => loc('SQL Queries'),
 +           description => loc('Browse the SQL queries made in this process'),
 +           path        => '/Admin/Tools/Queries.html',
 +       );
 +    }
 +    $admin_tools->child( shredder =>
 +        title       => loc('Shredder'),
 +        description => loc('Permanently wipeout data from RT'),
 +        path        => '/Admin/Tools/Shredder',
 +    );
 +
 +    if ( $request_path =~ m{^/Admin/(Queues|Users|Groups|CustomFields|CustomRoles)} ) {
 +        my $type = $1;
  
 -        my %query_args;
 -        my %fallback_query_args = (
 -            SavedSearchId => ( $search_id eq 'new' ) ? undef : $search_id,
 -            SavedChartSearchId => $chart_id,
 -            (
 -                map {
 -                    my $p = $_;
 -                    $p => $DECODED_ARGS->{$p} || $current_search->{$p}
 -                } qw(Query Format OrderBy Order Page)
 -            ),
 -            RowsPerPage => (
 -                defined $DECODED_ARGS->{'RowsPerPage'}
 -                ? $DECODED_ARGS->{'RowsPerPage'}
 -                : $current_search->{'RowsPerPage'}
 -            ),
 +        my %labels = (
 +            Queues       => loc("Queues"),
 +            Users        => loc("Users"),
 +            Groups       => loc("Groups"),
 +            CustomFields => loc("Custom Fields"),
 +            CustomRoles  => loc("Custom Roles"),
          );
  
 -        if ($QueryString) {
 -            $args = '?' . $QueryString;
 -        }
 -        else {
 -            my %final_query_args = ();
 -            # key => callback to avoid unnecessary work
 -
 -            for my $param (keys %fallback_query_args) {
 -                $final_query_args{$param} = defined($QueryArgs->{$param})
 -                                          ? $QueryArgs->{$param}
 -                                          : $fallback_query_args{$param};
 -            }
 -
 -            for my $field (qw(Order OrderBy)) {
 -                if ( ref( $final_query_args{$field} ) eq 'ARRAY' ) {
 -                    $final_query_args{$field} = join( "|", @{ $final_query_args{$field} } );
 -                } elsif (not defined $final_query_args{$field}) {
 -                    delete $final_query_args{$field};
 -                }
 -                else {
 -                    $final_query_args{$field} ||= '';
 -                }
 -            }
 -
 -            $args = '?' . $query_string->(%final_query_args);
 -        }
 +        my $section;
 +        if ( $request_path =~ m|^/Admin/$type/?(?:index.html)?$|
 +             || (    $request_path =~ m|^/Admin/$type/(?:Modify.html)$|
 +                  && $HTML::Mason::Commands::DECODED_ARGS->{'Create'} )
 +           )
 +        {
 +            $section = $page;
  
 -        my $current_search_menu;
 -        if ( $request_path =~ m{^/Ticket} ) {
 -            $current_search_menu = $search->child( current_search => title => loc('Current Search') );
 -            $current_search_menu->path("/Search/Results.html$args") if $has_query;
          } else {
 -            $current_search_menu = PageMenu();
 +            $section = $page->child( select => title => $labels{$type},
 +                                     path => "/Admin/$type/" );
          }
  
 -        $current_search_menu->child( edit_search =>
 -            title => loc('Edit Search'), path => "/Search/Build.html" . ( ($has_query) ? $args : '' ) );
 -        $current_search_menu->child( advanced =>
 -            title => loc('Advanced'),    path => "/Search/Edit.html$args" );
 -        if ($has_query) {
 -            $current_search_menu->child( results => title => loc('Show Results'), path => "/Search/Results.html$args" );
 -        }
 +        $section->child( select => title => loc('Select'), path => "/Admin/$type/" );
 +        $section->child( create => title => loc('Create'), path => "/Admin/$type/Modify.html?Create=1" );
 +    }
  
 -        if ( $has_query ) {
 -            $current_search_menu->child( bulk  => title => loc('Bulk Update'), path => "/Search/Bulk.html$args" );
 -            $current_search_menu->child( chart => title => loc('Chart'),       path => "/Search/Chart.html$args" );
 +    if ( $request_path =~ m{^/Admin/Queues} ) {
 +        if ( $HTML::Mason::Commands::DECODED_ARGS->{'id'} && $HTML::Mason::Commands::DECODED_ARGS->{'id'} =~ /^\d+$/
 +                ||
 +              $HTML::Mason::Commands::DECODED_ARGS->{'Queue'} && $HTML::Mason::Commands::DECODED_ARGS->{'Queue'} =~ /^\d+$/
 +                ) {
 +            my $id = $HTML::Mason::Commands::DECODED_ARGS->{'Queue'} || $HTML::Mason::Commands::DECODED_ARGS->{'id'};
 +            my $queue_obj = RT::Queue->new( $current_user );
 +            $queue_obj->Load($id);
  
 -            my $more = $current_search_menu->child( more => title => loc('Feeds') );
 +            if ( $queue_obj and $queue_obj->id ) {
 +                my $queue = $page;
 +                $queue->child( basics => title => loc('Basics'),   path => "/Admin/Queues/Modify.html?id=" . $id );
 +                $queue->child( people => title => loc('Watchers'), path => "/Admin/Queues/People.html?id=" . $id );
  
 -            $more->child( spreadsheet => title => loc('Spreadsheet'), path => "/Search/Results.tsv$args" );
 +                my $templates = $queue->child(templates => title => loc('Templates'), path => "/Admin/Queues/Templates.html?id=" . $id);
 +                $templates->child( select => title => loc('Select'), path => "/Admin/Queues/Templates.html?id=".$id);
 +                $templates->child( create => title => loc('Create'), path => "/Admin/Queues/Template.html?Create=1;Queue=".$id);
  
 -            my %rss_data = map {
 -                $_ => $QueryArgs->{$_} || $fallback_query_args{$_} || '' }
 -                    qw(Query Order OrderBy);
 -            my $RSSQueryString = "?"
 -                . $query_string->( Query   => $rss_data{Query},
 -                                   Order   => $rss_data{Order},
 -                                   OrderBy => $rss_data{OrderBy}
 -                                 );
 -            my $RSSPath = join '/', map $m->interp->apply_escapes( $_, 'u' ),
 -                $session{'CurrentUser'}->UserObj->Name,
 -                $session{'CurrentUser'}
 -                ->UserObj->GenerateAuthString(   $rss_data{Query}
 -                                               . $rss_data{Order}
 -                                               . $rss_data{OrderBy} );
 +                my $scrips = $queue->child( scrips => title => loc('Scrips'), path => "/Admin/Queues/Scrips.html?id=" . $id);
 +                $scrips->child( select => title => loc('Select'), path => "/Admin/Queues/Scrips.html?id=" . $id );
 +                $scrips->child( create => title => loc('Create'), path => "/Admin/Scrips/Create.html?Queue=" . $id);
  
 -            $more->child( rss => title => loc('RSS'), path => "/NoAuth/rss/$RSSPath/$RSSQueryString");
 -            my $ical_path = join '/', map $m->interp->apply_escapes($_, 'u'),
 -                $session{'CurrentUser'}->UserObj->Name,
 -                $session{'CurrentUser'}->UserObj->GenerateAuthString( $rss_data{Query} ),
 -                $rss_data{Query};
 -            $more->child( ical => title => loc('iCal'), path => '/NoAuth/iCal/'.$ical_path);
 +                my $cfs = $queue->child( 'custom-fields' => title => loc('Custom Fields') );
 +                my $ticket_cfs = $cfs->child( 'tickets' => title => loc('Tickets'),
 +                    path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket&id=' . $id );
  
 -            if ($request_path =~ m{^/Search/Results.html}
 -                &&                        #XXX TODO better abstraction
 -                $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System )) {
 -                my $shred_args = $query_string->(
 -                    Search          => 1,
 -                    Plugin          => 'Tickets',
 -                    'Tickets:query' => $rss_data{'Query'},
 -                    'Tickets:limit' => $QueryArgs->{'Rows'},
 -                );
 +                my $txn_cfs = $cfs->child( 'transactions' => title => loc('Transactions'),
 +                    path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket-RT::Transaction&id='.$id );
  
 -                $more->child( shredder => title => loc('Shredder'), path => '/Admin/Tools/Shredder/?' . $shred_args);
 +                $queue->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Queues/GroupRights.html?id=".$id );
 +                $queue->child( 'user-rights' => title => loc('User Rights'), path => "/Admin/Queues/UserRights.html?id=" . $id );
 +                $queue->child( 'history' => title => loc('History'), path => "/Admin/Queues/History.html?id=" . $id );
 +                $queue->child( 'default-values' => title => loc('Default Values'), path => "/Admin/Queues/DefaultValues.html?id=" . $id );
 +
 +                # due to historical reasons of always having been in /Elements/Tabs
 +                $HTML::Mason::Commands::m->callback( CallbackName => 'PrivilegedQueue', queue_id => $id, page_menu => $queue, CallbackPage => '/Elements/Tabs' );
              }
 +        }
 +    }
 +    if ( $request_path =~ m{^(/Admin/Users|/User/(Summary|History)\.html)} and $admin->child("users") ) {
 +        if ( $HTML::Mason::Commands::DECODED_ARGS->{'id'} && $HTML::Mason::Commands::DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
 +            my $id = $HTML::Mason::Commands::DECODED_ARGS->{'id'};
 +            my $obj = RT::User->new( $current_user );
 +            $obj->Load($id);
  
 +            if ( $obj and $obj->id ) {
 +                $page->child( basics      => title => loc('Basics'),         path => "/Admin/Users/Modify.html?id=" . $id );
 +                $page->child( memberships => title => loc('Memberships'),    path => "/Admin/Users/Memberships.html?id=" . $id );
 +                $page->child( history     => title => loc('History'),        path => "/Admin/Users/History.html?id=" . $id );
 +                $page->child( 'my-rt'     => title => loc('RT at a glance'), path => "/Admin/Users/MyRT.html?id=" . $id );
 +                $page->child( 'dashboards-in-menu' =>
 +                    title => loc('Dashboards in menu'),
 +                    path  => '/Admin/Users/DashboardsInMenu.html?id=' . $id,
 +                );
 +                if ( RT->Config->Get('Crypt')->{'Enable'} ) {
 +                    $page->child( keys    => title => loc('Private keys'),   path => "/Admin/Users/Keys.html?id=" . $id );
 +                }
 +                $page->child( 'summary'   => title => loc('User Summary'),   path => "/User/Summary.html?id=" . $id );
 +            }
          }
 +
      }
  
 -    if ( $request_path =~ m{^/Article/} ) {
 -        if ( $DECODED_ARGS->{'id'} && $DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
 -            my $id = $DECODED_ARGS->{'id'};
 -            my $tabs = PageMenu();
 +    if ( $request_path =~ m{^/Admin/Groups} ) {
 +        if ( $HTML::Mason::Commands::DECODED_ARGS->{'id'} && $HTML::Mason::Commands::DECODED_ARGS->{'id'} =~ /^\d+$/ ) {
 +            my $id = $HTML::Mason::Commands::DECODED_ARGS->{'id'};
 +            my $obj = RT::Group->new( $current_user );
 +            $obj->Load($id);
  
 -            $tabs->child( display => title => loc('Display'), path => "/Articles/Article/Display.html?id=".$id );
 -            $tabs->child( history => title => loc('History'), path => "/Articles/Article/History.html?id=".$id );
 -            $tabs->child( modify  => title => loc('Modify'),  path => "/Articles/Article/Edit.html?id=".$id );
 +            if ( $obj and $obj->id ) {
 +                $page->child( basics         => title => loc('Basics'),       path => "/Admin/Groups/Modify.html?id=" . $obj->id );
 +                $page->child( members        => title => loc('Members'),      path => "/Admin/Groups/Members.html?id=" . $obj->id );
 +                $page->child( memberships    => title => loc('Memberships'),  path => "/Admin/Groups/Memberships.html?id=" . $obj->id );
 +                $page->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Groups/GroupRights.html?id=" . $obj->id );
 +                $page->child( 'user-rights'  => title => loc('User Rights'),  path => "/Admin/Groups/UserRights.html?id=" . $obj->id );
 +                $page->child( history        => title => loc('History'),      path => "/Admin/Groups/History.html?id=" . $obj->id );
 +            }
          }
      }
  

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


More information about the rt-commit mailing list