Initial commit 4.0.5-3
[usit-rt.git] / share / html / Elements / Tabs
1 %# BEGIN BPS TAGGED BLOCK {{{
2 %#
3 %# COPYRIGHT:
4 %#
5 %# This software is Copyright (c) 1996-2012 Best Practical Solutions, LLC
6 %#                                          <sales@bestpractical.com>
7 %#
8 %# (Except where explicitly superseded by other copyright notices)
9 %#
10 %#
11 %# LICENSE:
12 %#
13 %# This work is made available to you under the terms of Version 2 of
14 %# the GNU General Public License. A copy of that license should have
15 %# been provided with this software, but in any event can be snarfed
16 %# from www.gnu.org.
17 %#
18 %# This work is distributed in the hope that it will be useful, but
19 %# WITHOUT ANY WARRANTY; without even the implied warranty of
20 %# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 %# General Public License for more details.
22 %#
23 %# You should have received a copy of the GNU General Public License
24 %# along with this program; if not, write to the Free Software
25 %# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 %# 02110-1301 or visit their web page on the internet at
27 %# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28 %#
29 %#
30 %# CONTRIBUTION SUBMISSION POLICY:
31 %#
32 %# (The following paragraph is not intended to limit the rights granted
33 %# to you to modify and distribute this software under the terms of
34 %# the GNU General Public License and is only of importance to you if
35 %# you choose to contribute your changes and enhancements to the
36 %# community by submitting them to Best Practical Solutions, LLC.)
37 %#
38 %# By intentionally submitting any modifications, corrections or
39 %# derivatives to this work, or any other work intended for use with
40 %# Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 %# you are the copyright holder for those contributions and you grant
42 %# Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43 %# royalty-free, perpetual, license to use, copy, create derivative
44 %# works based on those contributions, and sublicense and distribute
45 %# those contributions and any derivatives thereof.
46 %#
47 %# END BPS TAGGED BLOCK }}}
48 <& /Elements/PageLayout, show_menu => $show_menu &>
49 <a name="skipnav" id="skipnav" accesskey="8"></a>
50 <%INIT>
51
52 my $request_path = $HTML::Mason::Commands::r->path_info;
53
54 my $query_string = sub {
55     my %args = @_;
56     my $u    = URI->new();
57     $u->query_form(%args);
58     return $u->query;
59 };
60
61 my $build_admin_menu = sub {
62     my $top = shift;
63     my $admin = $top->child( config => title => loc('Configuration'), path => '/Admin/', sort_order => 99 );
64     if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminUsers' ) ) {
65         my $users = $admin->child( users =>
66             title       => loc('Users'),
67             description => loc('Manage users and passwords'),
68             path        => '/Admin/Users/',
69         );
70         $users->child( select => title => loc('Select'), path => "/Admin/Users/" );
71         $users->child( create => title => loc('Create'), path => "/Admin/Users/Modify.html?Create=1" );
72     }
73     my $groups = $admin->child( groups =>
74         title       => loc('Groups'),
75         description => loc('Manage groups and group membership'),
76         path        => '/Admin/Groups/',
77     );
78     $groups->child( select => title => loc('Select'), path => "/Admin/Groups/" );
79     $groups->child( create => title => loc('Create'), path => "/Admin/Groups/Modify.html?Create=1" );
80
81     my $queues = $admin->child( queues =>
82         title       => loc('Queues'),
83         description => loc('Manage queues and queue-specific properties'),
84         path        => '/Admin/Queues/',
85     );
86     $queues->child( select => title => loc('Select'), path => "/Admin/Queues/" );
87     $queues->child( create => title => loc('Create'), path => "/Admin/Queues/Modify.html?Create=1" );
88
89     if ( $session{'CurrentUser'}->HasRight( Object => RT->System, Right => 'AdminCustomField' ) ) {
90         my $cfs = $admin->child( 'custom-fields' =>
91             title       => loc('Custom Fields'),
92             description => loc('Manage custom fields and custom field values'),
93             path        => '/Admin/CustomFields/',
94         );
95         $cfs->child( select => title => loc('Select'), path => "/Admin/CustomFields/" );
96         $cfs->child( create => title => loc('Create'), path => "/Admin/CustomFields/Modify.html?Create=1" );
97     }
98
99     my $admin_global = $admin->child( global =>
100         title       => loc('Global'),
101         description => loc('Manage properties and configuration which apply to all queues'),
102         path        => '/Admin/Global/',
103     );
104
105     my $scrips = $admin_global->child( scrips =>
106         title       => loc('Scrips'),
107         description => loc('Modify scrips which apply to all queues'),
108         path        => '/Admin/Global/Scrips.html',
109     );
110     $scrips->child( select => title => loc('Select'), path => "/Admin/Global/Scrips.html" );
111     $scrips->child( create => title => loc('Create'), path => "/Admin/Global/Scrip.html?Create=1" );
112
113     my $templates = $admin_global->child( templates =>
114         title       => loc('Templates'),
115         description => loc('Edit system templates'),
116         path        => '/Admin/Global/Templates.html',
117     );
118     $templates->child( select => title => loc('Select'), path => "/Admin/Global/Templates.html" );
119     $templates->child( create => title => loc('Create'), path => "/Admin/Global/Template.html?Create=1" );
120
121     my $cfadmin = $admin_global->child( 'custom-fields' =>
122         title       => loc('Custom Fields'),
123         description => loc('Modify global custom fields'),
124         path        => '/Admin/Global/CustomFields/index.html',
125     );
126     $cfadmin->child( users =>
127         title       => loc('Users'),
128         description => loc('Select custom fields for all users'),
129         path        => '/Admin/Global/CustomFields/Users.html',
130     );
131     $cfadmin->child( groups =>
132         title       => loc('Groups'),
133         description => loc('Select custom fields for all user groups'),
134         path        => '/Admin/Global/CustomFields/Groups.html',
135     );
136     $cfadmin->child( queues =>
137         title       => loc('Queues'),
138         description => loc('Select custom fields for all queues'),
139         path        => '/Admin/Global/CustomFields/Queues.html',
140     );
141     $cfadmin->child( tickets =>
142         title       => loc('Tickets'),
143         description => loc('Select custom fields for tickets in all queues'),
144         path        => '/Admin/Global/CustomFields/Queue-Tickets.html',
145     );
146     $cfadmin->child( transactions =>
147         title       => loc('Ticket Transactions'),
148         description => loc('Select custom fields for transactions on tickets in all queues'),
149         path        => '/Admin/Global/CustomFields/Queue-Transactions.html',
150     );
151     $cfadmin->child( 'custom-fields' =>
152         title       => loc('Articles'),
153         description => loc('Select Custom Fields for Articles in all Classes'),
154         path        => '/Admin/Global/CustomFields/Class-Article.html',
155     );
156
157     my $article_admin = $admin->child( articles => title => loc('Articles'), path => "/Admin/Articles/index.html" );
158     my $class_admin = $article_admin->child(classes => title => loc('Classes'), path => '/Admin/Articles/Classes/' );
159     $class_admin->child( select =>
160         title       => loc('Select'),
161         description => loc('Modify and Create Classes'),
162         path        => '/Admin/Articles/Classes/',
163     );
164     $class_admin->child( create =>
165         title       => loc('Create'),
166         description => loc('Modify and Create Custom Fields for Articles'),
167         path        => '/Admin/Articles/Classes/Modify.html?Create=1',
168     );
169
170
171     my $cfs = $article_admin->child( 'custom-fields' =>
172         title => loc('Custom Fields'),
173         path  => '/Admin/CustomFields/index.html?'.$m->comp('/Elements/QueryString', type => 'RT::Class-RT::Article'),
174     );
175     $cfs->child( select =>
176         title => loc('Select'),
177         path => '/Admin/CustomFields/index.html?'.$m->comp('/Elements/QueryString', type => 'RT::Class-RT::Article'),
178     );
179     $cfs->child( create =>
180         title => loc('Create'),
181         path => '/Admin/CustomFields/Modify.html?'.$m->comp("/Elements/QueryString", Create=>1, LookupType=> "RT::Class-RT::Article" ),
182     );
183
184     $admin_global->child( 'group-rights' =>
185         title       => loc('Group Rights'),
186         description => loc('Modify global group rights'),
187         path        => '/Admin/Global/GroupRights.html',
188     );
189     $admin_global->child( 'user-rights' =>
190         title       => loc('User Rights'),
191         description => loc('Modify global user rights'),
192         path        => '/Admin/Global/UserRights.html',
193     );
194     $admin_global->child( 'my-rt' =>
195         title       => loc('RT at a glance'),
196         description => loc('Modify the default "RT at a glance" view'),
197         path        => '/Admin/Global/MyRT.html',
198     );
199     $admin_global->child( 'topics' =>
200         title       => loc('Topics'),
201         description => loc('Modify global article topics'),
202         path        => '/Admin/Global/Topics.html',
203     );
204
205     my $admin_tools = $admin->child( tools =>
206         title       => loc('Tools'),
207         description => loc('Use other RT administrative tools'),
208         path        => '/Admin/Tools/',
209     );
210     $admin_tools->child( configuration =>
211         title       => loc('System Configuration'),
212         description => loc('Detailed information about your RT setup'),
213         path        => '/Admin/Tools/Configuration.html',
214     );
215     $admin_tools->child( theme =>
216         title       => loc('Theme'),
217         description => loc('Customize the look of your RT'),
218         path        => '/Admin/Tools/Theme.html',
219     );
220     if (RT->Config->Get('StatementLog')
221         && $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System )) {
222        $admin_tools->child( 'sql-queries' =>
223            title       => loc('SQL Queries'),
224            description => loc('Browse the SQL queries made in this process'),
225            path        => '/Admin/Tools/Queries.html',
226        );
227     }
228     $admin_tools->child( shredder =>
229         title       => loc('Shredder'),
230         description => loc('Permanently wipeout data from RT'),
231         path        => '/Admin/Tools/Shredder',
232     );
233
234     if ( $request_path =~ m{^/Admin/(Queues|Users|Groups|CustomFields)} ) {
235         my $type = $1;
236         my $tabs = PageMenu();
237
238         my %labels = (
239             Queues       => loc("Queues"),
240             Users        => loc("Users"),
241             Groups       => loc("Groups"),
242             CustomFields => loc("Custom Fields"),
243         );
244
245         my $section;
246         if ( $request_path =~ m|^/Admin/$type/?(?:index.html)?$|
247              || (    $request_path =~ m|^/Admin/$type/(?:Modify.html)$|
248                   && $m->request_args->{'Create'} )
249            )
250         {
251             $section = $tabs;
252
253         } else {
254             $section = $tabs->child( select => title => $labels{$type},
255                                      path => "/Admin/$type/" );
256         }
257
258         $section->child( select => title => loc('Select'), path => "/Admin/$type/" );
259         $section->child( create => title => loc('Create'), path => "/Admin/$type/Modify.html?Create=1" );
260     }
261
262     if ( $request_path =~ m{^/Admin/Queues} ) {
263         if ( $m->request_args->{'id'} && $m->request_args->{'id'} =~ /^\d+$/
264                 ||
265               $m->request_args->{'Queue'} && $m->request_args->{'Queue'} =~ /^\d+$/
266                 ) {
267             my $id = $m->request_args->{'Queue'} || $m->request_args->{'id'};
268             my $queue_obj = RT::Queue->new( $session{'CurrentUser'} );
269             $queue_obj->Load($id);
270
271             my $queue = PageMenu();
272             $queue->child( basics => title => loc('Basics'),   path => "/Admin/Queues/Modify.html?id=" . $id );
273             $queue->child( people => title => loc('Watchers'), path => "/Admin/Queues/People.html?id=" . $id );
274
275             my $templates = $queue->child(templates => title => loc('Templates'), path => "/Admin/Queues/Templates.html?id=" . $id);
276             $templates->child( select => title => loc('Select'), path => "/Admin/Queues/Templates.html?id=".$id);
277             $templates->child( create => title => loc('Create'), path => "/Admin/Queues/Template.html?Create=1;Queue=".$id);
278
279             my $scrips = $queue->child( scrips => title => loc('Scrips'), path => "/Admin/Queues/Scrips.html?id=" . $id);
280             $scrips->child( select => title => loc('Select'), path => "/Admin/Queues/Scrips.html?id=" . $id );
281             $scrips->child( create => title => loc('Create'), path => "/Admin/Queues/Scrip.html?Create=1;Queue=" . $id);
282
283             my $ticket_cfs = $queue->child( 'ticket-custom-fields' => title => loc('Ticket Custom Fields'),
284                 path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket&id=' . $id );
285
286             my $txn_cfs = $queue->child( 'transaction-custom-fields' => title => loc('Transaction Custom Fields'),
287                 path => '/Admin/Queues/CustomFields.html?SubType=RT::Ticket-RT::Transaction&id='.$id );
288
289             $queue->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Queues/GroupRights.html?id=".$id );
290             $queue->child( 'user-rights' => title => loc('User Rights'), path => "/Admin/Queues/UserRights.html?id=" . $id );
291
292
293             $m->callback( CallbackName => 'PrivilegedQueue', queue_id => $id, page_menu => $queue);
294         }
295     }
296     if ( $request_path =~ m{^/Admin/Users} ) {
297         if ( $m->request_args->{'id'} && $m->request_args->{'id'} =~ /^\d+$/ ) {
298             my $id = $m->request_args->{'id'};
299             my $obj = RT::User->new( $session{'CurrentUser'} );
300             $obj->Load($id);
301
302             my $tabs = PageMenu();
303             $tabs->child( basics      => title => loc('Basics'),         path => "/Admin/Users/Modify.html?id=" . $id );
304             $tabs->child( memberships => title => loc('Memberships'),    path => "/Admin/Users/Memberships.html?id=" . $id );
305             $tabs->child( history     => title => loc('History'),        path => "/Admin/Users/History.html?id=" . $id );
306             $tabs->child( 'my-rt'     => title => loc('RT at a glance'), path => "/Admin/Users/MyRT.html?id=" . $id );
307             if ( RT->Config->Get('GnuPG')->{'Enable'} ) {
308                 $tabs->child( pgp     => title => loc('GnuPG'),          path => "/Admin/Users/GnuPG.html?id=" . $id );
309             }
310         }
311
312     }
313
314     if ( $request_path =~ m{^/Admin/Groups} ) {
315         if ( $m->request_args->{'id'} && $m->request_args->{'id'} =~ /^\d+$/ ) {
316             my $id = $m->request_args->{'id'};
317             my $obj = RT::Group->new( $session{'CurrentUser'} );
318             $obj->Load($id);
319
320             my $tabs = PageMenu();
321             $tabs->child( basics         => title => loc('Basics'),       path => "/Admin/Groups/Modify.html?id=" . $obj->id );
322             $tabs->child( members        => title => loc('Members'),      path => "/Admin/Groups/Members.html?id=" . $obj->id );
323             $tabs->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/Groups/GroupRights.html?id=" . $obj->id );
324             $tabs->child( 'user-rights'  => title => loc('User Rights'),  path => "/Admin/Groups/UserRights.html?id=" . $obj->id );
325             $tabs->child( history        => title => loc('History'),      path => "/Admin/Groups/History.html?id=" . $obj->id );
326         }
327     }
328
329     if ( $request_path =~ m{^/Admin/CustomFields/} ) {
330         if ( $m->request_args->{'id'} && $m->request_args->{'id'} =~ /^\d+$/ ) {
331             my $id = $m->request_args->{'id'};
332             my $obj = RT::CustomField->new( $session{'CurrentUser'} );
333             $obj->Load($id);
334
335             my $tabs = PageMenu();
336             $tabs->child( basics         => title => loc('Basics'),       path => "/Admin/CustomFields/Modify.html?id=".$id );
337             $tabs->child( 'group-rights' => title => loc('Group Rights'), path => "/Admin/CustomFields/GroupRights.html?id=" . $id );
338             $tabs->child( 'user-rights'  => title => loc('User Rights'),  path => "/Admin/CustomFields/UserRights.html?id=" . $id );
339             $tabs->child( 'applies-to'   => title => loc('Applies to'),   path => "/Admin/CustomFields/Objects.html?id=" . $id );
340         }
341     }
342
343     if ( $request_path =~ m{^/Admin/Global/(Scrip|Template)s?\.html} ) {
344         my $type = $1;
345         my $tabs = PageMenu();
346
347         # With only two elements, swapping between dropdown and menu is kinda dumb
348         # In the glorious future this should be cleaner.
349
350         $tabs->child( select => title => loc('Select'), path => "/Admin/Global/${type}s.html" );
351         $tabs->child( create => title => loc('Create'), path => "/Admin/Global/${type}.html?Create=1" );
352     }
353
354     if ( $request_path =~ m{^/Admin/Articles/Classes/} ) {
355         my $tabs = PageMenu();
356         if ( my $id = $m->request_args->{'id'} ) {
357             my $obj = RT::CustomField->new( $session{'CurrentUser'} );
358             $obj->Load($id);
359
360             my $section = $tabs->child( select => title => loc("Classes"), path => "/Admin/Articles/Classes/" );
361             $section->child( select => title => loc('Select'), path => "/Admin/Articles/Classes/" );
362             $section->child( create => title => loc('Create'), path => "/Admin/Articles/Classes/Modify.html?Create=1" );
363
364             $tabs->child( basics          => title => loc('Basics'),        path => "/Admin/Articles/Classes/Modify.html?id=".$id );
365             $tabs->child( topics          => title => loc('Topics'),        path => "/Admin/Articles/Classes/Topics.html?id=".$id );
366             $tabs->child( 'custom-fields' => title => loc('Custom Fields'), path => "/Admin/Articles/Classes/CustomFields.html?id=".$id );
367             $tabs->child( 'group-rights'  => title => loc('Group Rights'),  path => "/Admin/Articles/Classes/GroupRights.html?id=".$id );
368             $tabs->child( 'user-rights'   => title => loc('User Rights'),   path => "/Admin/Articles/Classes/UserRights.html?id=".$id );
369             $tabs->child( 'applies-to'    => title => loc('Applies to'),    path => "/Admin/Articles/Classes/Objects.html?id=$id" );
370         } else {
371             $tabs->child( select => title => loc('Select'), path => "/Admin/Articles/Classes/" );
372             $tabs->child( create => title => loc('Create'), path => "/Admin/Articles/Classes/Modify.html?Create=1" );
373         }
374     }
375 };
376
377
378 my $build_main_nav = sub {
379
380     my $home = Menu->child( home => title => loc('Homepage'), path => '/' );
381     # We explicitly exclude superusers; otherwise the dashboards for
382     # groups you're not in (but can see the dashboards of by dint of
383     # being a superuser) would push the useful ones from the groups
384     # you're actually in off of the stack.
385     my @dashboards = $m->comp("/Dashboards/Elements/ListOfDashboards", IncludeSuperuserGroups => 0);
386     my $limit      = 7;
387
388     my $more = 0;
389     if ( @dashboards > $limit ) {
390         $more = 1;
391         splice @dashboards, $limit;
392     }
393
394     my $dashes = Menu()->child('home');
395     if (@dashboards) {
396         for my $dash (@dashboards) {
397             $home->child( 'dashboard-' . $dash->id,
398                 title => $dash->Name,
399                 path  => '/Dashboards/' . $dash->id . '/' . $dash->Name
400             );
401         }
402
403         $dashes->child( more => title => loc('All Dashboards'), path => 'Dashboards/index.html' );
404     }
405     my $dashboard = RT::Dashboard->new( $session{CurrentUser} );
406     if ( $dashboard->CurrentUserCanCreateAny ) {
407         $dashes->child('dashboard_create' => title => loc('New Dashboard'), path => "/Dashboards/Modify.html?Create=1" );
408     }
409
410     my $tickets = Menu->child( search => title => loc('Tickets'), path => '/Search/Build.html' );
411     $tickets->child( simple => title => loc('Simple Search'), path => "/Search/Simple.html" );
412     $tickets->child( new    => title => loc('New Search'),    path => "/Search/Build.html?NewQuery=1" );
413
414
415     my $tools = Menu->child( tools => title => loc('Tools'), path => '/Tools/index.html' );
416     my $articles = $tools->child( articles => title => loc('Articles'), path => "/Articles/index.html");
417     $articles->child( articles => title => loc('Overview'), path => "/Articles/index.html" );
418     $articles->child( search   => title => loc('Search'),   path => "/Articles/Article/Search.html" );
419     $articles->child( topics   => title => loc('Topics'),   path => "/Articles/Topics.html" );
420
421     $tools->child( my_day =>
422         title       => loc('My Day'),
423         description => loc('Easy updating of your open tickets'),
424         path        => '/Tools/MyDay.html',
425     );
426
427     if ( RT->Config->Get('EnableReminders') ) {
428         $tools->child( my_reminders =>
429             title       => loc('My Reminders'),
430             description => loc('Easy viewing of your reminders'),
431             path        => '/Tools/MyReminders.html',
432         );
433     }
434
435     $tools->child( offline =>
436         title       => loc('Offline'),
437         description => loc('Create tickets offline'),
438         path        => '/Tools/Offline.html',
439     );
440
441     if ( $session{'CurrentUser'}->HasRight( Right => 'ShowApprovalsTab', Object => RT->System ) ) {
442         $tools->child( approval =>
443             title       => loc('Approval'),
444             description => loc('My Approvals'),
445             path        => '/Approvals/',
446         );
447     }
448
449     if ( $session{'CurrentUser'}->HasRight( Right => 'ShowConfigTab', Object => RT->System ) )
450     {
451         $build_admin_menu->($tools);
452     }
453
454     my $username = '<span class="current-user">'
455                  . $m->interp->apply_escapes($session{'CurrentUser'}->Name, 'h')
456                  . '</span>';
457     my $about_me = Menu->child( 'preferences' =>
458         title        => loc('Logged in as [_1]', $username),
459         escape_title => 0,
460         sort_order   => 99,
461     );
462
463
464     if ( $session{'CurrentUser'}->UserObj
465          && $session{'CurrentUser'}->HasRight( Right => 'ModifySelf', Object => RT->System )) {
466         my $settings = $about_me->child( settings => title => loc('Settings'), path => '/Prefs/Other.html' );
467         $settings->child( options        => title => loc('Options'),        path => '/Prefs/Other.html' );
468         $settings->child( about_me       => title => loc('About me'),       path => '/User/Prefs.html' );
469         $settings->child( search_options => title => loc('Search options'), path => '/Prefs/SearchOptions.html' );
470         $settings->child( myrt           => title => loc('RT at a glance'), path => '/Prefs/MyRT.html' );
471         $settings->child( quicksearch    => title => loc('Quick search'),   path => '/Prefs/Quicksearch.html' );
472
473         my $search_menu = $settings->child( 'saved-searches' => title => loc('Saved Searches') );
474         my $searches = [ $m->comp( "/Search/Elements/SearchesForObject",
475                           Object => RT::System->new( $session{'CurrentUser'} )) ];
476         my $i = 0;
477
478         for my $search (@$searches) {
479             $search_menu->child( "search-" . $i++ =>
480                 title => $search->[0],
481                 path  => "/Prefs/Search.html?"
482                        . $query_string->( name => ref( $search->[1] ) . '-' . $search->[1]->Id ),
483             );
484
485         }
486     }
487     if ( $session{'CurrentUser'}->Name
488          && (   !RT->Config->Get('WebExternalAuth')
489               || RT->Config->Get('WebFallbackToInternalAuth') )) {
490         $about_me->child( logout => title => loc('Logout'), path => '/NoAuth/Logout.html' );
491     }
492     if ( $request_path =~ m{^/Dashboards/(\d+)?}) {
493         if ( my $id = ( $1 || $m->request_args->{'id'} ) ) {
494             my $obj = RT::Dashboard->new( $session{'CurrentUser'} );
495             $obj->LoadById($id);
496             if ( $obj and $obj->id ) {
497                 my $tabs = PageMenu;
498                 $tabs->child( basics       => title => loc('Basics'),       path => "/Dashboards/Modify.html?id=" . $obj->id);
499                 $tabs->child( content      => title => loc('Content'),      path => "/Dashboards/Queries.html?id=" . $obj->id);
500                 $tabs->child( subscription => title => loc('Subscription'), path => "/Dashboards/Subscription.html?id=" . $obj->id)
501                     if $obj->CurrentUserCanSubscribe;
502                 $tabs->child( show         => title => loc('Show'),         path => "/Dashboards/" . $obj->id . "/" . $obj->Name)
503             }
504         }
505     }
506
507
508     if ( $request_path =~ m{^/Ticket/} ) {
509         if ( ( $m->request_args->{'id'} || '' ) =~ /^(\d+)$/ ) {
510             my $id  = $1;
511             my $obj = RT::Ticket->new( $session{'CurrentUser'} );
512             $obj->Load($id);
513
514             my $actions = PageMenu()->child( actions => title => loc('Actions'), sort_order  => 95 );
515             my $tabs = PageMenu();
516             $tabs->child( bookmark => raw_html => $m->scomp( '/Ticket/Elements/Bookmark', id => $id ), sort_order => 99 );
517             $tabs->child( display => title => loc('Display'), path => "/Ticket/Display.html?id=" . $id );
518             $tabs->child( history => title => loc('History'), path => "/Ticket/History.html?id=" . $id );
519
520             my %can = %{ $obj->CurrentUser->PrincipalObj->HasRights( Object => $obj ) };
521             $can{'_ModifyOwner'} = $can{'OwnTicket'} || $can{'TakeTicket'} || $can{'StealTicket'};
522             my $can = sub {
523                 unless ($_[0] eq 'ExecuteCode') {
524                     return $can{$_[0]} || $can{'SuperUser'};
525                 } else {
526                     return !RT->Config->Get('DisallowExecuteCode')
527                         && ( $can{'ExecuteCode'} || $can{'SuperUser'} );
528                 }
529             };
530
531             # comment out until we can do it for an individual custom field
532             #if ( $can->('ModifyTicket') || $can->('ModifyCustomField') ) {
533             $tabs->child( basics => title => loc('Basics'), path => "/Ticket/Modify.html?id=" . $id );
534
535             #}
536
537             if ( $can->('ModifyTicket') || $can->('_ModifyOwner') || $can->('Watch') || $can->('WatchAsAdminCc') ) {
538                 $tabs->child( people => title => loc('People'), path => "/Ticket/ModifyPeople.html?id=" . $id );
539             }
540
541             if ( $can->('ModifyTicket') ) {
542                 $tabs->child( dates => title => loc('Dates'), path => "/Ticket/ModifyDates.html?id=" . $id );
543                 $tabs->child( links => title => loc('Links'), path => "/Ticket/ModifyLinks.html?id=" . $id );
544             }
545
546             #if ( $can->('ModifyTicket') || $can->('ModifyCustomField') || $can->('_ModifyOwner') ) {
547             $tabs->child( jumbo => title => loc('Jumbo'), path => "/Ticket/ModifyAll.html?id=" . $id );
548             #}
549
550             if ( RT->Config->Get('EnableReminders') ) {
551                 $tabs->child( reminders => title => loc('Reminders'), path => "/Ticket/Reminders.html?id=" . $id );
552             }
553
554             if ( $can->('ModifyTicket') or $can->('ReplyToTicket') ) {
555                 $actions->child( reply => title => loc('Reply'), path => "/Ticket/Update.html?Action=Respond;id=" . $id );
556             }
557
558             if ( $can->('ModifyTicket') or $can->('CommentOnTicket') ) {
559                 $actions->child( comment => title => loc('Comment'), path => "/Ticket/Update.html?Action=Comment;id=" . $id );
560             }
561
562             if ( $can->('ForwardMessage') ) {
563                 $actions->child( forward => title => loc('Forward'), path => "/Ticket/Forward.html?id=" . $id );
564             }
565
566             my $hide_resolve_with_deps = RT->Config->Get('HideResolveActionsWithDependencies')
567                 && $obj->HasUnresolvedDependencies;
568
569             my $current   = $obj->Status;
570             my $lifecycle = $obj->QueueObj->Lifecycle;
571             my $i         = 1;
572             foreach my $info ( $lifecycle->Actions($current) ) {
573                 my $next = $info->{'to'};
574                 next unless $lifecycle->IsTransition( $current => $next );
575
576                 my $check = $lifecycle->CheckRight( $current => $next );
577                 next unless $can->($check);
578
579                 next if $hide_resolve_with_deps
580                     && $lifecycle->IsInactive($next)
581                     && !$lifecycle->IsInactive($current);
582
583                 my $action = $info->{'update'} || '';
584                 my $url = '/Ticket/';
585                 if ($action) {
586                     $url .= "Update.html?"
587                         . $query_string->(
588                             Action        => $action,
589                             DefaultStatus => $next,
590                             id            => $id,
591                         );
592                 } else {
593                     $url .= "Display.html?"
594                         . $query_string->(
595                             Status => $next,
596                             id     => $id,
597                         );
598                 }
599                 my $key = $info->{'label'} || ucfirst($next);
600                 $actions->child( $key => title => loc( $key ), path => $url);
601             }
602
603             if ( $can->('OwnTicket') ) {
604                 if ( $obj->OwnerObj->Id == RT->Nobody->id
605                      && ( $can->('ModifyTicket') or $can->('TakeTicket') ) ) {
606                     $actions->child( take => title => loc('Take'), path => "/Ticket/Display.html?Action=Take;id=" . $id );
607                 }
608
609                 elsif (    $obj->OwnerObj->id != RT->Nobody->id
610                         && $obj->OwnerObj->id != $session{CurrentUser}->id
611                         && ( $can->('ModifyTicket') or $can->('StealTicket') ) ) {
612                     $actions->child( steal => title => loc('Steal'), path => "/Ticket/Display.html?Action=Steal;id=" . $id );
613                 }
614             }
615
616             # TODO needs a "Can extract article into a class applied to this queue" check
617             $actions->child( 'extract-article' =>
618                 title => loc('Extract Article'),
619                 path  => "/Articles/Article/ExtractIntoClass.html?Ticket=".$obj->id,
620             );
621
622             if ( defined $session{"tickets"} ) {
623                 # we have to update session data if we get new ItemMap
624                 my $updatesession = 1 unless ( $session{"tickets"}->{'item_map'} );
625
626                 my $item_map = $session{"tickets"}->ItemMap;
627
628                 if ($updatesession) {
629                     $session{"tickets"}->PrepForSerialization();
630                 }
631
632                 my $search = Menu()->child('search');
633                 # Don't display prev links if we're on the first ticket
634                 if ( $item_map->{$id}->{prev} ) {
635                     $search->child( first =>
636                         title => '<< ' . loc('First'), class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{first});
637                     $search->child( prev =>
638                         title => '< ' . loc('Prev'),   class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{$id}->{prev});
639                 }
640                 # Don't display next links if we're on the last ticket
641                 if ( $item_map->{$id}->{next} ) {
642                     $search->child( next =>
643                         title => loc('Next') . ' >',  class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{$id}->{next});
644                     $search->child( last =>
645                         title => loc('Last') . ' >>', class => "nav", path => "/Ticket/Display.html?id=" . $item_map->{last});
646                 }
647             }
648         }
649     }
650
651     if (
652         (
653                $request_path =~ m{^/(?:Ticket|Search)/}
654             && $request_path !~ m{^/Search/Simple\.html}
655         )
656         || (   $request_path =~ m{^/Search/Simple\.html}
657             && $m->request_args->{'q'} )
658       )
659     {
660         my $search = Menu()->child('search');
661         my $args      = '';
662         my $has_query = '';
663         my $current_search = $session{"CurrentSearchHash"} || {};
664         my $search_id = $m->request_args->{'SavedSearchLoad'} || $m->request_args->{'SavedSearchId'} || $current_search->{'SearchId'} || '';
665         my $chart_id = $m->request_args->{'SavedChartSearchId'} || $current_search->{SavedChartSearchId};
666
667         $has_query = 1 if ( $m->request_args->{'Query'} or $current_search->{'Query'} );
668
669         my %query_args;
670         my %fallback_query_args = (
671             SavedSearchId => ( $search_id eq 'new' ) ? undef : $search_id,
672             SavedChartSearchId => $chart_id,
673             (
674                 map {
675                     my $p = $_;
676                     $p => $m->request_args->{$p} || $current_search->{$p}
677                 } qw(Query Format OrderBy Order Page)
678             ),
679             RowsPerPage => (
680                 defined $m->request_args->{'RowsPerPage'}
681                 ? $m->request_args->{'RowsPerPage'}
682                 : $current_search->{'RowsPerPage'}
683             ),
684         );
685
686         if ($QueryString) {
687             $args = '?' . $QueryString;
688         }
689         else {
690             my %final_query_args = ();
691             # key => callback to avoid unnecessary work
692
693             for my $param (keys %fallback_query_args) {
694                 $final_query_args{$param} = defined($QueryArgs->{$param})
695                                           ? $QueryArgs->{$param}
696                                           : $fallback_query_args{$param};
697             }
698
699             for my $field (qw(Order OrderBy)) {
700                 if ( ref( $final_query_args{$field} ) eq 'ARRAY' ) {
701                     $final_query_args{$field} = join( "|", @{ $final_query_args{$field} } );
702                 } elsif (not defined $final_query_args{$field}) {
703                     delete $final_query_args{$field};
704                 }
705                 else {
706                     $final_query_args{$field} ||= '';
707                 }
708             }
709
710             $args = '?' . $query_string->(%final_query_args);
711         }
712
713         my $current_search_menu;
714         if ( $request_path =~ m{^/Ticket} ) {
715             $current_search_menu = $search->child( current_search => title => loc('Current Search') );
716             $current_search_menu->path("/Search/Results.html$args") if $has_query;
717         } else {
718             $current_search_menu = PageMenu();
719         }
720
721         $current_search_menu->child( edit_search =>
722             title => loc('Edit Search'), path => "/Search/Build.html" . ( ($has_query) ? $args : '' ) );
723         $current_search_menu->child( advanced =>
724             title => loc('Advanced'),    path => "/Search/Edit.html$args" );
725         if ($has_query) {
726             $current_search_menu->child( results => title => loc('Show Results'), path => "/Search/Results.html$args" );
727         }
728
729         if ( $has_query ) {
730             $current_search_menu->child( bulk  => title => loc('Bulk Update'), path => "/Search/Bulk.html$args" );
731             $current_search_menu->child( chart => title => loc('Chart'),       path => "/Search/Chart.html$args" );
732
733             my $more = $current_search_menu->child( more => title => loc('Feeds') );
734
735             $more->child( spreadsheet => title => loc('Spreadsheet'), path => "/Search/Results.tsv$args" );
736
737             my %rss_data = map {
738                 $_ => $QueryArgs->{$_} || $fallback_query_args{$_} || '' }
739                     qw(Query Order OrderBy);
740             my $RSSQueryString = "?"
741                 . $query_string->( Query   => $rss_data{Query},
742                                    Order   => $rss_data{Order},
743                                    OrderBy => $rss_data{OrderBy}
744                                  );
745             my $RSSPath = join '/', map $m->interp->apply_escapes( $_, 'u' ),
746                 $session{'CurrentUser'}->UserObj->Name,
747                 $session{'CurrentUser'}
748                 ->UserObj->GenerateAuthString(   $rss_data{Query}
749                                                . $rss_data{Order}
750                                                . $rss_data{OrderBy} );
751
752             $more->child( rss => title => loc('RSS'), path => "/NoAuth/rss/$RSSPath/$RSSQueryString");
753             my $ical_path = join '/', map $m->interp->apply_escapes($_, 'u'),
754                 $session{'CurrentUser'}->UserObj->Name,
755                 $session{'CurrentUser'}->UserObj->GenerateAuthString( $rss_data{Query} ),
756                 $rss_data{Query};
757             $more->child( ical => title => loc('iCal'), path => '/NoAuth/iCal/'.$ical_path);
758
759             if ($request_path =~ m{^/Search/Results.html}
760                 &&                        #XXX TODO better abstraction
761                 $session{'CurrentUser'}->HasRight( Right => 'SuperUser', Object => RT->System )) {
762                 my $shred_args = $query_string->(
763                     search          => 1,
764                     plugin          => 'Tickets',
765                     'Tickets:query' => $rss_data{'Query'},
766                     'Tickets:limit' => $QueryArgs->{'Rows'},
767                 );
768
769                 $more->child( shredder => title => loc('Shredder'), path => '/Admin/Tools/Shredder/?' . $shred_args);
770             }
771
772         }
773     }
774
775     if ( $request_path =~ m{^/Article/} ) {
776         if ( $m->request_args->{'id'} && $m->request_args->{'id'} =~ /^\d+$/ ) {
777             my $id = $m->request_args->{'id'};
778             my $tabs = PageMenu();
779
780             $tabs->child( display => title => loc('Display'), path => "/Articles/Article/Display.html?id=".$id );
781             $tabs->child( history => title => loc('History'), path => "/Articles/Article/History.html?id=".$id );
782             $tabs->child( modify  => title => loc('Modify'),  path => "/Articles/Article/Edit.html?id=".$id );
783             $tabs->child( delete  => title => loc('Delete'),  path => "/Articles/Article/Delete.html?id=".$id );
784         }
785     }
786
787     if ( $request_path =~ m{^/Articles/} ) {
788         my $tabs = PageMenu();
789         $tabs->child( search => title => loc("Search"),       path => "/Articles/Article/Search.html" );
790         $tabs->child( create => title => loc("New Article" ), path => "/Articles/Article/PreCreate.html" );
791         if ( $request_path =~ m{^/Articles/Article/} and ( $m->request_args->{'id'} || '' ) =~ /^(\d+)$/ ) {
792             my $id  = $1;
793             my $obj = RT::Article->new( $session{'CurrentUser'} );
794             $obj->Load($id);
795
796             $tabs->child( display => title => loc("Display"), path => "/Articles/Article/Display.html?id=" . $id );
797             $tabs->child( history => title => loc('History'), path => '/Articles/Article/History.html?id=' . $id );
798
799             if ( $obj->CurrentUserHasRight('ModifyArticle') ) {
800                 $tabs->child(modify => title => loc('Modify'), path => '/Articles/Article/Edit.html?id=' . $id );
801             }
802             if ( $obj->CurrentUserHasRight('DeleteArticle') ) {
803                 $tabs->child(delete => title => loc('Delete'), path => '/Articles/Article/Delete.html?id=' . $id );
804             }
805         }
806
807     }
808
809     if ( $request_path =~ /^\/(?:index.html|$)/ ) {
810         PageMenu()->child( edit => title => loc('Edit'), path => '/Prefs/MyRT.html' );
811     }
812
813     PageWidgets()->child( simple_search => raw_html => $m->scomp('SimpleSearch') );
814     PageWidgets()->child( create_ticket => raw_html => $m->scomp('CreateTicket') );
815
816     $m->callback( CallbackName => 'Privileged' );
817 };
818
819 my $build_selfservice_nav = sub {
820     my $queues = RT::Queues->new( $session{'CurrentUser'} );
821     $queues->UnLimit;
822
823     my $queue_count = 0;
824     my $queue_id    = 1;
825
826     while ( my $queue = $queues->Next ) {
827         next unless $queue->CurrentUserHasRight('CreateTicket');
828         $queue_id = $queue->id;
829         $queue_count++;
830         last if ( $queue_count > 1 );
831     }
832
833
834     my $tickets = Menu->child( tickets => title => loc('Tickets'));
835     $tickets->child( open   => title => loc('Open tickets'),   path => '/SelfService/' );
836     $tickets->child( closed => title => loc('Closed tickets'), path => '/SelfService/Closed.html' );
837     if ( $queue_count > 1 ) {
838         $tickets->child( new => title => loc('New ticket'),    path => '/SelfService/CreateTicketInQueue.html' );
839     } else {
840         $tickets->child( new => title => loc('New ticket'),    path => '/SelfService/Create.html?Queue=' . $queue_id );
841     }
842
843
844     my $username = '<span class="current-user">'
845                  . $m->interp->apply_escapes($session{'CurrentUser'}->Name, 'h')
846                  . '</span>';
847     my $about_me = Menu->child( preferences =>
848         title        => loc('Logged in as [_1]', $username),
849         escape_title => 0,
850         sort_order   => 99,
851     );
852
853     if ( $session{'CurrentUser'}->HasRight( Right => 'ModifySelf', Object => RT->System ) ) {
854         $about_me->child( prefs => title => loc('Preferences'), path => '/SelfService/Prefs.html' );
855     }
856
857     if ( $session{'CurrentUser'}->Name
858          && (   !RT->Config->Get('WebExternalAuth')
859               || RT->Config->Get('WebFallbackToInternalAuth') )) {
860         $about_me->child( logout => title => loc('Logout'), path => '/NoAuth/Logout.html' );
861     }
862
863     if ($session{'CurrentUser'}->HasRight( Right => 'ShowArticle', Object => RT->System )) {
864         PageWidgets->child( 'goto-article' => raw_html => $m->scomp('/SelfService/Elements/SearchArticle') );
865     }
866
867     PageWidgets->child( goto => raw_html => $m->scomp('/SelfService/Elements/GotoTicket') );
868
869     $m->callback( CallbackName => 'SelfService' );
870 };
871
872
873
874 if ( $request_path !~ m{^/SelfService/} ) {
875     $build_main_nav->();
876 } else {
877     $build_selfservice_nav->();
878 }
879
880
881
882
883 </%INIT>
884 <%ARGS>
885 $show_menu => 1
886 $QueryString => ''
887 $QueryArgs => {}
888 </%ARGS>