Putting 4.2.0 on top of 4.0.17
[usit-rt.git] / share / html / Dashboards / Queries.html
CommitLineData
84fb5b46
MKG
1%# BEGIN BPS TAGGED BLOCK {{{
2%#
3%# COPYRIGHT:
4%#
403d7b0b 5%# This software is Copyright (c) 1996-2013 Best Practical Solutions, LLC
84fb5b46
MKG
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/Header, Title => $title &>
49<& /Elements/Tabs &>
50
84fb5b46
MKG
51<& /Elements/ListActions, actions => \@results &>
52
53<& Elements/Deleted, searches => \@deleted, Dashboard => $Dashboard &>
54
55<& Elements/HiddenSearches, searches => \@hidden_searches, Dashboard => $Dashboard &>
56
57<table width="100%" border="0">
58% for my $pane (@panes) {
59<tr><td valign="top" class="boxcontainer">
60<form action="Queries.html" name="Dashboard-<%$pane->{Name}%>" method="post" enctype="multipart/form-data">
61<input type="hidden" class="hidden" name="id" value="<%$Dashboard->Id%>" />
62<input type="hidden" class="hidden" name="Privacy" value="<%$Dashboard->Privacy%>" />
63
64<&| /Widgets/TitleBox, title => $pane->{DisplayName} &>
65% my ( $pane_name ) = $pane->{Name} =~ /Searches-(.+)/;
af59614d 66 <& /Widgets/SelectionBox:show, self => $pane, grep( {
84fb5b46
MKG
67 $_->{pane} eq $pane_name} @deleted ) ? ( ShowUpdate => 1 ) : () &>
68</&>
69</form>
70</td></tr>
71% }
72</table>
73
74<%INIT>
75
76my @results;
77
78use RT::Dashboard;
79my $Dashboard = RT::Dashboard->new($session{'CurrentUser'});
80my ($ok, $msg) = $Dashboard->LoadById($id);
81$ok || Abort(loc("Couldn't load dashboard [_1]: [_2]", $id, $msg));
82my $title = loc("Modify the content of dashboard [_1]", $Dashboard->Name);
83
84my %desc_of;
85my @items;
86my %selected;
87my %still_exists;
88
89# add portlets (homepage componenets)
90my @components = @{ RT->Config->Get('HomepageComponents') };
91
92for my $desc (@components) {
93 my $name = "component-$desc";
5b0d0914
MKG
94 push @items, [$name, loc($desc)];
95 $desc_of{$name} = loc($desc);
84fb5b46
MKG
96 $still_exists{$name} = 1;
97}
98
99# add dashboards
100my @dashboards = $m->comp("/Dashboards/Elements/ListOfDashboards");
101for my $dashboard (@dashboards) {
102 # Users *can* set up mutually recursive dashboards, but don't make it THIS
103 # easy for them to shoot themselves in the foot.
104 next if $dashboard->Id == $Dashboard->Id;
105
106 my $name = 'dashboard-' . $dashboard->Id . '-' . $dashboard->Privacy;
5b0d0914
MKG
107 my $type = loc('Dashboard'); # loc
108 my $desc = "$type: " . $dashboard->Name;
84fb5b46
MKG
109 push @items, [$name, $desc];
110 $desc_of{$name} = $desc;
111 $still_exists{$name} = 1;
112}
113
114# add saved searches
115my @objs = RT::System->new($session{'CurrentUser'});
116
117push @objs, RT::SavedSearch->new( $session{CurrentUser} )->ObjectsForLoading
118 if $session{'CurrentUser'}->HasRight( Right => 'LoadSavedSearch',
119 Object => $RT::System );
120
121for my $object (@objs) {
122 for ($m->comp("/Search/Elements/SearchesForObject", Object => $object)) {
5b0d0914 123 my ($desc, $loc_desc, $search) = @$_;
84fb5b46 124 my $SearchType = $search->Content->{'SearchType'} || 'Ticket';
5b0d0914
MKG
125 my $type = ( $SearchType eq 'Ticket' )
126 ? 'Saved Search' # loc
127 : $SearchType;
128 $desc = loc($type) . ": $loc_desc";
84fb5b46
MKG
129 my $privacy = $Dashboard->_build_privacy($object);
130 my $name = 'search-' . $search->Id . '-' . $privacy;
131 push @items, [$name, $desc];
132 $desc_of{$name} = $desc;
133 $still_exists{$name} = 1;
134 }
135}
136
137# Get the list of portlets already in use
138my @deleted;
139do {
140 my $panes = $Dashboard->Panes;
141 for my $pane (keys %$panes) {
142 for my $portlet (@{ $panes->{$pane} }) {
143 my $name;
144 my $type = $portlet->{portlet_type};
145
146 if ($type eq 'search' || $type eq 'dashboard') {
147 $name = join '-', $type, $portlet->{id}, $portlet->{privacy};
148 }
149 elsif ($type eq 'component') {
150 $name = join '-', 'component', $portlet->{component};
151 }
152
153 if (!$still_exists{$name}) {
154 push @deleted, {
155 pane => $pane,
156 name => $name,
157 description => $portlet->{description},
158 };
159 next;
160 }
161
162 push @{ $selected{$pane} }, $name;
163 $desc_of{$name} = $portlet->{description};
164 }
165 }
166};
167
168$m->callback(
169 CallbackName => 'PopulatePossibilities',
170 Dashboard => $Dashboard,
171 items => \@items,
172 desc_of => \%desc_of,
173 still_exists => \%still_exists,
174 selected => \%selected,
175);
176
177# Create selectionbox widgets for those portlets
178
179my %pane_name = (
180 'body' => loc('Body'),
181 'sidebar' => loc('Sidebar'),
182);
183
184$m->callback(
185 CallbackName => 'Panes',
186 Dashboard => $Dashboard,
187 panes => \%pane_name,
188);
189
190my @panes;
191for my $pane (keys %pane_name) {
192 my $sel = $m->comp(
193 '/Widgets/SelectionBox:new',
194 Action => 'Queries.html',
195 Name => "Searches-$pane",
196 DisplayName => $pane_name{$pane},
197 Available => \@items,
198 Selected => $selected{$pane},
199 AutoSave => 1,
200 OnSubmit => sub {
201 my $self = shift;
202
203 $m->callback(
204 CallbackName => 'Submit',
205 Dashboard => $Dashboard,
206 Selected => $self->{Current},
207 pane => $pane,
208 );
209
210 my @portlets;
211 for (@{ $self->{Current} }) {
212 my $item = $_;
213 my $desc = $desc_of{$item};
214 my $portlet_type = $1 if $item =~ s/^(\w+)-//;
215
216 if ($portlet_type eq 'search' || $portlet_type eq 'dashboard') {
217 my ($id, $privacy) = split '-', $item, 2;
218 push @portlets, {
219 portlet_type => $portlet_type,
220 privacy => $privacy,
221 id => $id,
222 description => $desc,
223 pane => $pane,
224 };
225 }
226 elsif ($portlet_type eq 'component') {
227 # Absolute paths stay absolute, relative paths go into
228 # /Elements. This way, extensions that add portlets work.
229 my $path = $item;
230 $path = "/Elements/$path" if substr($path, 0, 1) ne '/';
231
232 push @portlets, {
233 portlet_type => $portlet_type,
234 component => $item,
235 path => $path,
236 description => $item,
237 pane => $pane,
238 };
239 }
240 }
241
242 # we want to keep all the other panes the same
243 my $panes = $Dashboard->Panes;
244 $panes->{$pane} = \@portlets;
245
246 # remove "deleted" warnings about this pane
247 @deleted = grep { $_->{pane} ne $pane } @deleted;
248
249 $m->callback(
250 CallbackName => 'BeforeUpdate',
251 Dashboard => $Dashboard,
252 panes => $panes,
253 );
254
255 my ($ok, $msg) = $Dashboard->Update(Panes => $panes);
256
257 if ($ok) {
258 push @results, loc("Dashboard updated");
259 }
260 else {
261 push @results, loc("Dashboard could not be updated: [_1]", $msg);
262 }
263 },
264 );
265
266 push @panes, $sel;
267}
268
af59614d 269$m->comp('/Widgets/SelectionBox:process', %ARGS, self => $_ )
84fb5b46
MKG
270 for @panes;
271
272my @hidden_searches = $Dashboard->PossibleHiddenSearches;
273</%INIT>
274<%ARGS>
275$id => '' unless defined $id
276</%ARGS>
277