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