summaryrefslogtreecommitdiff
path: root/rt/html
diff options
context:
space:
mode:
Diffstat (limited to 'rt/html')
-rw-r--r--rt/html/Admin/Elements/ModifyQueue78
-rw-r--r--rt/html/Admin/Elements/ModifyUser99
-rw-r--r--rt/html/Admin/Global/CustomField.html86
-rw-r--r--rt/html/Admin/Global/CustomFields.html69
-rw-r--r--rt/html/Admin/Users/Modify.html12
-rw-r--r--rt/html/Admin/Users/Prefs.html122
-rw-r--r--rt/html/Callbacks/ActivityReports/Elements/Tabs/Default7
-rw-r--r--rt/html/Callbacks/ActivityReports/NoAuth/webrt.css/Default71
-rw-r--r--rt/html/Callbacks/ActivityReports/Search/Results.html/SearchActions7
-rw-r--r--rt/html/Callbacks/RT-WebCronTool/Elements/Tabs/Default13
-rw-r--r--rt/html/Callbacks/kStatistics/Elements/Tabs/Default11
-rw-r--r--rt/html/Developer/CronTool/autohandler9
-rw-r--r--rt/html/Developer/CronTool/index.html116
-rw-r--r--rt/html/Elements/AddCustomers59
-rw-r--r--rt/html/Elements/EditCustomers63
-rw-r--r--rt/html/Elements/Footer25
-rw-r--r--rt/html/Elements/FreesideInvoiceSearch20
-rw-r--r--rt/html/Elements/FreesideNewCust3
-rw-r--r--rt/html/Elements/FreesideSearch13
-rw-r--r--rt/html/Elements/FreesideSvcSearch13
-rw-r--r--rt/html/Elements/Header109
-rw-r--r--rt/html/Elements/PageLayout160
-rw-r--r--rt/html/Elements/QuickCreate4
-rw-r--r--rt/html/Elements/SelectDate15
-rw-r--r--rt/html/Elements/ShadedBox33
-rw-r--r--rt/html/Elements/ShadedInputRow35
-rw-r--r--rt/html/Elements/ShadedRow31
-rw-r--r--rt/html/Elements/SimpleSearch13
-rw-r--r--rt/html/Elements/Tabs22
-rw-r--r--rt/html/Elements/TicketList3
-rw-r--r--rt/html/Elements/ViewUser51
-rw-r--r--rt/html/NoAuth/css/3.5-default/freeside.css9
-rw-r--r--rt/html/NoAuth/css/3.5-default/main.css1
-rwxr-xr-xrt/html/NoAuth/css/3.5-default/misc.css8
-rw-r--r--rt/html/NoAuth/css/3.5-default/titlebox.css3
-rwxr-xr-xrt/html/NoAuth/css/3.5-default/transactions.css4
-rw-r--r--rt/html/NoAuth/images/back_home.gifbin330 -> 0 bytes
-rw-r--r--rt/html/NoAuth/images/css/cb.gifbin163 -> 110 bytes
-rw-r--r--rt/html/NoAuth/images/css/cbr.gifbin188 -> 110 bytes
-rw-r--r--rt/html/NoAuth/images/css/ct.gifbin162 -> 110 bytes
-rw-r--r--rt/html/NoAuth/images/css/ctr.gifbin188 -> 111 bytes
-rw-r--r--rt/html/NoAuth/images/head_requestracker.gifbin1233 -> 0 bytes
-rw-r--r--rt/html/NoAuth/images/rt.jpgbin917 -> 0 bytes
-rw-r--r--rt/html/NoAuth/images/small-logo.pngbin0 -> 4887 bytes
-rw-r--r--rt/html/NoAuth/images/space.gifbin43 -> 0 bytes
-rw-r--r--rt/html/NoAuth/images/spacer.gifbin43 -> 0 bytes
-rw-r--r--rt/html/NoAuth/images/squares_blue.gifbin219 -> 0 bytes
-rw-r--r--rt/html/NoAuth/printrt.css77
-rw-r--r--rt/html/NoAuth/webrt.css628
-rw-r--r--rt/html/Prefs/SearchOptions.html2
-rwxr-xr-xrt/html/RTx/Statistics/CallsMultiQueue/Elements/Chart39
-rwxr-xr-xrt/html/RTx/Statistics/CallsMultiQueue/index.html330
-rwxr-xr-xrt/html/RTx/Statistics/CallsQueueDay/Elements/Chart29
-rw-r--r--rt/html/RTx/Statistics/CallsQueueDay/Results.tsv191
-rwxr-xr-xrt/html/RTx/Statistics/CallsQueueDay/index.html275
-rwxr-xr-xrt/html/RTx/Statistics/DayOfWeek/Elements/Chart26
-rwxr-xr-xrt/html/RTx/Statistics/DayOfWeek/index.html155
-rwxr-xr-xrt/html/RTx/Statistics/DurationAsString18
-rw-r--r--rt/html/RTx/Statistics/Elements/CollectionAsTable/Header126
-rw-r--r--rt/html/RTx/Statistics/Elements/CollectionAsTable/ParseFormat (renamed from rt/html/Ticket/Elements/ShowReferences)83
-rw-r--r--rt/html/RTx/Statistics/Elements/CollectionAsTable/Row112
-rw-r--r--rt/html/RTx/Statistics/Elements/ControlsAsTable/ControlBox103
-rw-r--r--rt/html/RTx/Statistics/Elements/ControlsAsTable/UpdatePage5
-rw-r--r--rt/html/RTx/Statistics/Elements/DateSelectRow55
-rwxr-xr-xrt/html/RTx/Statistics/Elements/DurationAsString18
-rw-r--r--rt/html/RTx/Statistics/Elements/GraphBox27
-rwxr-xr-x[-rw-r--r--]rt/html/RTx/Statistics/Elements/SelectMultiQueue (renamed from rt/html/Ticket/Elements/ShowMemberOf)40
-rw-r--r--rt/html/RTx/Statistics/Elements/StatColumnMap173
-rwxr-xr-xrt/html/RTx/Statistics/Elements/Tabs72
-rw-r--r--rt/html/RTx/Statistics/FAQ/index.html23
-rwxr-xr-xrt/html/RTx/Statistics/OpenStalled/Elements/Chart27
-rw-r--r--rt/html/RTx/Statistics/OpenStalled/Results.tsv114
-rwxr-xr-xrt/html/RTx/Statistics/OpenStalled/index.html188
-rwxr-xr-xrt/html/RTx/Statistics/Resolution/Elements/Chart29
-rw-r--r--rt/html/RTx/Statistics/Resolution/index.html269
-rwxr-xr-xrt/html/RTx/Statistics/TimeToResolve/Elements/Chart23
-rwxr-xr-xrt/html/RTx/Statistics/TimeToResolve/index.html75
-rwxr-xr-xrt/html/RTx/Statistics/UserTest/Elements/Chart28
-rwxr-xr-xrt/html/RTx/Statistics/UserTest/index.html54
-rwxr-xr-xrt/html/RTx/Statistics/index.html59
-rw-r--r--rt/html/Reports/Activity/ActivityDetail.html83
-rw-r--r--rt/html/Reports/Activity/ActivitySummary.html61
-rw-r--r--rt/html/Reports/Activity/Elements/LimitReport23
-rw-r--r--rt/html/Reports/Activity/Elements/MiniPlot57
-rw-r--r--rt/html/Reports/Activity/Elements/PrintFooter7
-rw-r--r--rt/html/Reports/Activity/Elements/PrintHeader32
-rw-r--r--rt/html/Reports/Activity/Elements/ScreenFooter13
-rw-r--r--rt/html/Reports/Activity/Elements/ScreenHeader8
-rw-r--r--rt/html/Reports/Activity/Elements/Tabs52
-rw-r--r--rt/html/Reports/Activity/Elements/Wrapper16
-rw-r--r--rt/html/Reports/Activity/ResolutionComments.html62
-rw-r--r--rt/html/Reports/Activity/ResolutionStatistics.html95
-rw-r--r--rt/html/Reports/Activity/index.html29
-rw-r--r--rt/html/Search/Elements/PickRestriction142
-rw-r--r--rt/html/Search/Elements/TicketHeader40
-rw-r--r--rt/html/Search/Elements/TicketHeaderCell55
-rw-r--r--rt/html/Search/Elements/TicketRow55
-rw-r--r--rt/html/Search/Listing.html113
-rw-r--r--rt/html/Ticket/Create.html4
-rw-r--r--rt/html/Ticket/Display.html4
-rw-r--r--rt/html/Ticket/Elements/AddCustomers52
-rw-r--r--rt/html/Ticket/Elements/EditCustomers63
-rw-r--r--rt/html/Ticket/Elements/EditLinks133
-rw-r--r--rt/html/Ticket/Elements/ShowCustomers38
-rw-r--r--rt/html/Ticket/Elements/ShowLink40
-rw-r--r--rt/html/Ticket/Elements/ShowLinks87
-rw-r--r--rt/html/Ticket/Elements/ShowSummary6
-rw-r--r--rt/html/Ticket/Elements/ShowTransactionAttachments10
-rw-r--r--rt/html/Ticket/Elements/Tabs2
-rw-r--r--rt/html/Ticket/ModifyCustomers.html49
-rw-r--r--rt/html/User/Prefs.html2
111 files changed, 4157 insertions, 2146 deletions
diff --git a/rt/html/Admin/Elements/ModifyQueue b/rt/html/Admin/Elements/ModifyQueue
deleted file mode 100644
index 36f9ce17f..000000000
--- a/rt/html/Admin/Elements/ModifyQueue
+++ /dev/null
@@ -1,78 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<& /Elements/TitleBoxStart, title => loc('Editing Configuration for queue [_1]', $QueueObj->Id) &>
-
-<FORM ACTION="<%$RT::WebPath%>/Admin/Queues/Modify.html" METHOD=POST>
-<INPUT TYPE=HIDDEN NAME=id VALUE="<%$QueueObj->Id%>">
-<TABLE>
-<TR><TD ALIGN=RIGHT>
-<&|/l&>Queue Name</&>:
-</TD>
-<TD><INPUT name="Name" value="<%$QueueObj->Name%>"></TD>
-</TR><TR>
-<TD ALIGN=RIGHT>
-<&|/l&>Description</&>:</TD><TD COLSPAN=3><INPUT name="Description" value="<%$QueueObj->Description%>" size=60></TD></TR>
-<TR>
-<TD ALIGN=RIGHT>
-<&|/l&>Correspondence Address</&>:
-</TD><TD>
-<INPUT name="CorrespondAddress" value="<%$QueueObj->CorrespondAddress%>">
-</TD>
-<TD ALIGN=RIGHT>
-
-<&|/l&>Comment Address</&>: </TD><TD>
-<INPUT NAME="CommentAddress" value="<%$QueueObj->CommentAddress%>">
-</TD>
-</TR><TR>
-
-<TD ALIGN=RIGHT>
-<&|/l&>Priority starts at</&>:
-</TD><TD><INPUT NAME="InitialPriority" value="<%$QueueObj->InitialPriority %>">
-</TD>
-<TD ALIGN=RIGHT>
-<&|/l&>Over time, priority moves toward</&>:
-</TD><TD><INPUT NAME="FinalPriority" value="<%$QueueObj->FinalPriority %>">
-</TD>
-</TR>
-<TR>
-<TD ALIGN=RIGHT>
-<&|/l&>Requests should be due in</&>:
-</TD><TD>
-<INPUT NAME="DefaultDueIn" VALUE="<%$QueueObj->DefaultDueIn%>"> <&|/l&>days</&>.
-</TD>
-</TR>
-</TABLE>
-<& /Elements/Submit, Label => loc('Save Changes') &>
-</form>
-<& /Elements/TitleBoxEnd &>
-
-<%INIT>
-
-</%INIT>
-
-<%ARGS>
-
-
-$QueueObj => undef
-</%ARGS>
diff --git a/rt/html/Admin/Elements/ModifyUser b/rt/html/Admin/Elements/ModifyUser
deleted file mode 100644
index 2faefefaa..000000000
--- a/rt/html/Admin/Elements/ModifyUser
+++ /dev/null
@@ -1,99 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<& /Elements/TitleBoxStart, title => loc('Editing Configuration for user [_1]', $UserObj->Name) &>
-
-<FORM ACTION="<%$RT::WebPath%>/Admin/Users/Modify.html" METHOD=POST>
-<INPUT TYPE=HIDDEN NAME=id VALUE="<%$UserObj->Id%>">
-
-<&|/l&>Name</&>: <input name="Name" value="<%$UserObj->Name%>">
-<BR>
-<&|/l&>New Password</&>: <input type=password name="Pass1"><BR>
-<&|/l&>Retype Password</&>: <input type=password name="Pass2"><BR>
-
-<&|/l&>Comments</&>: <TEXTAREA name="Comments" COLS=80 ROWS=5 WRAP=VIRTUAL>
-<%$UserObj->Comments%></TEXTAREA>
-
-<BR>
-<&|/l&>Signature</&>: <TEXTAREA COLS=80 ROWS=5 name="Signature" WRAP=HARD>
-<%$UserObj->Signature%></TEXTAREA>
-<BR>
-<&|/l&>EmailAddress</&>: <input name="EmailAddress" value="<%$UserObj->EmailAddress%>">
-<BR>
-<&|/l&>FreeformContactInfo</&>: <input name="FreeformContactInfo" value="<%$UserObj->FreeformContactInfo%>">
-<BR>
-<&|/l&>Organization</&>: <input name="Organization" value="<%$UserObj->Organization%>">
-<BR>
-<&|/l&>RealName</&>: <input name="RealName" value="<%$UserObj->RealName%>">
-<BR>
-<&|/l&>NickName</&>: <input name="NickName" value="<%$UserObj->NickName%>">
-<BR>
-<&|/l&>Lang</&>: <input name="Lang" value="<%$UserObj->Lang%>">
-<BR>
-<&|/l&>EmailEncoding</&>: <input name="EmailEncoding" value="<%$UserObj->EmailEncoding%>">
-<BR>
-<&|/l&>WebEncoding</&>: <input name="WebEncoding" value="<%$UserObj->WebEncoding%>">
-<BR>
-<&|/l&>ExternalContactInfoId</&>: <input name="ExternalContactInfoId" value="<%$UserObj->ExternalContactInfoId%>">
-<BR>
-<&|/l&>ContactInfoSystem</&>: <input name="ContactInfoSystem" value="<%$UserObj->ContactInfoSystem%>">
-<BR>
-<&|/l&>UnixUsername</&>: <input name="Gecos" value="<%$UserObj->Gecos%>">
-<BR>
-<&|/l&>ExternalAuthId</&>: <input name="ExternalAuthId" value="<%$UserObj->ExternalAuthId%>">
-<BR>
-<&|/l&>AuthSystem</&>: <input name="AuthSystem" value="<%$UserObj->AuthSystem%>">
-<BR>
-<&|/l&>HomePhone</&>: <input name="HomePhone" value="<%$UserObj->HomePhone%>">
-<BR>
-<&|/l&>WorkPhone</&>: <input name="WorkPhone" value="<%$UserObj->WorkPhone%>">
-<BR>
-<&|/l&>MobilePhone</&>: <input name="MobilePhone" value="<%$UserObj->MobilePhone%>">
-<BR>
-<&|/l&>PagerPhone</&>: <input name="PagerPhone" value="<%$UserObj->PagerPhone%>">
-<BR>
-<&|/l&>Address1</&>: <input name="Address1" value="<%$UserObj->Address1%>">
-<BR>
-<&|/l&>Address2</&>: <input name="Address2" value="<%$UserObj->Address2%>">
-<BR>
-<&|/l&>City</&>: <input name="City" value="<%$UserObj->City%>">
-<BR>
-<&|/l&>State</&>: <input name="State" value="<%$UserObj->State%>">
-<BR>
-<&|/l&>Zip</&>: <input name="Zip" value="<%$UserObj->Zip%>">
-<BR>
-<&|/l&>Country</&>: <input name="Country" value="<%$UserObj->Country%>">
-<BR>
-<& /Elements/Submit, Label => loc('Save Changes') &>
-</form>
-<& /Elements/TitleBoxEnd &>
-
-<%INIT>
-
-</%INIT>
-
-<%ARGS>
-
-
-$UserObj => undef
-</%ARGS>
diff --git a/rt/html/Admin/Global/CustomField.html b/rt/html/Admin/Global/CustomField.html
deleted file mode 100644
index 3871d8998..000000000
--- a/rt/html/Admin/Global/CustomField.html
+++ /dev/null
@@ -1,86 +0,0 @@
-%# {{{ BEGIN BPS TAGGED BLOCK
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC
-%# <jesse@bestpractical.com>
-%#
-%# (Except where explicitly superseded by other copyright notices)
-%#
-%#
-%# LICENSE:
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# You should have received a copy of the GNU General Public License
-%# along with this program; if not, write to the Free Software
-%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-%#
-%#
-%# CONTRIBUTION SUBMISSION POLICY:
-%#
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%#
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%#
-%# }}} END BPS TAGGED BLOCK
-<& /Admin/Elements/Header, Title => $title &>
-<& /Admin/Elements/SystemTabs,
- current_tab => 'Admin/Global/CustomFields.html',
- current_subtab => $current_subtab,
- subtabs => $subtabs,
- Title => $title &>
-
-<& /Admin/Elements/EditCustomField, title => $title, %ARGS &>
-
-<%INIT>
-my ($title, $current_subtab);
-
-my $subtabs = {
- A => { title => loc('Select custom field'),
- path => "Admin/Global/CustomFields.html"
- },
- B => { title => loc('New custom field'),
- path => "Admin/Global/CustomField.html?create=1&Queue=0",
- separator => 1,
- }
- };
-if ( $ARGS{'create'} ) {
- $current_subtab = "Admin/Global/CustomField.html?create=1&Queue=0";
- $title = loc('Create a CustomField which applies to all queues');
-}
-else {
- $current_subtab =
- "Admin/Global/CustomField.html?CustomField=" . $CustomField . "&Queue=0";
- $title = loc('Modify a CustomField which applies to all queues');
- $subtabs->{"C"} = {
- title => loc( 'Custom Field #[_1]', $CustomField ),
- path => "Admin/Global/CustomField.html?CustomField=" . $CustomField . "&Queue=0"
- };
-}
-</%INIT>
-<%ARGS>
-$CustomField => undef
-</%ARGS>
-<%ATTR>
-AutoFlush => 0
-</%ATTR>
diff --git a/rt/html/Admin/Global/CustomFields.html b/rt/html/Admin/Global/CustomFields.html
deleted file mode 100644
index 593040218..000000000
--- a/rt/html/Admin/Global/CustomFields.html
+++ /dev/null
@@ -1,69 +0,0 @@
-%# {{{ BEGIN BPS TAGGED BLOCK
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2004 Best Practical Solutions, LLC
-%# <jesse@bestpractical.com>
-%#
-%# (Except where explicitly superseded by other copyright notices)
-%#
-%#
-%# LICENSE:
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# You should have received a copy of the GNU General Public License
-%# along with this program; if not, write to the Free Software
-%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-%#
-%#
-%# CONTRIBUTION SUBMISSION POLICY:
-%#
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%#
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%#
-%# }}} END BPS TAGGED BLOCK
-<& /Admin/Elements/Header, Title => $title &>
-<& /Admin/Elements/SystemTabs,
- current_tab => 'Admin/Global/CustomFields.html',
- current_subtab => 'Admin/Global/CustomFields.html',
- subtabs => $subtabs,
- Title => $title &>
-
-<& /Admin/Elements/EditCustomFields, title => $title, %ARGS &>
-
-<%INIT>
-my $subtabs = {
- A => { title => loc('Select custom field'),
- path => "Admin/Global/CustomFields.html"
- },
- B => { title => loc('New custom field'),
- path => "Admin/Global/CustomField.html?create=1&Queue=0",
- separator => 1,
- }
- };
-my $title = loc("Modify Custom Fields which apply to all queues");
-</%INIT>
-<%ARGS>
-$id => undef
-</%ARGS>
diff --git a/rt/html/Admin/Users/Modify.html b/rt/html/Admin/Users/Modify.html
index 75a7696a5..1be96f695 100644
--- a/rt/html/Admin/Users/Modify.html
+++ b/rt/html/Admin/Users/Modify.html
@@ -105,6 +105,12 @@
</table>
</&>
<br />
+
+<&| /Widgets/TitleBox, title => loc('Customers') &>
+<& /Elements/EditCustomers, Object => $UserObj, CustomerString=> $CustomerString, ServiceString => $ServiceString &>
+</&>
+<br />
+
<&| /Widgets/TitleBox, title => loc('Access control') &>
<input type="hidden" class="hidden" name="SetEnabled" value="1" />
<input type="checkbox" class="checkbox" name="Enabled" value="1" <%$EnabledChecked%> />
@@ -339,6 +345,8 @@ if ($UserObj->Id && $id ne 'new') {
push (@results,@fieldresults);
push @results, ProcessObjectCustomFieldUpdates( ARGSRef => \%ARGS, Object => $UserObj );
+ #deal with freeside customer links
+ push @results, ProcessObjectCustomers( ARGSRef => \%ARGS, Object => $UserObj );
# {{{ Deal with special fields: Privileged, Enabled
if ( $SetPrivileged and $Privileged != $UserObj->Privileged ) {
@@ -430,4 +438,8 @@ $Country => undef
$Pass1 => undef
$Pass2=> undef
$Create=> undef
+$OnlySearchForCustomers => undef
+$OnlySearchForServices => undef
+$CustomerString => undef
+$ServiceString => undef
</%ARGS>
diff --git a/rt/html/Admin/Users/Prefs.html b/rt/html/Admin/Users/Prefs.html
deleted file mode 100644
index 0bba9fadd..000000000
--- a/rt/html/Admin/Users/Prefs.html
+++ /dev/null
@@ -1,122 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<& /Elements/Header, Title => loc("User view") &>
-
-<& /Elements/ViewUser, User=>$u &>
-
-<h2 class="title"><%loc("User view")%></h2>
-
-%if ($session{CurrentUser} && ($session{CurrentUser}->Id == $id)) {
- <& /Elements/TitleBoxStart, title => loc('Signature') &>
-<form method=post>
-<input type="hidden" name="id" value=<%$id%>>
-<TEXTAREA COLS=72 ROWS=4 WRAP=HARD NAME="Signature"><% $u->Signature %></TEXTAREA><br><br>
-<input type="submit" value="<&|/l&>Update signature</&>">
-</form>
- <& /Elements/TitleBoxEnd &>
- <form method=post>
- <&|/l&>Open tickets (from listing) in another window</&>: <input type="checkbox" name="NewWindowOption" <%exists $session{NewWindowOption} && "CHECKED"%>><br>
- <&|/l&>Open tickets (from listing) in a new window</&>: <input type="checkbox" name="AlwaysNewWindowOption" <%exists $session{AlwaysNewWindowOption} && "CHECKED"%>><br>
- <input type="submit" name="NewWindowSetting" value="<&|/l&>New window setting</&>">
- </form>
-%}
-
- <& /Elements/TitleBoxStart, title => loc('Email') &>
-<form method=post>
-<input type="hidden" name="id" value="<%$id%>">
-<input name="Email" value="<% $u->EmailAddress %>"><input type="submit" value="<&|/l&>Update email</&>">
-</form>
- <& /Elements/TitleBoxEnd &>
- <& /Elements/TitleBoxStart, title => loc('Real Name') &>
-<form method=post>
-<input type="hidden" name="id" value="<%$id%>">
-<input name="RealName" value="<% $u->RealName %>"><input type="submit" value="<&|/l&>Update name</&>">
-</form>
- <& /Elements/TitleBoxEnd &>
-
- <& /Elements/TitleBoxStart, title => loc('User ID') &>
-<form method=post>
-<input type="hidden" name="id" value="<%$id%>">
-<input name="Name" value="<% $u->Name %>"><input type="submit" value="<&|/l&>Update ID</&>">
-</form>
- <& /Elements/TitleBoxEnd &>
-
-%# TODO: alternative email addresses + merging users
-
-<%ARGS>
-$id => $session{CurrentUser} ? $session{CurrentUser}->Id : 0
-$Signature => undef
-$Email => undef
-$RealName => undef
-$Name => undef
-</%ARGS>
-
-<%INIT>
-require RT::User;
-my $u=RT::User->new($session{CurrentUser});
-$u->Load($id) || die loc("Couldn't load that user ([_1])", $id);
-if ($Signature) {
-my ($val, $msg)=$u->SetSignature($Signature);
-$RT::Logger->log(level=>($val ? 'info' : 'error'), message=>$msg);
-}
-
-if ($Email) {
-my ($val, $msg)=$u->SetEmailAddress($Email);
-$RT::Logger->log(level=>($val ? 'info' : 'error'), message=>$msg);
-}
-
-if ($RealName) {
-my ($val, $msg)=$u->SetRealName($RealName);
-$RT::Logger->log(level=>($val ? 'info' : 'error'), message=>$msg);
-}
-
-if ($Name) {
-my ($val, $msg)=$u->SetName($Name);
-$RT::Logger->log(level=>($val ? 'info' : 'error'), message=>$msg);
-}
-
-if ($ARGS{NewWindowSetting}) {
-if ($ARGS{NewWindowOption}) {
-$session{NewWindowOption}=1;
-} else {
-delete $session{NewWindowOption};
-}
-if ($ARGS{AlwaysNewWindowOption}) {
-$session{NewWindowOption}=1;
-$session{AlwaysNewWindowOption}=1;
-} else {
-delete $session{AlwaysNewWindowOption};
-}
-}
-
-</%INIT>
-
-
-
-
-
-
-
-
-
diff --git a/rt/html/Callbacks/ActivityReports/Elements/Tabs/Default b/rt/html/Callbacks/ActivityReports/Elements/Tabs/Default
new file mode 100644
index 000000000..f85d2e010
--- /dev/null
+++ b/rt/html/Callbacks/ActivityReports/Elements/Tabs/Default
@@ -0,0 +1,7 @@
+<%init>
+if ($ARGS{current_toptab} eq "Tools/Offline.html") {
+ $ARGS{tabs}{r} ||= { path => 'Reports/Activity/index.html',
+ title => 'Reports',
+ };
+}
+</%init> \ No newline at end of file
diff --git a/rt/html/Callbacks/ActivityReports/NoAuth/webrt.css/Default b/rt/html/Callbacks/ActivityReports/NoAuth/webrt.css/Default
new file mode 100644
index 000000000..30480f7b6
--- /dev/null
+++ b/rt/html/Callbacks/ActivityReports/NoAuth/webrt.css/Default
@@ -0,0 +1,71 @@
+table.miniplot {
+ width: 100%;
+ border-collapse: collapse;
+}
+table.miniplot td {
+ margin: 0;
+ padding: 0;
+ border-bottom: 1px solid black;
+}
+table.miniplot .graph {
+ margin-left: auto;
+ margin-right: auto;
+ position: relative;
+ width: 60px;
+}
+table.miniplot .graph ul {
+ height: 100px;
+ margin: 0;
+ padding: 0;
+}
+table.miniplot .graph ul li {
+ list-style: none;
+ position: absolute;
+ bottom: 0px;
+ padding: 0 !important;
+ margin: 0 !important;
+ border-bottom: none;
+}
+table.miniplot .graph ul li .data {
+ display: none;
+}
+
+.miniplot .demoblock { margin: 0 10px; padding: 0 30px; }
+
+.miniplot .c1 { border: 2px solid #990000; background: #ff0000; }
+.miniplot .c2 { border: 2px solid #996600; background: #ff9900; }
+.miniplot .c3 { border: 2px solid #009900; background: #00ff00; }
+.miniplot .c4 { border: 2px solid #009999; background: #00ffff; }
+.miniplot .c5 { border: 2px solid #000099; background: #0000ff; }
+.miniplot .c6 { border: 2px solid #990099; background: #ff00ff; }
+graph .c5 { border: 2px solid #000099; background: #0000ff; }
+.graph .c6 { border: 2px solid #990099; background: #ff00ff; }
+
+tr.titlerow th {
+
+ border-bottom: solid black 1px;
+ margin: 0;
+ font-size:80%;
+ text-wrap: none;
+
+}
+
+tr.grandtotal td{
+ border-top: 1px solid black;
+}
+
+tr.grandtotal th{
+ border-top: 1px solid black;
+}
+
+th.label {
+ align: left;
+
+}
+
+table.miniplot th.legend {
+ font-style: normal;
+ font-size: 80%;
+
+}
+
diff --git a/rt/html/Callbacks/ActivityReports/Search/Results.html/SearchActions b/rt/html/Callbacks/ActivityReports/Search/Results.html/SearchActions
new file mode 100644
index 000000000..4775a9af3
--- /dev/null
+++ b/rt/html/Callbacks/ActivityReports/Search/Results.html/SearchActions
@@ -0,0 +1,7 @@
+<a href="<% $RT::WebPath %>/Reports/Activity/index.html?<% $QueryString %>">Generate reports</a>
+<%init>
+use YAML;
+my %args = $m->caller_args(2);
+
+my $QueryString = $m->comp('/Elements/QueryString', query => $args{Query});
+</%init> \ No newline at end of file
diff --git a/rt/html/Callbacks/RT-WebCronTool/Elements/Tabs/Default b/rt/html/Callbacks/RT-WebCronTool/Elements/Tabs/Default
new file mode 100644
index 000000000..db74ced2d
--- /dev/null
+++ b/rt/html/Callbacks/RT-WebCronTool/Elements/Tabs/Default
@@ -0,0 +1,13 @@
+%# The day after tomorrow is the third day of the rest of your life.
+<%INIT>
+if ($session{'CurrentUser'}->UserObj->HasRight(
+ Right => 'SuperUser',
+ Object => $RT::System,
+)) {
+ $toptabs->{'ZZ-RT-WebCronTool'} = { title =>loc("Web CronTool"),
+ path => "Developer/CronTool/index.html" };
+}
+</%init>
+<%args>
+$toptabs =>undef
+</%args>
diff --git a/rt/html/Callbacks/kStatistics/Elements/Tabs/Default b/rt/html/Callbacks/kStatistics/Elements/Tabs/Default
new file mode 100644
index 000000000..d4ca2b95e
--- /dev/null
+++ b/rt/html/Callbacks/kStatistics/Elements/Tabs/Default
@@ -0,0 +1,11 @@
+<%init>
+use RTx::Statistics;
+if (($Statistics::RestrictAccess == 0) || ($session{'CurrentUser'}->HasRight( Right => 'ShowConfigTab',
+ Object => $RT::System ))) {
+ $toptabs->{'ZZ-RTx-STATS'} = { title => 'RTx-Statistics',
+ path => "RTx/Statistics/index.html" };
+}
+</%init>
+<%args>
+ $toptabs =>undef
+</%args>
diff --git a/rt/html/Developer/CronTool/autohandler b/rt/html/Developer/CronTool/autohandler
new file mode 100644
index 000000000..7daa09e8d
--- /dev/null
+++ b/rt/html/Developer/CronTool/autohandler
@@ -0,0 +1,9 @@
+%# All theoretical chemistry is really physics;
+%# and all theoretical chemists know it.
+%# -- Richard P. Feynman
+<%INIT>
+$m->call_next(%ARGS) if $session{'CurrentUser'}->UserObj->HasRight(
+ Right => 'SuperUser',
+ Object => $RT::System,
+);
+</%INIT>
diff --git a/rt/html/Developer/CronTool/index.html b/rt/html/Developer/CronTool/index.html
new file mode 100644
index 000000000..67c9e5634
--- /dev/null
+++ b/rt/html/Developer/CronTool/index.html
@@ -0,0 +1,116 @@
+% if ($@) {
+<P><FONT Color="red"><% $@ %></FONT></P>
+% }
+% if (!$NoUI) {
+<HR>
+<FORM Action="index.html" Method="POST">
+<TABLE>
+% foreach my $class (qw( Search Condition Action )) {
+<TR><TH>
+<% loc($class) %>
+</TH><TD>
+<SELECT NAME="<% $class %>">
+% require File::Find;
+% my @modules;
+% File::Find::find(sub {
+% push @modules, $1 if /^(?!Generic|UserDefined)(\w+)\.pm$/i;
+% }, grep -d, map "$_/RT/$class", @INC);
+<OPTION <% $ARGS{$class} ? '' : 'SELECTED' %>></OPTION>
+% foreach my $module (sort @modules) {
+% my $fullname = "RT::$class\::$module";
+ <OPTION VALUE="<% $fullname %>" <% ($fullname eq $ARGS{$class}) ? 'SELECTED' : '' %>><% $module %></OPTION>
+% }
+</SELECT>
+</TD><TH>
+<&|/l&>Parameter</&>
+</TH><TD>
+<INPUT NAME="<% $class %>Arg" VALUE="<% $ARGS{$class.'Arg'} %>">
+</TD></TR>
+% }
+<TR>
+<TD COLSPAN="4" ALIGN="Right">
+<LABEL>
+<INPUT TYPE="CheckBox" NAME="Verbose" <% $Verbose ? 'CHECKED' : '' %>><&|/l&>Verbose</&>
+</LABEL>
+<INPUT TYPE="Submit" VALUE="<&|/l&>Run</&>">
+</TD>
+</TABLE>
+</FORM>
+<HR>
+% }
+<%INIT>
+$m->print("<H1>", loc("Web CronTool"), "</H1>");
+if ($Search) {
+ my $load_module = sub {
+ my $modname = $_[0];
+ $modname =~ s{::}{/}g;
+ require "$modname.pm" or die (
+ loc( "Failed to load module [_1]. ([_2])", $_[0], $@ ) . "\n"
+ );
+ };
+ $m->print(loc("Starting..."), "<UL>");
+ eval {
+ $load_module->($Search);
+ $load_module->($Action) if $Action;
+ $load_module->($Condition) if $Condition;
+
+ if ($TemplateId and !$TemplateObj) {
+ $TemplateObj = RT::Template->new($RT::Nobody);
+ $TemplateObj->LoadById($TemplateId);
+ }
+
+ my $tickets = RT::Tickets->new($RT::SystemUser);
+ my $search = $Search->new( TicketsObj => $tickets, Argument => $SearchArg );
+ $search->Prepare;
+ my $tickets_found = $search->TicketsObj;
+
+ #for each ticket we've found
+ while ( my $ticket = $tickets_found->Next ) {
+ $m->print("<LI>" . $ticket->Id . ": ") if $Verbose;
+ $m->print(loc("Checking...")) if $Verbose;
+
+ # perform some more advanced check
+ if ($Condition) {
+ my $ConditionObj = $Condition->new(
+ TicketObj => $ticket,
+ Argument => $ConditionArg
+ );
+
+ # if the condition doesn't apply, get out of here
+ next unless ( $ConditionObj->IsApplicable );
+ $m->print(loc("Condition matches...")) if $Verbose;
+ }
+
+ if ($Action) {
+ #prepare our action
+ my $ActionObj = $Action->new(
+ TicketObj => $ticket,
+ TemplateObj => $TemplateObj,
+ Argument => $ActionArg
+ );
+
+ #if our preparation, move onto the next ticket
+ next unless ( $ActionObj->Prepare );
+ $m->print(loc("Action prepared...")) if $Verbose;
+
+ #commit our action.
+ next unless ( $ActionObj->Commit );
+ $m->print(loc("Action committed.")) if $Verbose;
+ }
+ }
+ };
+ $m->print('</UL>', loc("Finished."));
+}
+</%INIT>
+<%ARGS>
+$Search => undef
+$SearchArg => undef
+$Condition => undef
+$ConditionArg => undef
+$Action => undef
+$ActionArg => undef
+$TemplateId => undef
+$TemplateObj => undef
+$Verbose => 1
+$NoUI => 0
+</%ARGS>
diff --git a/rt/html/Elements/AddCustomers b/rt/html/Elements/AddCustomers
new file mode 100644
index 000000000..aaf8ca8ba
--- /dev/null
+++ b/rt/html/Elements/AddCustomers
@@ -0,0 +1,59 @@
+%# Copyright (c) 2004 Ivan Kohler <ivan-rt@420.am>
+%# Copyright (c) 2008 Freeside Internet Services, Inc.
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+<BR>
+<%$msg%><br>
+
+% if (@Customers) {
+
+<br><i>(Check box to link)<i>
+<table>
+% foreach my $customer (@Customers) {
+<tr>
+ <td>
+ <input type="checkbox" name="Object-AddCustomer-<% $customer->{'custnum'} %>" VALUE="1" <% scalar(@Customers) == 1 ? 'CHECKED' : '' %>>
+ <A HREF="<%$freeside_url%>/view/cust_main.cgi?<% $customer->{'custnum'} %>"><% &RT::URI::freeside::small_custview($customer->{'custnum'}, &RT::URI::freeside::FreesideGetConfig('countrydefault'), 1) |n %>
+ </td>
+</tr>
+% }
+</table>
+
+% }
+
+<%INIT>
+my ($msg);
+
+my $freeside_url = &RT::URI::freeside::FreesideURL();
+
+warn "/Elements/AddCustomers called with CustomerString $CustomerString\n"
+ if $Debug;
+
+my @Customers = ();
+if ( $CustomerString ) {
+ @Customers = &RT::URI::freeside::smart_search( 'search' => $CustomerString );
+}
+
+my @Services = ();
+if ($ServiceString) {
+ @Services = (); #service_search();
+}
+
+warn "/Elements/AddCustomers displaying ". scalar(@Customers). " customers\n"
+ if $Debug;
+
+</%INIT>
+
+<%ARGS>
+$CustomerString => undef
+$ServiceString => undef
+$Debug => 0
+</%ARGS>
diff --git a/rt/html/Elements/EditCustomers b/rt/html/Elements/EditCustomers
new file mode 100644
index 000000000..68efb5f40
--- /dev/null
+++ b/rt/html/Elements/EditCustomers
@@ -0,0 +1,63 @@
+%# Copyright (c) 2004 Ivan Kohler <ivan-rt@420.am>
+%# Copyright (c) 2008 Freeside Internet Services, Inc.
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+<TABLE width=100%>
+ <TR>
+ <TD VALIGN=TOP WIDTH=50%>
+ <h3><&|/l&>Current Customers</&></h3>
+
+<table>
+ <tr>
+ <td><i><&|/l&>(Check box to disassociate)</&></i></td>
+ </tr>
+ <tr>
+ <td class="value">
+% foreach my $link ( @{ $Object->Customers->ItemsArrayRef } ) {
+
+ <INPUT TYPE=CHECKBOX NAME="DeleteLink--<%$link->Type%>-<%$link->Target%>">
+%# <& ShowLink, URI => $link->TargetURI &><br>
+ <A HREF="<% $link->TargetURI->Resolver->HREF %>"><% $link->TargetURI->Resolver->AsStringLong |n %></A>
+ <BR>
+% }
+ </td>
+ </tr>
+</table>
+
+</TD>
+
+<TD VALIGN=TOP>
+<h3><&|/l&>New Customer Links</&></h3>
+<&|/l&>Find customer</&><BR>
+<input name="CustomerString">
+<input type=submit name="OnlySearchForCustomers" value="<&|/l&>Go!</&>">
+<br><i>cust #, name, company or phone</i>
+<BR>
+%#<BR>
+%#<&|/l&>Find service</&><BR>
+%#<input name="ServiceString">
+%#<input type=submit name="OnlySearchForServices" value="<&|/l&>Go!</&>">
+%#<br><i>username, username@domain, domain, or IP address</i>
+%#<BR>
+
+<& AddCustomers, Object => $Object,
+ CustomerString => $CustomerString,
+ ServiceString => $ServiceString, &>
+
+</TD>
+</TR>
+</TABLE>
+
+<%ARGS>
+$CustomerString => undef
+$ServiceString => undef
+$Object => undef
+</%ARGS>
diff --git a/rt/html/Elements/Footer b/rt/html/Elements/Footer
index c3d766258..914bbbd3b 100644
--- a/rt/html/Elements/Footer
+++ b/rt/html/Elements/Footer
@@ -47,25 +47,12 @@
%# END BPS TAGGED BLOCK }}}
%# End of div#body from /Elements/PageLayout
</div>
+</td>
+</tr>
+<tr>
+<td>
<& /Elements/Callback, %ARGS &>
-<div id="footer">
- <p id="time">
- <span><&|/l&>Time to display</&>: <%Time::HiRes::tv_interval( $m->{'rt_base_time'} )%></span>
- </p>
- <p id="bpscredits">
- <span>
-<&|/l, '&#187;&#124;&#171;', $RT::VERSION, '2009', '<a href="http://www.bestpractical.com?rt='.$RT::VERSION.'">Best Practical Solutions, LLC</a>', &>[_1] RT [_2] Copyright 1996-[_3] [_4].</&>
-</span>
-</p>
-% if (!$Menu) {
- <p id="legal">
-<&|/l&>Distributed under version 2 <a href="http://www.gnu.org/copyleft/gpl.html"> of the GNU GPL.</a></&><br />
-<&|/l, '<a href="mailto:sales@bestpractical.com">sales@bestpractical.com</a>' &>To inquire about support, training, custom development or licensing, please contact [_1].</&><br />
- </p>
-% }
-
-</div>
% if ($Debug >= 2 ) {
% require Data::Dumper;
% my $d = Data::Dumper->new([\%ARGS], [qw(%ARGS)]);
@@ -74,6 +61,10 @@
</pre>
% }
+</TD>
+</TR>
+</TABLE>
+
</body>
</html>
% $m->abort();
diff --git a/rt/html/Elements/FreesideInvoiceSearch b/rt/html/Elements/FreesideInvoiceSearch
new file mode 100644
index 000000000..3842b2ff9
--- /dev/null
+++ b/rt/html/Elements/FreesideInvoiceSearch
@@ -0,0 +1,20 @@
+% if ( $FS::CurrentUser::CurrentUser->access_right('View invoices') ) {
+
+ <form action="<% $RT::URI::freeside::URL %>/search/cust_bill.html" STYLE="margin:0">
+ <SCRIPT TYPE="text/javascript">
+ function clearhint_search_invoice (what) {
+ if ( what.value == '(inv #)' )
+ what.value = '';
+ }
+ </SCRIPT>
+ <input name="invnum" accesskey="0" VALUE="(inv #)" SIZE="4" onFocus="clearhint_search_invoice(this);" onClick="clearhint_search_invoice(this);" STYLE="text-align:right; margin-bottom:1px; font-family: Arial, Verdana, Helvetica, sans-serif;">
+
+% if ( $FS::CurrentUser::CurrentUser->access_right('List invoices') ) {
+ <A HREF="<% $RT::URI::freeside::URL %>search/report_cust_bill.html" STYLE="color: #ffffff; font-size: 70%; font-weight:normal">Advanced</A>
+% }
+ <BR>
+
+ <input type="submit" value="<&|/l&>Search invoices</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
+ </form>
+
+% }
diff --git a/rt/html/Elements/FreesideNewCust b/rt/html/Elements/FreesideNewCust
new file mode 100644
index 000000000..f60e99559
--- /dev/null
+++ b/rt/html/Elements/FreesideNewCust
@@ -0,0 +1,3 @@
+<form action="<% $RT::URI::freeside::URL %>/edit/cust_main.cgi" STYLE="margin:0">
+<INPUT TYPE="submit" VALUE="<&|/l&>New customer</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="vertical-align:bottom; font-size:100%">&nbsp;
+</FORM>
diff --git a/rt/html/Elements/FreesideSearch b/rt/html/Elements/FreesideSearch
new file mode 100644
index 000000000..8e609bb4b
--- /dev/null
+++ b/rt/html/Elements/FreesideSearch
@@ -0,0 +1,13 @@
+% if ( $FS::CurrentUser::CurrentUser->access_right('List customers') ) {
+<form action="<% $RT::URI::freeside::URL %>/search/cust_main.cgi" STYLE="margin:0">
+ <SCRIPT TYPE="text/javascript">
+ function clearhint_search_cust (what) {
+ if ( what.value == '(cust #, name, company or phone)' )
+ what.value = '';
+ }
+ </SCRIPT>
+<input name="search_cust" accesskey="0" VALUE="(cust #, name, company or phone)" SIZE="28" onFocus="clearhint_search_cust(this);" onClick="clearhint_search_cust(this);" STYLE="text-align:right; font-family: Arial, Verdana, Helvetica, sans-serif;"><BR>
+<A HREF="<% $RT::URI::freeside::URL %>/search/report_cust_main.html" STYLE="color: #ffffff; font-size: 70%; font-weight:normal">Advanced</A>
+<input type="submit" value="<&|/l&>Search customers</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
+</form>
+% }
diff --git a/rt/html/Elements/FreesideSvcSearch b/rt/html/Elements/FreesideSvcSearch
new file mode 100644
index 000000000..d68122da5
--- /dev/null
+++ b/rt/html/Elements/FreesideSvcSearch
@@ -0,0 +1,13 @@
+% if ( $FS::CurrentUser::CurrentUser->access_right('View customer services') ) {
+<form action="<% $RT::URI::freeside::URL %>/search/cust_svc.html" STYLE="margin:0">
+ <SCRIPT TYPE="text/javascript">
+ function clearhint_search_svc (what) {
+ if ( what.value == '(user, user@domain or domain)' )
+ what.value = '';
+ }
+ </SCRIPT>
+<input name="search_svc" accesskey="0" VALUE="(user, user@domain or domain)" SIZE="26" onFocus="clearhint_search_svc(this);" onClick="clearhint_search_svc(this);" STYLE="text-align:right; font-family: Arial, Verdana, Helvetica, sans-serif;"><BR>
+ <A NOTYET="<% $RT::URI::freeside::URL %>search/svc_Smarter.html" STYLE="color: #000000; font-size: 70%; font-weight:normal">Advanced</A>
+<input type="submit" value="<&|/l&>Search services</&>" CLASS="fsblackbutton" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%">
+</form>
+% }
diff --git a/rt/html/Elements/Header b/rt/html/Elements/Header
index 02450b1e0..571da6c90 100644
--- a/rt/html/Elements/Header
+++ b/rt/html/Elements/Header
@@ -45,70 +45,24 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<!DOCTYPE html
- PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<% include( '/elements/header.html', {
+ 'title' => $Title,
+ 'head' => $head,
+ 'nobr' => 1,
+ 'nocss' => 1,
+ }) |n
+%>
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
-
-<title><%$Title%></title>
-
-% if ($Refresh && $Refresh > 0) {
- <meta http-equiv="refresh" content="<%$Refresh%>" />
-% }
-
-<link rel="shortcut icon" href="<%$RT::WebImagesURL%>/favicon.png" type="image/png" />
-<link rel="stylesheet" href="<%$RT::WebPath%>/NoAuth/css/<% $RT::WebDefaultStylesheet %>/main-squished.css" type="text/css" media="all" />
-<link rel="stylesheet" href="<%$RT::WebPath%>/NoAuth/css/print.css" type="text/css" media="print" />
-
-% if ( $RSSAutoDiscovery ) {
- <link rel="alternate" href="<%$RSSAutoDiscovery%>" type="application/rss+xml" title="RSS RT Search" />
-% }
-
-<script type="text/javascript" src="<%$RT::WebPath%>/NoAuth/js/util.js"></script>
-<script type="text/javascript" src="<%$RT::WebPath%>/NoAuth/js/ahah.js"></script>
-<script type="text/javascript" src="<%$RT::WebPath%>/NoAuth/js/titlebox-state.js"></script>
-<script type="text/javascript"><!--
- onLoadHook("loadTitleBoxStates()");
-% if ( $Focus ) {
- onLoadHook("focusElementById('<% $Focus %>')");
-% }
-% if ( $onload ) {
- onLoadHook("<% $onload |n %>");
-% }
---></script>
-
-<& /Elements/Callback, _CallbackName => 'Head', %ARGS &>
-
-</head>
- <body<% $id && qq[ id="comp-$id"] |n %>>
-
-% if ($ShowBar) {
-<& /Elements/Logo &>
-
-<div id="quickbar">
- <div id="quick-personal">
- <span class="hide"><a href="#skipnav"><&|/l&>Skip Menu</&></a> | </span>
-% if ($session{'CurrentUser'}->Name) {
- <&|/l, "<span>".$session{'CurrentUser'}->Name."</span>" &>Logged in as [_1]</&>
-% if ($session{'CurrentUser'}->HasRight( Right => 'ModifySelf', Object => $RT::System )) {
- | <a href="<%$RT::WebPath%><%$Prefs%>"><&|/l&>Preferences</&></a>
-% }
-% } else {
- <&|/l&>Not logged in.</&>
-% }
- <& /Elements/Callback, %ARGS &>
-% unless (!$session{'CurrentUser'}->Name
-% or ($RT::WebExternalAuth and !$RT::WebFallbackToInternalAuth)) {
- | <a href="<%$RT::WebPath%>/NoAuth/Logout.html<%$URL ? "?URL=".$URL : ''%>"><&|/l&>Logout</&></a>
-% }
- </div>
-% }
+%# if ($session{'CurrentUser'}->HasRight( Right => 'ModifySelf', Object => $RT::System )) {
+%# | <a href="<%$RT::WebPath%><%$Prefs%>"><&|/l&>Preferences</&></a>
+%# }
<%INIT>
$r->headers_out->{'Pragma'} = 'no-cache';
$r->headers_out->{'Cache-control'} = 'no-cache';
+require RT::URI::freeside;
+
my $id = $m->request_comp->path;
$id =~ s|^/||g;
$id =~ s|/|-|g;
@@ -116,6 +70,45 @@ $id =~ s|\.html$||g;
$id =~ s|index$||g
if $id ne 'index';
$id =~ s|-$||g;
+
+my $head = '';
+
+if ($Refresh && $Refresh > 0) {
+ $head .= '<meta http-equiv="refresh" content="$Refresh" />';
+}
+
+$head .= <<END;
+<link rel="shortcut icon" href="$RT::WebImagesURL/favicon.png" type="image/png" />
+<link rel="stylesheet" href="$RT::WebPath/NoAuth/css/$RT::WebDefaultStylesheet/main-squished.css" type="text/css" media="all" />
+<link rel="stylesheet" href="$RT::WebPath/NoAuth/css/print.css" type="text/css" media="print" />
+END
+
+if ( $RSSAutoDiscovery ) {
+ $head .= qq(<link rel="alternate" href="$RSSAutoDiscovery" type="application/rss+xml" title="RSS RT Search" />);
+}
+
+$head .= <<END;
+<script type="text/javascript" src="$RT::WebPath/NoAuth/js/util.js"></script>
+<script type="text/javascript" src="$RT::WebPath/NoAuth/js/ahah.js"></script>
+<script type="text/javascript" src="$RT::WebPath/NoAuth/js/titlebox-state.js"></script>
+<script type="text/javascript"><!--
+ onLoadHook("loadTitleBoxStates()");
+END
+
+if ( $Focus ) {
+ $head .= qq{ onLoadHook("focusElementById('$Focus')");\n};
+}
+if ( $onload ) {
+ $head .= qq{ onLoadHook("$onload");\n};
+}
+
+$head .= '--></script>';
+
+$head .= $m->scomp( '/Elements/Callback', _CallbackName => 'Head', %ARGS );
+
+my $etc = '';
+$etc .= qq[ id="comp-$id"] if $id;
+
</%INIT>
<%ARGS>
diff --git a/rt/html/Elements/PageLayout b/rt/html/Elements/PageLayout
index 6897ede1a..3185662e1 100644
--- a/rt/html/Elements/PageLayout
+++ b/rt/html/Elements/PageLayout
@@ -45,34 +45,116 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
- <div id="topactions">
-% foreach my $action (reverse sort keys %{$topactions}) {
- <span class="topaction">
-% $m->out($topactions->{"$action"}->{'html'});
- </span>
-% }
- </div>
+% #false laziness w/menubar.html... shouldn't these just go in freeside.css?
+<style type="text/css">
+a.fsblackbutton {
+ background-color:#333333;
+ color: #ffffff;
+ border:1px solid;
+ border-top-color:#cccccc;
+ border-left-color:#cccccc;
+ border-right-color:#aaaaaa;
+ border-bottom-color:#aaaaaa;
+ /*font-weight:bold;*/
+ /*padding-left:12px;
+ padding-right:12px;*/
+ padding-left:4px;
+ padding-right:4px;
+ font-size:16px;
+ text-decoration:none;
+ overflow:visible;
+ filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff333333',EndColorStr='#ff666666')
+}
-%# End of div#quickbar from /Elements/Header
-</div>
+a.fsblackbuttonselected,
+a:link:hover.fsblackbutton,
+a:visited:hover.fsblackbutton {
+ background-color:#7e0079;
+ color: #ffffff;
+ border:1px solid;
+ border-top-color:#cccccc;
+ border-left-color:#cccccc;
+ border-right-color:#aaaaaa;
+ border-bottom-color:#aaaaaa;
+ /*font-weight:bold;*/
+ /*padding-left:12px;
+ padding-right:12px;*/
+ padding-left:4px;
+ padding-right:4px;
+ font-size:16px;
+ text-decoration:none;
+ overflow:visible;
+ filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff330033',EndColorStr='#ff7e0079')
+}
+
+a.fsdarkbutton {
+ background-color:#555555;
+ color: #ffffff;
+ border:1px solid;
+ border-top-color:#cccccc;
+ border-left-color:#cccccc;
+ border-right-color:#aaaaaa;
+ border-bottom-color:#aaaaaa;
+ /*font-weight:bold;*/
+ /*padding-left:12px;
+ padding-right:12px;*/
+ padding-left:4px;
+ padding-right:4px;
+ font-size:16px;
+ text-decoration:none;
+ overflow:visible;
+ filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff555555',EndColorStr='#ff666666')
+}
+
+a.fsdarkbuttonselected,
+a:link:hover.fsdarkbutton,
+a:visited:hover.fsdarkbutton {
+ background-color:#7e0079;
+ color: #ffffff;
+ border:1px solid;
+ border-top-color:#cccccc;
+ border-left-color:#cccccc;
+ border-right-color:#aaaaaa;
+ border-bottom-color:#aaaaaa;
+ /*font-weight:bold;*/
+ /*padding-left:12px;
+ padding-right:12px;*/
+ padding-left:4px;
+ padding-right:4px;
+ font-size:16px;
+ text-decoration:none;
+ overflow:visible;
+ filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr='#ff330033',EndColorStr='#ff7e0079')
+}
+</style>
+<% include('/elements/init_calendar.html') |n %>
+<table border=0 cellspacing=0 cellpadding=0 width="100%" height="100%">
+ <TR HEIGHT="100%">
+ <TD valign="top">
-% if ( $show_menu ) {
+% if (0) { ##FREESIDE MENUS INSTEAD## if ( $show_menu ) {
+%# if ( $show_menu ) {
<div id="nav">
<& /Elements/Menu, toptabs => $toptabs, current_toptab => $current_toptab &>
</div>
% }
-<div id="header">
- <h1><%$title%></h1>
+%#already shown <h1><%$title%></h1>
% my $sep = 0;
% my $postsep = 0;
% my $count = 0;
% my $class = { };
%
- <ul id="page-menu"<% (($actions && %$actions) || ($subactions && %$subactions)) && q[ class="actions-present"] | n %>>
- <div><div><div>
+
+ <TABLE BGCOLOR="#000000" BORDER=0 CELLSPACING=0 CELLPADDING=0>
+ <TR>
+
+%# <ul id="page-menu"<% (($actions && %$actions) || ($subactions && %$subactions)) && q[ class="actions-present"] | n %>>
+
% if ($page_tabs) {
+ <TD><IMG SRC="<%$fsurl%>images/gray-black-side.png" WIDTH=13 HEIGHT=25></TD>
+ <TD>
% foreach my $tab (sort keys %{$page_tabs}) {
% next if $tab =~ /^(?:current_toptab|this)$/;
% $count++;
@@ -100,22 +182,24 @@
% $class->{li} = join ' ', @li;
%
%
- <li<% $class->{li} ? qq[ class="$class->{li}"] : ''|n %>><% $count > 1 && !$postsep && "&#183; "|n%><a href="<%$RT::WebPath%>/<%$page_tabs->{$tab}->{'path'}%>"<%$class->{a}|n%><% $class->{a} ? ' name="focus"' : ''|n %>><% $page_tabs->{$tab}->{'title'} %></a></li>
-%
-% if ($sep) {
- <li class="separator">&#183;&#183;&#183;</li>
-% }
-% $postsep = $sep;
+
+%# <li<% $class->{li} ? qq[ class="$class->{li}"] : ''|n %>><% $count > 1 && !$postsep && "&#183; "|n%><a href="<%$RT::WebPath%>/<%$page_tabs->{$tab}->{'path'}%>"<%$class->{a}|n%><% $class->{a} ? ' name="focus"' : ''|n %>><% $page_tabs->{$tab}->{'title'} %></a></li>
+
+% $class->{a} = $path eq $current ? ' class="fsblackbuttonselected"' : ' class="fsblackbutton"';
+ <a href="<%$RT::WebPath%>/<%$page_tabs->{$tab}->{'path'}%>"<%$class->{a}|n%><% $class->{a} =~ 'selected' ? ' name="focus"' : ''|n %>><% $page_tabs->{$tab}->{'title'} %></a>
+
% }
-% } else {
-&nbsp;
+ </TD>
+%# } else {
+%#&nbsp;
% }
- </div></div></div>
- </ul>
% if (($actions && %$actions) || ($subactions && %$subactions)) {
- <ul id="actions-menu">
- <div><div><div>
+ <TD><IMG SRC="<%$fsurl%>images/<% $page_tabs ? 'black-gray' : 'gray-black' %>-side.png" WIDTH=13 HEIGHT=25></TD>
+% if ( $page_tabs ) {
+ <TD BGCOLOR="#333333">&nbsp;&nbsp;</TD>
+% }
+ <TD BGCOLOR="#333333">
% $sep = 0;
% $postsep = 0;
% $count = 0;
@@ -141,24 +225,30 @@
%
% $class->{li} = join ' ', @li;
%
- <li<% $class->{li} ? qq[ class="$class->{li}"] : ''|n %>><% $count > 1 && !$postsep && qq[<span class="bullet">&#183; </span>]|n%>
+
+%# <li<% $class->{li} ? qq[ class="$class->{li}"] : ''|n %>><% $count > 1 && !$postsep && qq[<span class="bullet">&#183; </span>]|n%>
+
+% #$class->{a} = $path eq $current ? ' class="fsblackbuttonselected"' : ' class="fsblackbutton"';
+% $type->{$action}->{class} ||= 'fsdarkbutton';
+
% if ($type->{"$action"}->{'html'}) {
<% $type->{"$action"}->{'html'} | n %>
% } else {
<a href="<%$RT::WebPath%>/<%$type->{$action}->{'path'}%>"<% $type->{$action}->{class} && ' class="'.$type->{$action}->{class}.'"' |n %><% $type->{$action}->{id} && ' id="'.$type->{$action}->{id}.'"' |n %>><%$type->{$action}->{'title'}%></a>
% }
- </li>
-% if ($sep) {
- <li class="separator">&#183;&#183;&#183;</li>
-% }
-% $postsep = $sep;
+
% }
% }
% }
- </div></div></div>
- </ul>
+
+ </TD>
+
% }
-</div>
+
+ <TD><IMG SRC="<%$fsurl%>images/black-gray-side.png" WIDTH=13 HEIGHT=25></TD>
+ </TR>
+</TABLE>
+
<div id="body">
<& /Elements/Callback, _CallbackName => 'BeforeBody', %ARGS &>
diff --git a/rt/html/Elements/QuickCreate b/rt/html/Elements/QuickCreate
index 5669a4544..83d3a0d38 100644
--- a/rt/html/Elements/QuickCreate
+++ b/rt/html/Elements/QuickCreate
@@ -47,11 +47,11 @@
%# END BPS TAGGED BLOCK }}}
<div class="quick-create">
<&| /Widgets/TitleBox, title => loc('Quick ticket creation') &>
-<form method="post" action="<%$RT::WebPath%>/index.html">
+<form method="post" action="<%$RT::WebPath%>/<% $RT::QuickCreateLong ? 'Ticket/Create.html' : 'index.html' %>">
<input type="hidden" class="hidden" name="QuickCreate" value="1" />
<table>
<tr><td>
-<&|/l&>Subject</&>:<br /><input size="15" name="Subject" />
+<&|/l&>Subject</&>:<br /><input size="30" name="Subject" />
</td><td>
<&|/l&>Queue</&>:<br /><& /Elements/SelectNewTicketQueue, Name => 'Queue', ShowNullOption => 0 &>
</td><td>
diff --git a/rt/html/Elements/SelectDate b/rt/html/Elements/SelectDate
index 5767074fb..d911cf713 100644
--- a/rt/html/Elements/SelectDate
+++ b/rt/html/Elements/SelectDate
@@ -45,10 +45,21 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+%# in PageLayout instead, once <% include('/elements/init_calendar.html') |n %>
+<input type="text" id="<% $Name %>" name="<% $Name %>" value="<% $Default %>" size="<% $Size %>" />
+<IMG SRC="<%$fsurl%>images/calendar.png" ID="<% $Name %>_date_button" STYLE="cursor: pointer" TITLE="Select date">
<script type="text/javascript"><!--
- onLoadHook('createCalendarLink("<% $Name %>");');
+Calendar.setup({
+ inputField: "<%$Name%>",
+% if ( defined($ShowTime) && $ShowTime ) {
+ ifFormat: "%Y-%m-%d %H:%M",
+ showsTime: true,
+% } else {
+ ifFormat: "%Y-%m-%d",
+% }
+ button: "<%$Name%>_date_button",
+});
--></script>
-<input type="text" id="<% $Name %>" name="<% $Name %>" value="<% $Default %>" size="<% $Size %>" />
<%init>
unless ((defined $Default) or
($current <= 0)) {
diff --git a/rt/html/Elements/ShadedBox b/rt/html/Elements/ShadedBox
deleted file mode 100644
index 36b9cae7c..000000000
--- a/rt/html/Elements/ShadedBox
+++ /dev/null
@@ -1,33 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<table>
- <tr>
- <td class="label"><%$title |n %>:</td>
- <td class="value"><%$content |n %></td>
- </tr>
-</table>
-<%ARGS>
-$title => undef
-$content => "&nbsp;"
-</%ARGS>
diff --git a/rt/html/Elements/ShadedInputRow b/rt/html/Elements/ShadedInputRow
deleted file mode 100644
index e9fb69e5f..000000000
--- a/rt/html/Elements/ShadedInputRow
+++ /dev/null
@@ -1,35 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<tr>
- <td class="label"><%$title |n %>:</td>
- <td class="value">
- <input name=<%$name%> value="<%$content|h%>" SIZE=<%$size%>>
- </td>
-</tr>
-<%ARGS>
-$title => undef
-$content => "&nbsp;"
-$name => undef
-$size => undef
-</%ARGS>
diff --git a/rt/html/Elements/ShadedRow b/rt/html/Elements/ShadedRow
deleted file mode 100644
index 8947fcd82..000000000
--- a/rt/html/Elements/ShadedRow
+++ /dev/null
@@ -1,31 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<tr>
- <td class="label"><%$title |n %>:</td>
- <td class="value"><%$content |n %></td>
-</tr>
-<%ARGS>
-$title => undef
-$content => "&nbsp;"
-</%ARGS>
diff --git a/rt/html/Elements/SimpleSearch b/rt/html/Elements/SimpleSearch
index 2876a2957..5f83da03e 100644
--- a/rt/html/Elements/SimpleSearch
+++ b/rt/html/Elements/SimpleSearch
@@ -45,7 +45,14 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<form action="<% $RT::WebPath %>/Search/Simple.html">
- <input size="12" name="q" autocomplete="off" accesskey="0" class="field" />
- <input type="submit" class="button" value="<&|/l&>Search</&>" />
+<form action="<% $RT::WebPath %>/Search/Simple.html" STYLE="margin:0">
+<SCRIPT TYPE="text/javascript">
+ function clearhint_search_ticket (what) {
+ if ( what.value == '(ticket # or subject string)' )
+ what.value = '';
+ }
+</SCRIPT>
+<input name="q" autocomplete="off" accesskey="0" class="field" VALUE="(ticket # or subject string)" onFocus="clearhint_search_ticket(this);" onClick="clearhint_search_ticket(this);" STYLE="text-align:right; font-family: Arial, Verdana, Helvetica, sans-serif;"><BR>
+<A HREF="<% $RT::WebPath %>/Search/Build.html" STYLE="color: #ffffff; font-size: 70%; font-weight:normal">Advanced</A>
+<input type="submit" class="fsblackbutton" value="<&|/l&>Search tickets</&>" onMouseOver="this.className='fsblackbuttonselected'; return true;" onMouseOut="this.className='fsblackbutton'; return true;" STYLE="font-size:70%;padding-left:2px;padding-right:2px">
</form>
diff --git a/rt/html/Elements/Tabs b/rt/html/Elements/Tabs
index 3b0f3da6d..7b3d80928 100644
--- a/rt/html/Elements/Tabs
+++ b/rt/html/Elements/Tabs
@@ -59,19 +59,18 @@
<a name="skipnav" id="skipnav" accesskey="8"></a>
<%INIT>
my $action;
-my $basetopactions = {
- A => { html => $m->scomp('/Elements/CreateTicket')
- },
- B => { html => $m->scomp('/Elements/SimpleSearch')
- }
- };
-my $basetabs = { A => { title => loc('Homepage'),
+my $basetabs = {
+ ' A'=> { title => 'Billing Main',
+ path => &RT::URI::freeside::FreesideURL(),
+ },
+ A => { #title => loc('Homepage'),
+ title => 'Ticketing Main',
path => '',
},
- Ab => { title => loc('Simple Search'),
+ Ab => { title => loc('Simple Ticket Search'),
path => 'Search/Simple.html'
},
- B => { title => loc('Tickets'),
+ B => { title => loc('Adv. Ticket Search'),
path => 'Search/Build.html'
},
C => { title => loc('Tools'),
@@ -99,9 +98,8 @@ if ($session{'CurrentUser'}->HasRight( Right => 'ModifySelf',
if (!defined $toptabs) {
$toptabs = $basetabs;
}
-if (!defined $topactions) {
- $topactions = $basetopactions;
-}
+
+ require RT::URI::freeside;
# Now let callbacks add their extra tabs
$m->comp('/Elements/Callback',
diff --git a/rt/html/Elements/TicketList b/rt/html/Elements/TicketList
index 81e265d93..7f715d921 100644
--- a/rt/html/Elements/TicketList
+++ b/rt/html/Elements/TicketList
@@ -65,7 +65,8 @@
% while (my $record = $Collection->Next) {
% $i++;
% # Every ten rows, flush the buffer and put something on the page.
-% $m->flush_buffer() unless ($i % 10);
+% # hun, this flushes things out out-of-order for me on "RT at a glance"...?
+% # $m->flush_buffer() unless ($i % 10);
<& /Elements/CollectionAsTable/Row, Format => \@Format, i => $i, record => $record, maxitems => $maxitems &>
% }
diff --git a/rt/html/Elements/ViewUser b/rt/html/Elements/ViewUser
deleted file mode 100644
index 657272496..000000000
--- a/rt/html/Elements/ViewUser
+++ /dev/null
@@ -1,51 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<& /Elements/TitleBoxStart,
- title => "<a class='inverse' href=\"$RT::WebPath/Search/Listing.html?LimitRequestorById=1&IdOfRequestor=".$User->id."\">".loc("Tickets from [_1]", $name)."</a>",
- titleright=> "<a class='inverse' href=\"$RT::WebPath/EditUserComments.html?id=".$User->id."\">".loc("Comments about [_1]", $name)."</a>" &>
-<TABLE WIDTH="100%">
-<tr>
-<td halign=left valign=top>
-%while (my $w=$tickets->Next) {
-<%$w->Id%>: <a href="<%$RT::WebPath%>/Ticket/Display.html?id=<%$w->id%>"><%$w->Subject%></a> (<%$w->Status%>)<BR>
-%}
-</td>
-<td align=right valign=top>
- <% ($User->Comments || loc("No comment entered about this user")) %>
-</tr>
-</table>
-<& /Elements/TitleBoxEnd &>
-
-<%ARGS>
-$User=>undef
-</%ARGS>
-
-<%INIT>
-my $name=$User->RealName || $User->EmailAddress;
-
-my $tickets = new RT::Tickets($session{'CurrentUser'});
-$tickets->LimitWatcher(TYPE => 'Requestor', VALUE => $User->EmailAddress);
-
-
-</%INIT>
diff --git a/rt/html/NoAuth/css/3.5-default/freeside.css b/rt/html/NoAuth/css/3.5-default/freeside.css
new file mode 100644
index 000000000..5e7e0a04a
--- /dev/null
+++ b/rt/html/NoAuth/css/3.5-default/freeside.css
@@ -0,0 +1,9 @@
+
+div.titlebox {
+ background: #d4d4d4;
+}
+
+div.titlebox-title {
+ background: #e8e8e8;
+}
+
diff --git a/rt/html/NoAuth/css/3.5-default/main.css b/rt/html/NoAuth/css/3.5-default/main.css
index 3a5fdfb5d..ed4a6989c 100644
--- a/rt/html/NoAuth/css/3.5-default/main.css
+++ b/rt/html/NoAuth/css/3.5-default/main.css
@@ -58,4 +58,5 @@
@import "nav.css";
@import "header.css";
@import "footer.css";
+@import "freeside.css";
diff --git a/rt/html/NoAuth/css/3.5-default/misc.css b/rt/html/NoAuth/css/3.5-default/misc.css
index 038e65def..981dea36d 100755
--- a/rt/html/NoAuth/css/3.5-default/misc.css
+++ b/rt/html/NoAuth/css/3.5-default/misc.css
@@ -46,10 +46,12 @@
%#
%# END BPS TAGGED BLOCK }}}
body {
- font-family: Verdana, sans-serif;
+ /* font-family: Verdana, sans-serif; */
+ font-family: Arial, Verdana, Helvetica, sans-serif;
font-size: 76%;
margin: 0;
- background-color: white;
+ /* background-color: white; */
+ background-color: #e8e8e8;
}
.hide, .hidden { display: none !important; }
@@ -73,9 +75,11 @@ body {
.evenline { background-color: white; }
.oddline { background-color: #ddd; }
+/*
td {
padding: 0.1em 0.5em 0.1em 0.5em;
}
+*/
.clear { clear: both; }
diff --git a/rt/html/NoAuth/css/3.5-default/titlebox.css b/rt/html/NoAuth/css/3.5-default/titlebox.css
index 3bd4e97cf..82961bb38 100644
--- a/rt/html/NoAuth/css/3.5-default/titlebox.css
+++ b/rt/html/NoAuth/css/3.5-default/titlebox.css
@@ -51,7 +51,8 @@
.titlebox .titlebox-content {
margin-top: -1px;
- padding: 1em 2em 0.5em 2em;
+ padding: 0.25em .50em 0.125em .50em;
+ /*padding: 1em 2em 0.5em 2em;*/
margin: 0;
/*margin: 1em 2em 0.5em 2em;*/
}
diff --git a/rt/html/NoAuth/css/3.5-default/transactions.css b/rt/html/NoAuth/css/3.5-default/transactions.css
index fdf8ea824..fee5c52f2 100755
--- a/rt/html/NoAuth/css/3.5-default/transactions.css
+++ b/rt/html/NoAuth/css/3.5-default/transactions.css
@@ -57,6 +57,10 @@
.ticket-transaction.even {
background: #eee;
}
+.ticket-transaction.odd {
+ background: #fff;
+}
+
.ticket-transaction .date {
font-size: 0.9em;
diff --git a/rt/html/NoAuth/images/back_home.gif b/rt/html/NoAuth/images/back_home.gif
deleted file mode 100644
index 40b19c153..000000000
--- a/rt/html/NoAuth/images/back_home.gif
+++ /dev/null
Binary files differ
diff --git a/rt/html/NoAuth/images/css/cb.gif b/rt/html/NoAuth/images/css/cb.gif
index 53bb2aec2..49a4a97b6 100644
--- a/rt/html/NoAuth/images/css/cb.gif
+++ b/rt/html/NoAuth/images/css/cb.gif
Binary files differ
diff --git a/rt/html/NoAuth/images/css/cbr.gif b/rt/html/NoAuth/images/css/cbr.gif
index 754cee19b..eeb7ff444 100644
--- a/rt/html/NoAuth/images/css/cbr.gif
+++ b/rt/html/NoAuth/images/css/cbr.gif
Binary files differ
diff --git a/rt/html/NoAuth/images/css/ct.gif b/rt/html/NoAuth/images/css/ct.gif
index d16a5c57f..d2ae8d8ae 100644
--- a/rt/html/NoAuth/images/css/ct.gif
+++ b/rt/html/NoAuth/images/css/ct.gif
Binary files differ
diff --git a/rt/html/NoAuth/images/css/ctr.gif b/rt/html/NoAuth/images/css/ctr.gif
index 9754e1567..d17e647c0 100644
--- a/rt/html/NoAuth/images/css/ctr.gif
+++ b/rt/html/NoAuth/images/css/ctr.gif
Binary files differ
diff --git a/rt/html/NoAuth/images/head_requestracker.gif b/rt/html/NoAuth/images/head_requestracker.gif
deleted file mode 100644
index 73315e918..000000000
--- a/rt/html/NoAuth/images/head_requestracker.gif
+++ /dev/null
Binary files differ
diff --git a/rt/html/NoAuth/images/rt.jpg b/rt/html/NoAuth/images/rt.jpg
deleted file mode 100644
index a137a932b..000000000
--- a/rt/html/NoAuth/images/rt.jpg
+++ /dev/null
Binary files differ
diff --git a/rt/html/NoAuth/images/small-logo.png b/rt/html/NoAuth/images/small-logo.png
new file mode 100644
index 000000000..1e415e6d8
--- /dev/null
+++ b/rt/html/NoAuth/images/small-logo.png
Binary files differ
diff --git a/rt/html/NoAuth/images/space.gif b/rt/html/NoAuth/images/space.gif
deleted file mode 100644
index 1d11fa9ad..000000000
--- a/rt/html/NoAuth/images/space.gif
+++ /dev/null
Binary files differ
diff --git a/rt/html/NoAuth/images/spacer.gif b/rt/html/NoAuth/images/spacer.gif
deleted file mode 100644
index 5bfd67a2d..000000000
--- a/rt/html/NoAuth/images/spacer.gif
+++ /dev/null
Binary files differ
diff --git a/rt/html/NoAuth/images/squares_blue.gif b/rt/html/NoAuth/images/squares_blue.gif
deleted file mode 100644
index a28da5ce1..000000000
--- a/rt/html/NoAuth/images/squares_blue.gif
+++ /dev/null
Binary files differ
diff --git a/rt/html/NoAuth/printrt.css b/rt/html/NoAuth/printrt.css
deleted file mode 100644
index 72e7e8b7e..000000000
--- a/rt/html/NoAuth/printrt.css
+++ /dev/null
@@ -1,77 +0,0 @@
-%# {{{ BEGIN BPS TAGGED BLOCK
-%#
-%#
-%#
-%# LICENSE:
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# You should have received a copy of the GNU General Public License
-%# along with this program; if not, write to the Free Software
-%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-%#
-%#
-%# CONTRIBUTION SUBMISSION POLICY:
-%#
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%#
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%#
-%# }}} END BPS TAGGED BLOCK
-%#
-%# Special stylesheet for printing tickets
-%# Koos van den Hout koos@cs.uu.nl 2005-11-21
-%#
-
-SPAN.nav { display: none !important; }
-.nav2 { display: none !important; }
-.nav { display: none !important; }
-.topnav { display: none !important; }
-.blue { display: none !important; }
-.darkblue { display: none !important; }
-.blueright { display: none !important; }
-.currentnav { display: none !important; }
-th.titlebox { border-top: none; border-bottom: none; }
-th.titleboxright { display:none !important; border-top: none; border-bottom: none; }
-.titlebox { border-top: none; border-bottom: none; }
-
-div.downloadattachment, div.downloadcontenttype {
- display: none !important;
-}
-
-
-a[href$="Respond"], a[href$="Comment"], a[href*="ShowEmailRecord"] {
- display: none !important;
-}
-
-
-%# Provide a callback for adding/modifying the style sheet.
-%# http://www.w3.org/TR/REC-CSS1 - section 3.2, says:
-%# "latter specified rule wins"
-<& /Elements/Callback &>
-<%flags>
-inherit => undef
-</%flags>
-<%init>
-$r->content_type('text/css');
-$r->headers_out->{'Expires'} = '+30m';
-</%init>
diff --git a/rt/html/NoAuth/webrt.css b/rt/html/NoAuth/webrt.css
deleted file mode 100644
index 7fa2f83f8..000000000
--- a/rt/html/NoAuth/webrt.css
+++ /dev/null
@@ -1,628 +0,0 @@
-%# BEGIN BPS TAGGED BLOCK {{{
-%#
-%# COPYRIGHT:
-%#
-%# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
-%# <jesse@bestpractical.com>
-%#
-%# (Except where explicitly superseded by other copyright notices)
-%#
-%#
-%# LICENSE:
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# You should have received a copy of the GNU General Public License
-%# along with this program; if not, write to the Free Software
-%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-%#
-%#
-%# CONTRIBUTION SUBMISSION POLICY:
-%#
-%# (The following paragraph is not intended to limit the rights granted
-%# to you to modify and distribute this software under the terms of
-%# the GNU General Public License and is only of importance to you if
-%# you choose to contribute your changes and enhancements to the
-%# community by submitting them to Best Practical Solutions, LLC.)
-%#
-%# By intentionally submitting any modifications, corrections or
-%# derivatives to this work, or any other work intended for use with
-%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-%# you are the copyright holder for those contributions and you grant
-%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
-%# royalty-free, perpetual, license to use, copy, create derivative
-%# works based on those contributions, and sublicense and distribute
-%# those contributions and any derivatives thereof.
-%#
-%# END BPS TAGGED BLOCK }}}
-SPAN.nav { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 12px;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-.nav2 { font-size: 10px;
- white-space: nowrap}
-.nav { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 13px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-.currentnav { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 13px;
- font-weight: bold;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-.topnav { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 16px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-
-%# .topnav is the original RT class for the sidebar navigation tabs.
-%# Font-sizing by level depth was originally hard-coded into Elements/Menu.
-%# This modification sets a different class name for each level, allowing
-%# style sheet control over the formats.
-
-a.topnav-0 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 16px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-a.topnav-1 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 14px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-a.topnav-2 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 12px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-a.topnav-3 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-a.topnav-4 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-a.topnav-5 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-li.topnav-0-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.topnav-1-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.topnav-2-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.topnav-3-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.topnav-4-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.topnav-5-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.topnav-0-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.topnav-1-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.topnav-2-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.topnav-3-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.topnav-4-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.topnav-5-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-
-.currenttopnav { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 16px;
- font-weight: bold;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-
-%# .currenttopnav is the original RT class for the sidebar navigation tabs.
-%# Font-sizing by level depth was originally hard-coded into Elements/Menu.
-%# This modification sets a different class name for each level, allowing
-%# style sheet control over the formats
-
-a.currenttopnav-0 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 16px;
- font-weight: bold;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-a.currenttopnav-1 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 14px;
- font-weight: bold;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-a.currenttopnav-2 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 12px;
- font-weight: normal;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-a.currenttopnav-3 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: normal;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-a.currenttopnav-4 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: normal;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-a.currenttopnav-5 { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: normal;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-li.currenttopnav-0-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.currenttopnav-1-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.currenttopnav-2-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.currenttopnav-3-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.currenttopnav-4-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.currenttopnav-5-minor {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-li.currenttopnav-0-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.currenttopnav-1-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.currenttopnav-2-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.currenttopnav-3-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.currenttopnav-4-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-li.currenttopnav-5-major {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-
-.topactions { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 10px;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-.subnav { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: normal;
- color: #FFFFFF;
- text-decoration: none;
- white-space: nowrap}
-.currentsubnav { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: bold;
- color: #FFFF66;
- text-decoration: none;
- white-space: nowrap}
-.error { background-color: #ff0000;
- background-position: left top;
- vertical-align: top;
- text-align: left;
- }
-.oldblue { background-color: #0066CC;
- background-position: left top;
- vertical-align: top;
- text-align: left;
- }
-.blue { background-color: #4682B4;
- background-position: left top;
- vertical-align: top;
- text-align: left;
- }
-%# Actually the "topactions" section
-.blueright { background-color: #4682B4;
- background-position: left top;
- vertical-align: top;
- text-align: right;
- padding-right: 1em;
- }
-.olddarkblue { background-color: #003399;
- background-position: left top;
- vertical-align: top;
- text-align: left;
- }
-.darkblue { background-color: #000080;
- background-position: left top;
- vertical-align: top;
- text-align: left;
- }
-.darkblueright { background-color: #000080;
- background-position: left top;
- vertical-align: top;
- text-align: right;
- }
-.overdue {
- color: red;
-}
-
-div.messagebody {
- padding: 2em;
-
-}
-
-
-div.downloadattachment {
- font-size: 10px;
- text-align: right;
-
-}
-
-
-td { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- background-position: left top;
- }
-.black { background-color: #000000;
- background-position: left top;
- }
-span.rtname { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 18px;
- font-weight: normal;
- color: #ffffff}
-span.title { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 20px;
- font-weight: bold;
- color: #ffffff}
-.header { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 12px;
- font-weight: bold;
- color: #0066CC}
-.subheader { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- font-weight: bold;
- color: #0066CC }
-.value { font-weight: bold; }
-.entry { font-weight: normal; }
-.label { font-weight: normal;
- text-align: right; }
-.labeltop { font-weight: normal;
- text-align: right;
- vertical-align: top }
-.productnav { font-family: Verdana, Arial, Helvetica, sans-serif;
- font-size: 11px;
- color: #000000;
- text-align: center;
- vertical-align: middle;
- text-decoration: none}
-.rtblue { background-color: #3399FF;
- margin-top: 0.2em;
- background-position: left top;
- vertical-align: top }
-
-
-.currenttab { margin: 0.2em; background: #336699; }
-.othertab { margin: 0.2em; background: #efefef; }
-.oddline { background-color : #ccccee; }
-
-UL.topnav LI :focus { text-decoration: underline; }
-
-TD.mainbody {
- padding-top: 0.5em;
- padding-left: 1em;
- padding-right: 1em;
- margin-left: 1em;
- margin-right: 1em;
-}
-
-td.boxcontainer + td.boxcontainer {
- margin-left: 1em;
- padding-left: 1em;
- border-collapse: collapse;
-}
-
-th.ticketheader { font-size: 80%;
- font-weight: bold;
- color: #336699;
- background: #cccccc;
-}
-
-th.titlebox {
- text-align: left;
- padding-left: 0.5em;
- padding-right: 0.5em;
- margin-left: 0.5em;
- margin-right: 0.5em;
- border-top: solid black 1px;
- border-bottom: solid black 1px;
-}
-th.titleboxright {
- text-align: right;
- padding-left: 0.5em;
- padding-right: 0.5em;
- margin-left: 0.5em;
- margin-right: 0.5em;
- border-top: solid black 1px;
- border-bottom: solid black 1px;
-}
-
-TD.titlebox {
- padding-left: 1em;
- padding-right: 1em;
- padding-top: 1em;
- padding-bottom: 1em;
-}
-
-SPAN.message {
- font-size: 100%;
- font-family: Verdana, Arial, Helvetica, sans-serif;
-}
-
-
-BODY {
- color: #000;
- background: #FFFFFF;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- margin-top: 0px;
- margin-bottom: 0px;
- margin-left: 0px;
- margin-right: 0px;
- border-top: 0px;
- border-bottom: 0px;
- border-left: 0px;
- border-right: 0px;
-}
-
-
-TR.oddline {
- background-color : #ffffff;
-}
-
-TR.evenline {
- background-color : #ccccee;
-}
-
-H1, H2, H3 {
- margin-top: 0.2em;
- color: #336699;
- font-family: Verdana, Arial, Helvetica, sans-serif;
-
- clear: both;
-}
-
-
-DIV.endmatter { margin-left: -7% }
-.bpscredits {margin-top: 1em;
- text-align: right;
- color: #666666;
- }
-
-
-A { font-weight: bold; color: #000000;
- }
-
-.currenttab { color: #ffffff;}
-.othertab { color: #336699; }
-
-.inverse { color: #ffffff; }
-
-
-
-A:link IMG, A:visited IMG { border-style: none }
-a:focus {text-decoration: underline }
-A IMG { color: white } /* The only way to hide the border in NS 4.x */
-
-a:link { text-decoration: none}
-a:visited { text-decoration: none}
-a:hover { text-decoration: underline}
-/* a:focus { background-color: #ccccee } */
-
-.hide {
- display: none;
- color: white;
-}
-
-SPAN.date { font-size: 0.8em }
-
-span.title { font-size: 1.6em;
- vertical-align: middle;
- color: #ffffff;}
-span.productname { font-size: 2em;
- color: #0066cc;}
-SPAN.titleboxtitle, SPAN.titleboxclose {
- font-size: 80%;
- color: #ffffff;
- vertical-align: middle;
- text-align: left;
- }
-SPAN.titleboxtitle a {
- color: #ffffff;
-}
-SPAN.titleboxtitle a:after {
- content: "...";
-}
-
-SPAN.titleboxright {
- font-size: 0.8em;
- color: #ffffff;
- vertical-align: middle;
- text-align: right;
- }
-
-SPAN.attribution {
- font-weight: bold;
-}
-
-SPAN.label { font-size: 0.8em;
-}
-
-DIV.page-stats { font-size: 0.8em;
- color: #cccccc;
- text-align: right;
- }
-
-
-BLOCKQUOTE {
- font-style: italic;
-}
-
-.emphasized {
- font-weight: bold
-}
-
-
-.oddline {
- background-color : #ccccee;
-}
-
-ul.topnav {
- list-style: none;
- margin-left: 0;
- margin-right: 0.25em;
- padding-left: 0.25em;
- padding-bottom: 0;
- padding-top:0;
- margin-top: 0;
- margin-bottom:0;
-}
-
-.menu-major-separator {
- border-bottom: solid white 1px;
- padding-top: .25em;
- padding-bottom: .5em;
-}
-
-.menu-minor-separator {
- border-top: solid #999999 1px;
- padding-top: .1em;
- margin-top: .5em;
-}
-
-TH.collection-as-table { text-align: center;
- font-size: 0.8em;
- padding-left: .5em;
- padding-right: .5em;
- color: #333333;
- background-color: #cccccc;
- white-space: nowrap;
- }
-
-TD.collection-as-table { text-align: left;
- padding-left: .5em;
- padding-right: .5em;
- }
-
-textarea.signature {
- width: 100%;
-}
-textarea.comments {
- width: 100%;
-}
-
-textarea.messagebox {
- width: 100%;
-}
-
-%# Provide a callback for adding/modifying the style sheet.
-%# http://www.w3.org/TR/REC-CSS1 - section 3.2, says:
-%# "latter specified rule wins"
-<& /Elements/Callback &>
-<%flags>
-inherit => undef
-</%flags>
-<%init>
-$r->content_type('text/css');
-#$r->headers_out->{'Expires'} = '+30m';
-</%init>
diff --git a/rt/html/Prefs/SearchOptions.html b/rt/html/Prefs/SearchOptions.html
index 655d6ec39..06f32ba7e 100644
--- a/rt/html/Prefs/SearchOptions.html
+++ b/rt/html/Prefs/SearchOptions.html
@@ -46,7 +46,7 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<& /Elements/Header, Title => loc("Search Preferences") &>
+<& /Elements/Header, Title => loc("Ticketing Search Preferences") &>
<& /User/Elements/Tabs,
current_tab => "Prefs/SearchOptions.html",
Title => loc("Search Preferences")
diff --git a/rt/html/RTx/Statistics/CallsMultiQueue/Elements/Chart b/rt/html/RTx/Statistics/CallsMultiQueue/Elements/Chart
new file mode 100755
index 000000000..02a183b2c
--- /dev/null
+++ b/rt/html/RTx/Statistics/CallsMultiQueue/Elements/Chart
@@ -0,0 +1,39 @@
+<%perl>
+$r->content_type("image/$format");
+print $graph->plot(\@data)->$format();
+$m->abort();
+</%perl>
+<em><&|/l, $#data+1&>[_1] Plot Elements</&></em><p>
+% foreach my $value (@data) {
+<% $value %><p>
+% }
+<em><&|/l&>x_labels</&>:</em><p>
+<% $ARGS{x_labels} %>
+<p>
+<em><&|/l&>legend</&>:</em><p>
+<% $ARGS{set_legend} %>
+<p>
+<em><&|/l, (keys %ARGS) - 2&>[_1] data sets</&>:</em><p>
+
+% for (1..(scalar keys %ARGS)-2) {
+<% $_ %> <% $ARGS{"data$_"} %><p>
+% }
+
+<%INIT>
+use GD::Graph::lines;
+
+my @data;
+my $graph = GD::Graph::lines->new($Statistics::GraphWidth,$Statistics::GraphHeight);
+$graph->set(export_format => "png",
+ x_label => 'Day of Week',
+ y_label => 'Tickets per day');
+$graph->set_legend(split /,/ , $ARGS{set_legend});
+my $format = $graph->export_format;
+push @data, [split /,/ , $ARGS{x_labels}];
+for (1..((scalar keys %ARGS)-2)) {
+ push @data, [split /,/ , $ARGS{"data".$_}];
+}
+
+</%INIT>
+<%ARGS>
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/CallsMultiQueue/index.html b/rt/html/RTx/Statistics/CallsMultiQueue/index.html
new file mode 100755
index 000000000..abf8aa74a
--- /dev/null
+++ b/rt/html/RTx/Statistics/CallsMultiQueue/index.html
@@ -0,0 +1,330 @@
+<& /Elements/Header, Title => loc('Tickets per day in Multiple queues') &>
+<& /RTx/Statistics/Elements/Tabs, Title => loc('Tickets per day in Multiple Queues by status') &>
+
+<h3>Description</h3>
+<p>This chart shows details of tickets per day by their status. You can select multiple queues to display at the same time, but only one status. You can chose any of the defined status values.
+There is also the option to display all available queues at the same time.
+The default display shows tickets resolved in your default queue (General unless altered locally).
+The line chart below shows the same information in a graphical form.
+
+<br />
+
+<form method="POST" action="index.html">
+
+%# Build Legend
+% my @legend;
+% for (sort keys %queues_to_show) {
+% push @legend, $_;
+% }
+
+%my $title = "Tickets with Status $status in " . join(', ', @queues) . ", per day from " .
+% Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[0]) . " through " .
+% Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[$#dates-1]);
+
+<& /Elements/TitleBoxStart, title => $title, title_href => "/RTx/Statistics/OpenStalled/index.html?$QueryString"&>
+<TABLE BORDER=0 cellspacing=0 cellpadding=1 WIDTH="100%">
+% if ($ShowHeader) {
+<& /RTx/Statistics/Elements/CollectionAsTable/Header,
+ Format => \@RowFormat,
+ FormatString => $RowFormat,
+ AllowSorting => $AllowSorting,
+ Order => $Order,
+ Query => undef,
+ Rows => $Rows,
+ Page => $Page,
+ OrderBy => $OrderBy ,
+ BaseURL => $BaseURL,
+ maxitems => $maxitems &>
+% }
+% my $line = 0;
+% LINE: for my $d (0..$#dates) {
+% if ($d == $#dates ){
+% next LINE;
+% }
+% $line++;
+% my $x = 1;
+% $values{Statistics_Date} = Statistics::FormatDate($dateformat, $dates[$d]);
+% my $row_total=0;
+% foreach my $q (sort keys %queues_to_show) {
+% my $tix = new RT::Tickets($session{'CurrentUser'});
+% if ($status eq "resolved") {
+% $tix->LimitStatus(VALUE => $status);
+% $tix->LimitResolved(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitResolved(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% }
+% elsif ($status eq "new") {
+% $tix->LimitCreated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitCreated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% }
+% elsif ($status eq "deleted") {
+% $tix->LimitStatus(VALUE => $status);
+% $tix->LimitLastUpdated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitLastUpdated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% }
+% elsif ($status eq "stalled") {
+% $tix->LimitStatus(VALUE => $status);
+% $tix->LimitLastUpdated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitLastUpdated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% }
+% elsif ($status eq "open") {
+% $tix->LimitStatus(VALUE => $status);
+% $tix->LimitLastUpdated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitLastUpdated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% }
+% elsif ($status eq "rejected") {
+% $tix->LimitStatus(VALUE => $status);
+% $tix->LimitLastUpdated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitLastUpdated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% }
+% $tix->LimitQueue (VALUE => $q);
+% $values{$q} = $tix->Count;
+% $row_total += $tix->Count;
+% $data[$x++][$d] = $tix->Count;
+% }
+% $values{Statistics_Totals} = $row_total;
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@RowFormat, i => $line, record => $record, maxitems => $maxitems &>
+% }
+</table>
+<& /Elements/TitleBoxEnd&>
+
+<hr>
+
+<BR />
+<BR />
+
+<!-- <td>Show:</td>
+ <td COLSPAN=2><SELECT NAME="status">
+% for (qw(resolved new deleted stalled rejected open)) {
+ <OPTION VALUE="<% $_ %>" <% $_ eq $status && "SELECTED" %>>
+ <% loc($_) %></OPTION>
+% }
+--!>
+
+<%perl>
+# Create the graph URL
+my $url = 'Elements/Chart?x_labels=';
+#$url .= join ",", @{ shift @data } . "&";
+for (0..$max) {
+ $url .= $m->interp->apply_escapes($data[0][$_],'u') . ",";
+}
+chop $url;
+$url .= "&";
+shift @data;
+$url .= 'set_legend='.(join ",", @legend)."&";
+for (0..$#data) {
+ $url .= "data".(1+$_)."=". (join ",", @{$data[$_]})."&";
+}
+chop $url;
+</%perl>
+
+<& /RTx/Statistics/Elements/GraphBox, GraphURL => $url &>
+
+<& /RTx/Statistics/Elements/ControlsAsTable/ControlBox,
+ Title => "Change Status, Queues or Dates",
+ ShowDates => 1, sMonth => \$sMonth, sDay => \$sDay, sYear => \$sYear,
+ eMonth => \$eMonth, eDay => \$eDay, eYear => \$eYear,
+ weekends => $weekends,
+ ShowMultiQueues => 1, queues_ref => \@queues,
+ ShowStatus => 1, Status => $status
+ &>
+
+</form>
+
+<a href="<%$RT::WebPath%>/RTx/Statistics/CallsMultiQueue/index.html?<% $QueryString %>"><&|/l&>Bookmarkable link</&></a>
+%# | <a href="<%$RT::WebPath%>/RTx/Statistics/CallsMultiQueue/Results.tsv?<%$QueryString%>"><&|/l&>spreadsheet</&></a>
+<BR>
+<BR>
+
+<%ARGS>
+$status => $Statistics::MultiQueueStatus
+$max => $Statistics::MultiQueueMaxRows
+@queues => @Statistics::MultiQueueQueueList
+$weekends => $Statistics::PerDayWeekends;
+$sMonth=>undef
+$sDay=>undef
+$sYear=>undef
+$eMonth=>undef
+$eDay=>undef
+$eYear=>undef
+$days=>undef
+$dateformat => $Statistics::MultiQueueDateFormat
+$currentMonth=>undef
+
+$AllowSorting => undef
+$Order => undef
+$OrderBy => undef
+$ShowNavigation => 1
+$ShowHeader => 1
+$Rows => 50
+$Page => 1
+$BaseURL => undef
+$AddAllCheck => undef
+</%ARGS>
+
+<%INIT>
+
+use RTx::Statistics;
+use Time::Local;
+my $n = 0;
+my @data = ([]);
+my @dates;
+my @msgs;
+my $selected;
+my $diff;
+my %queues_to_show;
+my $secsPerDay=86400;
+my $sEpoch;
+my $eEpoch;
+my $QueryString;
+my $maxitems;
+my $RowFormat;
+my $BoldRowFormat;
+my %record;
+my %values;
+my $record = \%record;
+
+$record{values} = \%values;
+
+Statistics::DebugClear();
+Statistics::DebugLog("CallsQueueDay/index.html ARGS:\n");
+for my $key (keys %ARGS) {
+ Statistics::DebugLog("ARG{ $key }=" . $ARGS{$key} . "\n");
+}
+
+
+ # Handle the Add All Checkbox
+ if($AddAllCheck eq "on") {
+ $AddAllCheck = undef;
+ undef (@queues);
+ my $q=new RT::Queues($session{'CurrentUser'});
+ $q->UnLimit;
+ while (my $queue=$q->Next) {
+ next if !$queue->CurrentUserHasRight('SeeQueue');
+ push @queues, $queue->Name;
+ }
+ }
+
+ # If the user has the right to see the queue, put it into the map
+ for my $q (@queues) {
+ my $Queueobj = new RT::Queue($session{'CurrentUser'});
+ $Queueobj->Load($q);
+ next if !$Queueobj->CurrentUserHasRight('SeeQueue');
+ $queues_to_show{$q} = 1;
+ }
+
+ $maxitems = (scalar @queues) + 2;
+
+ # Build the format strings
+ $RowFormat = "'__Statistics_Date__'";
+ $BoldRowFormat = "'<B>__Statistics_Date__</B>'";
+ for my $q (@queues) {
+ $RowFormat .= ",'__Statistics_Dynamic__/KEY:$q/TITLE:$q/STYLE:text-align:right;'";
+ $BoldRowFormat .= ",'<B>__Statistics_Dynamic__</B>/KEY:$q/TITLE:$q/STYLE:text-align:right;'";
+ }
+ $RowFormat .= ",'<B>__Statistics_Totals__</B>/STYLE:text-align:right;'";
+ $BoldRowFormat .= ",'<B>__Statistics_Totals__</B>/STYLE:text-align:right;'";
+ # Parse the formats into structures.
+ my (@RowFormat) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $RowFormat);
+ my (@BoldRowFormat) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $BoldRowFormat);
+
+if ($sDay > $Statistics::monthsMaxDay{$sMonth}) {
+ $sDay = $Statistics::monthsMaxDay{$sMonth};
+}
+
+if ($eDay > $Statistics::monthsMaxDay{$eMonth}) {
+ $eDay = $Statistics::monthsMaxDay{$eMonth};
+}
+
+if ($sYear){
+ $sEpoch = timelocal(0, 0, 0, $sDay, $sMonth, $sYear-1900);
+}
+if ($eYear){
+Statistics::DebugLog("eMonth = " . $eMonth . "\n");
+ $eEpoch = timelocal(0, 0, 0, $eDay, $eMonth, $eYear-1900);
+} else {
+ # This case happens when the page is first loaded
+ my @local = localtime(time);
+ ($eDay, $eMonth, $eYear) = ($local[3], $local[4], $local[5]);
+ $eYear += 1900;
+ $eEpoch = timelocal(0, 0, 0, $local[3], $local[4], $local[5], $local[6], $local[7], $local[8]);
+Statistics::DebugLog("Setting eEpoch=$eEpoch from current time.\n");
+}
+
+if (($eEpoch < $sEpoch) || ($sEpoch == 0)) {
+ # We have an end, but not a start, or, overlapping.
+
+ # if $currentMonth is set, just set the day to 1
+ if($currentMonth) {
+ # set start vars from end, but with day set to 1
+ (undef, undef, undef, $sDay, $sMonth, $sYear) = localtime($eEpoch);
+ $sDay=1;
+ $sEpoch = timelocal(0, 0, 0, $sDay, $sMonth, $sYear);
+ } else {
+ # If the user has specified how many days back to go, use that,
+ # If not, set start to configured default period before end
+ if(defined $days) {
+ $sEpoch = $eEpoch - ($days * $Statistics::secsPerDay);
+ } else {
+ $sEpoch = $eEpoch - ($Statistics::PerDayPeriod * $Statistics::secsPerDay);
+ }
+ (undef, undef, undef, $sDay, $sMonth, $sYear) = localtime($sEpoch);
+ }
+ $sYear += 1900;
+}
+
+# Compute days to chart.
+# The +1 is because we need to generate one more date. If the user
+# selected a 10 day range, we need to generate 11 days.
+$diff = int(($eEpoch - $sEpoch + $Statistics::secsPerDay - 1) / $Statistics::secsPerDay)+1;
+Statistics::DebugLog("Setting diff=$diff\n");
+
+Statistics::DebugLog("sEpoch=$sEpoch, components=" . join(',', localtime($sEpoch)) . "\n");
+Statistics::DebugLog("eEpoch=$eEpoch, components=" . join(',', localtime($eEpoch)) . "\n");
+
+# Build the new query string
+$QueryString = "queues=" . join("&queues=", @queues);
+$QueryString .= "&sDay=$sDay&sMonth=$sMonth&sYear=$sYear&eDay=$eDay&eMonth=$eMonth&eYear=$eYear&weekends=$weekends";
+
+
+
+
+# Set up the end date to be midnight(morning) of the date after the one the user wanted.
+my $endRange = $eEpoch + $Statistics::secsPerDay;
+$n = 0;
+until ($#dates == $diff) {
+ my $date = new RT::Date($session{CurrentUser});
+ $date->Set(Value=>$endRange - $n, Format => 'unix');
+ # Note: we used to adjust the time to local midnight, but
+ # none of the other date entry fields in RT seem to adjust, so we've stopped.
+ #Statistics::DebugLog("Before adjust to midnight date " . Statistics::FormatDate("%c", $date) . "\n");
+ $n+= $Statistics::secsPerDay;
+ # If we aren't showing weekends and this is one, decrement the number
+ # of days to show and skip to the next date.
+ if(!$weekends and Statistics::RTDateIsWeekend($date)) {$diff--; next;}
+ unshift @dates, $date;
+Statistics::DebugLog("pushing date " . Statistics::FormatDate("%c", $date) . "\n");
+ unshift @{ $data[0] }, Statistics::FormatDate($Statistics::PerDayLabelDateFormat, $date);
+}
+
+# We put an extra day into the lists to cover up till midnight of the next day,
+# But we don't want that to appear in the labels, so pop it off.
+pop( @{ $data[0] } );
+
+my $queue = new RT::Queues($session{CurrentUser});
+$queue->UnLimit;
+
+my $QueueObj = new RT::Queue($session{'CurrentUser'});
+$QueueObj->Load($queue);
+</%INIT>
diff --git a/rt/html/RTx/Statistics/CallsQueueDay/Elements/Chart b/rt/html/RTx/Statistics/CallsQueueDay/Elements/Chart
new file mode 100755
index 000000000..9a3a50574
--- /dev/null
+++ b/rt/html/RTx/Statistics/CallsQueueDay/Elements/Chart
@@ -0,0 +1,29 @@
+<%perl>
+$r->content_type("image/$format");
+print $graph->plot(\@data)->$format();
+$m->abort();
+print $#data+1 . " Elements:<p>";
+for (0..$#data) {
+print $data[$_];
+print "<p>";
+}
+</%perl>
+<%INIT>
+use GD::Graph::lines;
+
+my @data;
+my $graph = GD::Graph::lines->new($Statistics::GraphWidth,$Statistics::GraphHeight);
+$graph->set(export_format => "png",
+ x_label => 'Day of Week',
+ y_label => 'Tickets per Day',
+ x_labels_vertical => 1,
+ );
+my $format = $graph->export_format;
+$graph->set_legend(split /,/ , $ARGS{set_legend});
+push @data, [split /,/ , $ARGS{x_labels}];
+push @data, [split /,/ , $ARGS{data1}];
+push @data, [split /,/ , $ARGS{data2}];
+push @data, [split /,/ , $ARGS{data3}];
+</%INIT>
+<%ARGS>
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/CallsQueueDay/Results.tsv b/rt/html/RTx/Statistics/CallsQueueDay/Results.tsv
new file mode 100644
index 000000000..23f0c699c
--- /dev/null
+++ b/rt/html/RTx/Statistics/CallsQueueDay/Results.tsv
@@ -0,0 +1,191 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
+%# <jesse@bestpractical.com>
+%#
+%# (Except where explicitly superseded by other copyright notices)
+%#
+%#
+%# LICENSE:
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+%#
+%# You should have received a copy of the GNU General Public License
+%# along with this program; if not, write to the Free Software
+%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%#
+%#
+%# CONTRIBUTION SUBMISSION POLICY:
+%#
+%# (The following paragraph is not intended to limit the rights granted
+%# to you to modify and distribute this software under the terms of
+%# the GNU General Public License and is only of importance to you if
+%# you choose to contribute your changes and enhancements to the
+%# community by submitting them to Best Practical Solutions, LLC.)
+%#
+%# By intentionally submitting any modifications, corrections or
+%# derivatives to this work, or any other work intended for use with
+%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+%# you are the copyright holder for those contributions and you grant
+%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+%# royalty-free, perpetual, license to use, copy, create derivative
+%# works based on those contributions, and sublicense and distribute
+%# those contributions and any derivatives thereof.
+%#
+%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Queue => undef
+$weekends => $Statistics::PerDayWeekends;
+$sMonth=>undef
+$sDay=>undef
+$sYear=>undef
+$eMonth=>undef
+$eDay=>undef
+$eYear=>undef
+$days=>undef
+$currentMonth=>undef
+</%ARGS>
+
+<%INIT>
+use RTx::Statistics;
+use Time::Local;
+my @dates;
+my $n = 0;
+my %Totals;
+my $now = new RT::Date($session{CurrentUser});
+my $sEpoch;
+my $eEpoch;
+
+if (!defined $Queue) {
+ $Queue = $Statistics::PerDayQueue;
+}
+
+if ($sDay > $Statistics::monthsMaxDay{$sMonth}) {
+ $sDay = $Statistics::monthsMaxDay{$sMonth};
+}
+
+if ($eDay > $Statistics::monthsMaxDay{$eMonth}) {
+ $eDay = $Statistics::monthsMaxDay{$eMonth};
+}
+
+if ($sYear){
+ $sEpoch = timelocal(0, 0, 0, $sDay, $sMonth, $sYear-1900);
+}
+if ($eYear){
+Statistics::DebugLog("eMonth = " . $eMonth . "\n");
+ $eEpoch = timelocal(0, 0, 0, $eDay, $eMonth, $eYear-1900);
+} else {
+ # This case happens when the page is first loaded
+ my @local = localtime(time);
+ ($eDay, $eMonth, $eYear) = ($local[3], $local[4], $local[5]);
+ $eYear += 1900;
+ $eEpoch = timelocal(0, 0, 0, $local[3], $local[4], $local[5], $local[6], $local[7], $local[8]);
+Statistics::DebugLog("Setting eEpoch=$eEpoch from current time.\n");
+}
+
+if (($eEpoch < $sEpoch) || ($sEpoch == 0)) {
+ # We have an end, but not a start, or, overlapping.
+
+ # if $currentMonth is set, just set the day to 1
+ if($currentMonth) {
+ # set start vars from end, but with day set to 1
+ (undef, undef, undef, $sDay, $sMonth, $sYear) = localtime($eEpoch);
+ $sDay=1;
+ $sEpoch = timelocal(0, 0, 0, $sDay, $sMonth, $sYear);
+ } else {
+ # If the user has specified how many days back to go, use that,
+ # If not, set start to configured default period before end
+ if(defined $days) {
+ $sEpoch = $eEpoch - ($days * $Statistics::secsPerDay);
+ } else {
+ $sEpoch = $eEpoch - ($Statistics::PerDayPeriod * $Statistics::secsPerDay);
+ }
+ (undef, undef, undef, $sDay, $sMonth, $sYear) = localtime($sEpoch);
+ }
+ $sYear += 1900;
+}
+
+# set content type
+$r->content_type('application/vnd.ms-excel');
+
+# Put out some data about the generation of this file
+$m->out("Tickets per day for Queue:\t" . $Queue . "\tGenerated at:\t" . Statistics::FormatDate("%x %X", $now). "\n\n");
+
+
+# Compute days to chart.
+# The +1 is because we need to generate one more date. If the user
+# selected a 10 day range, we need to generate 11 days.
+my $diff = int(($eEpoch - $sEpoch + $Statistics::secsPerDay - 1) / $Statistics::secsPerDay)+1;
+
+# Build array of dates
+my $endRange = $eEpoch + $Statistics::secsPerDay;
+my $QueueObj = new RT::Queue($session{'CurrentUser'});
+$QueueObj->Load($Queue);
+until ($#dates == $diff) {
+ my $date = new RT::Date($session{CurrentUser});
+ $date->Set(Value=>$endRange - $n, Format => 'unix');
+ # Note: we used to adjust the time to local midnight, but
+ # none of the other date entry fields in RT seem to adjust, so we've stopped.
+ #Statistics::DebugLog("Before adjust to midnight date " . Statistics::FormatDate("%c", $date) . "\n");
+ $n+= $Statistics::secsPerDay;
+ # If we aren't showing weekends and this is one, decrement the number
+ # of days to show and skip to the next date.
+ if(!$weekends and Statistics::RTDateIsWeekend($date)) {$diff--; next;}
+ unshift @dates, $date;
+}
+
+# Output header row
+$m->out("Date\tcreate\tresolved\tdeleted\n");
+
+
+LINE: for my $d (0..$#dates) {
+ if ($d == $#dates){
+ next LINE;
+ }
+ my $x = 1;
+ # Output the date for this row
+ $m->out(Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[$d]));
+
+ # output the 3 columns for this row
+ for my $status (qw(created resolved deleted)) {
+ my $tix = new RT::Tickets($session{'CurrentUser'});
+ if ($status eq "created") {
+ $tix->LimitCreated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+ if ($dates[$d+1]) {
+ $tix->LimitCreated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+ }
+ } elsif ($status eq "resolved") {
+ $tix->LimitStatus(VALUE => $status);
+ $tix->LimitResolved(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+ if ($dates[$d+1]) {
+ $tix->LimitResolved(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+ }
+ } elsif ($status eq "deleted") {
+ $tix->LimitStatus(VALUE => $status);
+ $tix->LimitLastUpdated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+ if ($dates[$d+1]) {
+ $tix->LimitLastUpdated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+ }
+ }
+ $tix->LimitQueue (VALUE => $Queue);
+ $m->out( "\t" . $tix->Count );
+ $Totals{$status} += $tix->Count;
+ }
+ $m->out("\n");
+}
+
+# Output the totals
+$m->out("Totals\t$Totals{created}\t$Totals{resolved}\t$Totals{deleted}\n");
+
+$m->abort();
+</%INIT>
diff --git a/rt/html/RTx/Statistics/CallsQueueDay/index.html b/rt/html/RTx/Statistics/CallsQueueDay/index.html
new file mode 100755
index 000000000..06fc484d1
--- /dev/null
+++ b/rt/html/RTx/Statistics/CallsQueueDay/index.html
@@ -0,0 +1,275 @@
+<& /Elements/Header, Title => loc("Tickets per day in Queue:" . $QueueObj->Name()) &>
+<& /RTx/Statistics/Elements/Tabs, Title => loc("Tickets by status per day in Queue:" . $QueueObj->Name()) &>
+
+<h3>Description</h3>
+<p>This page displays details about tickets in the selected queue over the date range chosen. It shows how many tickets were created on
+each day in the chosen range, and how many of those were either Resolved or Deleted.</p>
+<p>To always show the current month to date, bookmark this <a href="<%$RT::WebPath%>/RTx/Statistics/CallsQueueDay/index.html?currentMonth=1">link</a>, or
+for a spreadsheet, use this <a href="<%$RT::WebPath%>/RTx/Statistics/CallsQueueDay/Results.tsv?currentMonth=1">link</a>.</p>
+
+<form method="POST" action="index.html">
+
+% Statistics::DebugLog("queue name=" . $QueueObj->Name() . "\n");
+
+%my $title = "Ticket counts in " . $QueueObj->Name() . " by status per day from " .
+% Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[0]) . " through " .
+% Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[$#dates-1]);
+<&|/Elements/TitleBox,
+ title => $title,
+ title_href => "/RTx/Statistics/CallsQueueDay/index.html?$QueryString" &>
+<TABLE BORDER=0 cellspacing=0 cellpadding=1 WIDTH=100%>
+% if ($ShowHeader) {
+<& /RTx/Statistics/Elements/CollectionAsTable/Header,
+ Format => \@Format,
+ FormatString => $Format,
+ AllowSorting => $AllowSorting,
+ Order => $Order,
+ Query => undef,
+ Rows => $Rows,
+ Page => $Page,
+ OrderBy => $OrderBy ,
+ BaseURL => $BaseURL,
+ maxitems => $maxitems &>
+% }
+% my $line = 1;
+% LINE: for my $d (0..$#dates) {
+% if ($d == $#dates){
+% next LINE;
+% }
+% my $x = 1;
+% $values{Statistics_Date} = Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[$d]);
+%# NOTE need to handle all status values here....
+% for my $status (qw(created resolved deleted)) {
+% my $tix = new RT::Tickets($session{'CurrentUser'});
+% $tix->LimitQueue (VALUE => $Queue);
+% if ($status eq "created") {
+% $tix->LimitCreated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitCreated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% $values{Statistics_Created_Count} = $tix->Count;
+% $Totals{Statistics_Created_Count} += $tix->Count;
+% }
+% elsif ($status eq "resolved") {
+% $tix->LimitStatus(VALUE => $status);
+% $tix->LimitResolved(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitResolved(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% $values{Statistics_Resolved_Count} = $tix->Count;
+% $Totals{Statistics_Resolved_Count} += $tix->Count;
+% }
+% elsif ($status eq "deleted") {
+% $tix->LimitStatus(VALUE => $status);
+% $tix->LimitLastUpdated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitLastUpdated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% $values{Statistics_Deleted_Count} = $tix->Count;
+% $Totals{Statistics_Deleted_Count} += $tix->Count;
+% }
+% $data[$x++][$d] = $tix->Count;
+% }
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@Format, i => $line, record => $record, maxitems => $maxitems &>
+% $line++;
+% }
+% $values {Statistics_Date} = "Totals";
+% $values {Statistics_Created_Count} = $Totals{Statistics_Created_Count};
+% $values {Statistics_Resolved_Count} = $Totals{Statistics_Resolved_Count};
+% $values {Statistics_Deleted_Count} = $Totals{Statistics_Deleted_Count};
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@BoldFormat, i => $line, record => $record, maxitems => $maxitems &>
+</table>
+</&>
+
+<hr>
+
+<BR />
+<BR />
+
+<%perl>
+# Create the graph URL
+my $url= 'Elements/Chart?x_labels=';
+for (1..$diff) {
+ $url .= $data[0][$_] . ",";
+}
+chop $url;
+$url .= "&";
+shift @data;
+for (0..$#data) {
+ $url .= "data".(1+$_)."=".(join ",", @{$data[$_]})."&";
+}
+chop $url;
+$url .= "&set_legend=Created,Resolved,Deleted";
+</%perl>
+
+<& /RTx/Statistics/Elements/GraphBox, GraphURL => $url &>
+
+<& /RTx/Statistics/Elements/ControlsAsTable/ControlBox,
+ Title => "Change Queue or Dates",
+ ShowDates => 1, sMonth => \$sMonth, sDay => \$sDay, sYear => \$sYear,
+ eMonth => \$eMonth, eDay => \$eDay, eYear => \$eYear,
+ weekends => $weekends,
+ ShowSingleQueue => 1, Queue => $Queue
+ &>
+
+</form>
+
+<a href="<%$RT::WebPath%>/RTx/Statistics/CallsQueueDay/index.html?<% $QueryString %>"><&|/l&>Bookmarkable link</&></a> |
+<a href="<%$RT::WebPath%>/RTx/Statistics/CallsQueueDay/Results.tsv?<%$QueryString%>"><&|/l&>spreadsheet</&></a>
+<BR>
+<BR>
+
+
+% Statistics::DebugLog("ref of eMonth is " . ref($eMonth) . "\n");
+% Statistics::DebugInit( $m );
+
+<%ARGS>
+$Queue => undef
+$weekends => $Statistics::PerDayWeekends;
+$sMonth=>undef
+$sDay=>undef
+$sYear=>undef
+$eMonth=>undef
+$eDay=>undef
+$eYear=>undef
+$days=>undef
+$currentMonth=>undef
+
+$AllowSorting => undef
+$Order => undef
+$OrderBy => undef
+$ShowNavigation => 1
+$ShowHeader => 1
+$Rows => 50
+$Page => 1
+$BaseURL => undef
+</%ARGS>
+
+<%INIT>
+use RTx::Statistics;
+use Time::Local;
+my $selected;
+my $n = 0;
+my @data = ([]);
+my @dates;
+my @msgs;
+my $diff;
+my $sEpoch=0;
+my $eEpoch=0;
+my %Totals;
+my $QueryString;
+my $maxitems = 4;
+my %record;
+my %values;
+my $record = \%record;
+
+$record{values} = \%values;
+
+
+# If debugging, set things up and display all the args
+Statistics::DebugClear();
+Statistics::DebugLog("CallsQueueDay/index.html ARGS:\n");
+for my $key (keys %ARGS) {
+ Statistics::DebugLog("ARG{ $key }=" . $ARGS{$key} . "\n");
+}
+
+my $Format = qq{ Statistics_Date,
+ '__Statistics_Created_Count__/STYLE:text-align:right;',
+ '__Statistics_Resolved_Count__/STYLE:text-align:right;',
+ '__Statistics_Deleted_Count__/STYLE:text-align:right;' };
+my $BoldFormat = qq{ '<B>__Statistics_Date__</B>',
+ '<B>__Statistics_Created_Count__</B>/STYLE:text-align:right;',
+ '<B>__Statistics_Resolved_Count__</B>/STYLE:text-align:right;',
+ '<B>__Statistics_Deleted_Count__</B>/STYLE:text-align:right;' };
+my (@Format) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $Format);
+my (@BoldFormat) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $BoldFormat);
+Statistics::DebugLog("CallsQueueDay/index.html Format array=" . join(',', @Format) . "\n");
+
+if (!defined $Queue) {
+ my $QueueObj = new RT::Queue($session{'CurrentUser'});
+ $QueueObj->Load($Statistics::PerDayQueue);
+ $Queue = $QueueObj->Id();
+}
+
+if ($sDay > $Statistics::monthsMaxDay{$sMonth}) {
+ $sDay = $Statistics::monthsMaxDay{$sMonth};
+}
+
+if ($eDay > $Statistics::monthsMaxDay{$eMonth}) {
+ $eDay = $Statistics::monthsMaxDay{$eMonth};
+}
+
+if ($sYear){
+ $sEpoch = timelocal(0, 0, 0, $sDay, $sMonth, $sYear-1900);
+}
+if ($eYear){
+Statistics::DebugLog("eMonth = " . $eMonth . "\n");
+ $eEpoch = timelocal(0, 0, 0, $eDay, $eMonth, $eYear-1900);
+} else {
+ # This case happens when the page is first loaded
+ my @local = localtime(time);
+ ($eDay, $eMonth, $eYear) = ($local[3], $local[4], $local[5]);
+ $eYear += 1900;
+ $eEpoch = timelocal(0, 0, 0, $local[3], $local[4], $local[5], $local[6], $local[7], $local[8]);
+Statistics::DebugLog("Setting eEpoch=$eEpoch from current time.\n");
+}
+
+if (($eEpoch < $sEpoch) || ($sEpoch == 0)) {
+ # We have an end, but not a start, or, overlapping.
+
+ # if $currentMonth is set, just set the day to 1
+ if($currentMonth) {
+ # set start vars from end, but with day set to 1
+ (undef, undef, undef, $sDay, $sMonth, $sYear) = localtime($eEpoch);
+ $sDay=1;
+ $sEpoch = timelocal(0, 0, 0, $sDay, $sMonth, $sYear);
+ } else {
+ # If the user has specified how many days back to go, use that,
+ # If not, set start to configured default period before end
+ if(defined $days) {
+ $sEpoch = $eEpoch - ($days * $Statistics::secsPerDay);
+ } else {
+ $sEpoch = $eEpoch - ($Statistics::PerDayPeriod * $Statistics::secsPerDay);
+ }
+ (undef, undef, undef, $sDay, $sMonth, $sYear) = localtime($sEpoch);
+ }
+ $sYear += 1900;
+}
+
+# Compute days to chart.
+# The +1 is because we need to generate one more date. If the user
+# selected a 10 day range, we need to generate 11 days.
+$diff = int(($eEpoch - $sEpoch + $Statistics::secsPerDay - 1) / $Statistics::secsPerDay)+1;
+Statistics::DebugLog("Setting diff=$diff\n");
+
+Statistics::DebugLog("sEpoch=$sEpoch, components=" . join(',', localtime($sEpoch)) . "\n");
+Statistics::DebugLog("eEpoch=$eEpoch, components=" . join(',', localtime($eEpoch)) . "\n");
+
+# Set up the string for the current query for bookmarkable link
+$QueryString = "sDay=$sDay&sMonth=$sMonth&sYear=$sYear&eDay=$eDay&eMonth=$eMonth&eYear=$eYear&weekends=$weekends&Queue=$Queue";
+
+# Set up the end date to be midnight(morning) of the date after the one the user wanted.
+my $endRange = $eEpoch + $Statistics::secsPerDay;
+my $QueueObj = new RT::Queue($session{'CurrentUser'});
+$QueueObj->Load($Queue);
+$n = 0;
+until ($#dates == $diff) {
+ my $date = new RT::Date($session{CurrentUser});
+ $date->Set(Value=>$endRange - $n, Format => 'unix');
+ # Note: we used to adjust the time to local midnight, but
+ # none of the other date entry fields in RT seem to adjust, so we've stopped.
+ #Statistics::DebugLog("Before adjust to midnight date " . Statistics::FormatDate("%c", $date) . "\n");
+ $n+= $Statistics::secsPerDay;
+ # If we aren't showing weekends and this is one, decrement the number
+ # of days to show and skip to the next date.
+ if(!$weekends and Statistics::RTDateIsWeekend($date)) {$diff--; next;}
+ unshift @dates, $date;
+Statistics::DebugLog("pushing date " . Statistics::FormatDate("%c", $date) . "\n");
+ unshift @{ $data[0] }, Statistics::FormatDate($Statistics::PerDayLabelDateFormat, $date);
+}
+
+# We put an extra day into the lists to cover up till midnight of the next day,
+# But we don't want that to appear in the labels, so pop it off.
+pop( @{ $data[0] } );
+
+</%INIT>
diff --git a/rt/html/RTx/Statistics/DayOfWeek/Elements/Chart b/rt/html/RTx/Statistics/DayOfWeek/Elements/Chart
new file mode 100755
index 000000000..239c09541
--- /dev/null
+++ b/rt/html/RTx/Statistics/DayOfWeek/Elements/Chart
@@ -0,0 +1,26 @@
+% $r->content_type("image/$format");
+% $m->print($graph->plot(\@data)->$format());
+% $m->abort();
+<&|/l, $#data+1&>[_1] Elements</&>:<p>
+% for (0..$#data) {
+<% $data[$_] %><p>
+% }
+<%INIT>
+use GD::Graph::bars;
+
+my @data;
+my $graph = GD::Graph::bars->new($Statistics::GraphWidth,$Statistics::GraphHeight);
+$graph->set(export_format => "png",
+ x_label => 'Day of Week',
+ y_label => 'Ticket actions per Day by type');
+$graph->set_legend(split /,/ , $ARGS{set_legend});
+push @data, [split /,/ , $ARGS{x_labels}];
+push @data, [split /,/ , $ARGS{data1}];
+push @data, [split /,/ , $ARGS{data2}];
+push @data, [split /,/ , $ARGS{data3}];
+
+my $format = $graph->export_format;
+$r->content_type("image/$format");
+</%INIT>
+<%ARGS>
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/DayOfWeek/index.html b/rt/html/RTx/Statistics/DayOfWeek/index.html
new file mode 100755
index 000000000..2e82b9c24
--- /dev/null
+++ b/rt/html/RTx/Statistics/DayOfWeek/index.html
@@ -0,0 +1,155 @@
+<& /Elements/Header, Title =>loc('Tickets by Day Of Week in Queue:' . $QueueObj->Name()) &>
+<& /RTx/Statistics/Elements/Tabs, Title =>loc('Trends in ticket status by Day Of Week in Queue:' . $QueueObj->Name()) &>
+
+<h3>Description</h3>
+<p>The purpose of this page is to show historical trends for each day of the week.
+It displays details of number of tickets created in your
+selected queue for each day. It also hows how many of those created tickets were Resolved or Deleted</p>
+
+<form method="POST" action="index.html">
+
+
+%my $title = "Ticket counts by day of week in " . $QueueObj->Name();
+<&|/Elements/TitleBox,
+ title => $title,
+ title_href => "/RTx/Statistics/DayOfWeek/index.html?$QueryString" &>
+<TABLE BORDER=0 cellspacing=0 cellpadding=1 WIDTH=100%>
+% if ($ShowHeader) {
+<& /RTx/Statistics/Elements/CollectionAsTable/Header,
+ Format => \@Format,
+ FormatString => $Format,
+ AllowSorting => $AllowSorting,
+ Order => $Order,
+ Query => undef,
+ Rows => $Rows,
+ Page => $Page,
+ OrderBy => $OrderBy ,
+ BaseURL => $BaseURL,
+ maxitems => $maxitems &>
+% }
+% my $line = 1;
+% for my $d (0..$#days) {
+% my $x = 1;
+% $values{Statistics_Date} = $days[$d];
+%# NOTE Show all status values???
+% $values{Statistics_Created_Count} = $counts[$d]{new};
+% $values{Statistics_Resolved_Count} = $counts[$d]{resolved};
+% $values{Statistics_Deleted_Count} = $counts[$d]{deleted};
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@Format, i => $line, record => $record, maxitems => $maxitems &>
+% $line++;
+% }
+% $values {Statistics_Date} = "Totals";
+% $values {Statistics_Created_Count} = $Totals{new};
+% $values {Statistics_Resolved_Count} = $Totals{resolved};
+% $values {Statistics_Deleted_Count} = $Totals{deleted};
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@BoldFormat, i => $line, record => $record, maxitems => $maxitems &>
+</table>
+</&>
+
+<hr>
+
+<BR />
+<BR />
+
+<%perl>
+my $url = 'Elements/Chart?&x_labels=';
+for (0..$#days) {
+ $url .= $days[$_] . "," ;
+}
+chop $url;
+$url .= "&";
+
+my @things = qw(new resolved deleted);
+for my $th (0..$#things) {
+ $url .= "data".(1+$th)."=".(join ",", map { $counts[$_]{$things[$th]} } (0..6))."&";
+}
+chop $url;
+$url .= '&set_legend=Created,Resolved,Deleted';
+</%perl>
+
+<& /RTx/Statistics/Elements/GraphBox, GraphURL => $url &>
+
+% Statistics::DebugLog("queue name=" . $QueueObj->Id() . "\n");
+
+<& /RTx/Statistics/Elements/ControlsAsTable/ControlBox,
+ Title => "Change Queue",
+ ShowSingleQueue => 1, Queue => $QueueObj->Id()
+ &>
+
+</form>
+
+% Statistics::DebugInit( $m );
+
+<%ARGS>
+$Queue => $Statistics::DayOfWeekQueue
+
+$AllowSorting => undef
+$Order => undef
+$OrderBy => undef
+$ShowNavigation => 1
+$ShowHeader => 1
+$Rows => 50
+$Page => 1
+$BaseURL => undef
+</%ARGS>
+
+<%INIT>
+use GD::Graph;
+use RTx::Statistics;
+my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
+my $n = 0;
+my @data = ([]);
+my @msgs;
+my @counts;
+my %Totals = (
+ resolved => 0,
+ deleted => 0,
+ new => 0
+);
+my $QueryString = "Queue=$Queue";
+my $maxitems = 4;
+my %record;
+my %values;
+my $record = \%record;
+
+$record{values} = \%values;
+
+my $Format = qq{ Statistics_Date,
+ '__Statistics_Created_Count__/STYLE:text-align:right;',
+ '__Statistics_Resolved_Count__/STYLE:text-align:right;',
+ '__Statistics_Deleted_Count__/STYLE:text-align:right;' };
+my $BoldFormat = qq{ '<B>__Statistics_Date__</B>',
+ '<B>__Statistics_Created_Count__</B>/STYLE:text-align:right;',
+ '<B>__Statistics_Resolved_Count__</B>/STYLE:text-align:right;',
+ '<B>__Statistics_Deleted_Count__</B>/STYLE:text-align:right;' };
+my (@Format) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $Format);
+my (@BoldFormat) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $BoldFormat);
+
+my $QueueObj = new RT::Queue($session{'CurrentUser'});
+$QueueObj->Load($Queue);
+$RT::Logger->warning("Loaded queue $Queue, name=". $QueueObj->Name());
+
+my $tix = new RT::Tickets($session{'CurrentUser'});
+$tix->LimitQueue (VALUE => $Queue);
+$tix->UnLimit;
+if ($tix->Count) {
+ # Initialize the counters to zero, so that all the cells show up
+ foreach my $day (0..@days) {
+ $counts[$day]{resolved} = 0;
+ $counts[$day]{deleted} = 0;
+ $counts[$day]{new} = 0;
+ }
+ while (my $t = $tix->RT::SearchBuilder::Next) { # BLOODY HACK
+ if($t->Status eq "resolved") {
+ $counts[(localtime($t->ResolvedObj->Unix))[6]]{resolved}++;
+ $Totals{resolved}++;
+ }
+ if($t->Status eq "deleted") {
+ $counts[(localtime($t->LastUpdatedObj->Unix))[6]]{deleted}++;
+ $Totals{deleted}++;
+ }
+ $counts[(localtime($t->CreatedObj->Unix))[6]]{new}++;
+ $Totals{new}++;
+ }
+}
+</%INIT>
diff --git a/rt/html/RTx/Statistics/DurationAsString b/rt/html/RTx/Statistics/DurationAsString
new file mode 100755
index 000000000..c0b4d9af4
--- /dev/null
+++ b/rt/html/RTx/Statistics/DurationAsString
@@ -0,0 +1,18 @@
+<%$days|'00'%> days <%$hours|'00'%>:<%$minutes|'00'%>
+<%INIT>
+
+my $MINUTE = 60;
+my $HOUR = $MINUTE*60;
+my $DAY = $HOUR * 24;
+my $WEEK = $DAY * 7;
+my $days = int($Duration / $DAY);
+$Duration = $Duration % $DAY;
+my $hours = int($Duration / $HOUR);
+$hours = sprintf("%02d", $hours);
+$Duration = $Duration % $HOUR;
+my $minutes = int($Duration/$MINUTE);
+$minutes = sprintf("%02d", $minutes);
+</%INIT>
+<%ARGS>
+$Duration => undef
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/Elements/CollectionAsTable/Header b/rt/html/RTx/Statistics/Elements/CollectionAsTable/Header
new file mode 100644
index 000000000..cecb02eee
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/CollectionAsTable/Header
@@ -0,0 +1,126 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
+%# <jesse@bestpractical.com>
+%#
+%# (Except where explicitly superseded by other copyright notices)
+%#
+%#
+%# LICENSE:
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+%#
+%# You should have received a copy of the GNU General Public License
+%# along with this program; if not, write to the Free Software
+%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%#
+%#
+%# CONTRIBUTION SUBMISSION POLICY:
+%#
+%# (The following paragraph is not intended to limit the rights granted
+%# to you to modify and distribute this software under the terms of
+%# the GNU General Public License and is only of importance to you if
+%# you choose to contribute your changes and enhancements to the
+%# community by submitting them to Best Practical Solutions, LLC.)
+%#
+%# By intentionally submitting any modifications, corrections or
+%# derivatives to this work, or any other work intended for use with
+%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+%# you are the copyright holder for those contributions and you grant
+%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+%# royalty-free, perpetual, license to use, copy, create derivative
+%# works based on those contributions, and sublicense and distribute
+%# those contributions and any derivatives thereof.
+%#
+%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+@Format => undef
+$FormatString => undef
+$AllowSorting => undef
+$Order=>undef
+$BaseURL => undef
+$Query => undef
+$Rows => undef
+$Page => undef
+$maxitems => undef
+</%ARGS>
+<TR class="collection-as-table">
+<%perl>
+
+my %generic_query_args = ( Query => $Query, Rows => $Rows, Page => $Page, Format => $FormatString );
+
+my $item = 0;
+foreach my $col (@Format) {
+ $item++;
+ if ( $col->{title} eq 'NEWLINE' ) {
+ while ( $item < $maxitems ) {
+ $m->out(qq{<th class="collection-as-table">&nbsp;</th>\n});
+ $item++;
+ }
+
+ $item = 0;
+ $m->out(qq{</TR>\n<TR class="collection-as-table">});
+ }
+ else {
+ $m->out('<TH class="collection-as-table" ');
+ $m->out( 'align="' . $col->{align} . '"' ) if ( $col->{align} );
+ $m->out( 'style="' . $col->{style} . '"' ) if ( $col->{style} );
+ $m->out('>');
+ my $title = $col->{title};
+ $title =~ s/^__(.*)__$/$1/o;
+ $title = (
+ $m->comp(
+ '/RTx/Statistics/Elements/StatColumnMap',
+ Name => $title,
+ Attr => 'title'
+ )
+ || $title
+ );
+ if (
+ $AllowSorting
+ && $col->{'attribute'}
+ && $m->comp(
+ '/RTx/Statistics/Elements/StatColumnMap',
+ Name => $col->{'attribute'},
+ Attr => 'attribute'
+ )
+ )
+ {
+
+ $m->out(
+ '<a href="' . $BaseURL
+ . $m->comp(
+ '/Elements/QueryString',
+ %generic_query_args,
+ OrderBy => (
+ $m->comp(
+ '/RTx/Statistics/Elements/StatColumnMap',
+ Name => $col->{'attribute'},
+ Attr => 'attribute'
+ )
+ || $col->{'attribute'}
+ ),
+ Order => ( $ARGS{'Order'} eq 'ASC' ? 'DESC' : 'ASC' )
+ )
+ . '">'
+ . loc($title) . '</a>'
+ );
+ }
+ else {
+ $m->out( loc($title) );
+ }
+ $m->out('</TH>');
+ }
+}
+</%perl>
+</TR>
diff --git a/rt/html/Ticket/Elements/ShowReferences b/rt/html/RTx/Statistics/Elements/CollectionAsTable/ParseFormat
index bb323f66c..a482f817e 100644
--- a/rt/html/Ticket/Elements/ShowReferences
+++ b/rt/html/RTx/Statistics/Elements/CollectionAsTable/ParseFormat
@@ -43,30 +43,67 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<UL>
-% while (my $Link = $Ticket->RefersTo->Next) {
-<LI>
-% if ($Link->TargetURI->IsLocal) {
-% my $member = $Link->TargetObj;
+<%ARGS>
+$Format
+</%ARGS>
-<a href="<%$RT::WebPath%>/Ticket/Display.html?id=<%$member->Id%>"><%$member->Id%></a>: (<%$member->OwnerObj->Name%>) <%$member->Subject%> [<%$member->Status%>]<br>
-% } else {
-<A HREF="<%$Link->TargetURI->HREF%>"><%$Link->Target%></A>
-% }
-%}
+<%init>
+use Regexp::Common;
+my @Columns;
+while ($Format =~ /($RE{delimited}{-delim=>qq{\'"}}|[{}\w.]+)/go) {
+ my $col = $1;
+ if ($col =~ /^$RE{quoted}$/o) {
+ substr($col,0,1) = "";
+ substr($col,-1,1) = "";
+ }
-% while (my $Link = $Ticket->ReferredToBy->Next) {
-<LI>
-% if ($Link->BaseURI->IsLocal) {
-% my $member = $Link->BaseObj;
-<a href="<%$RT::WebPath%>/Ticket/Display.html?id=<%$member->Id%>"><%$member->Id%></a>: (<%$member->OwnerObj->Name%>) <%$member->Subject%> [<%$member->Status%>]<br>
-% } else {
-<A HREF="<%$Link->BaseURI->HREF%>"><%$Link->Base%></A>
-%}
-% }
-</UL>
-<%ARGS>
-$Ticket => undef
-</%ARGS>
+ my $colref;
+
+ # kfh at mqsoftware.com added this to be able
+ # to create columns where the actual heading and value
+ # aren't know ahead of time. For instance queue names.
+ # it will work with subcols, but all subcols will have the same KEY
+ if ( $col =~ s!/KEY:([^/]+)!!io ) {
+ $colref->{'keyname'} = $1;
+ }
+ if ( $col =~ s!/STYLE:([^/]+)!!io ) {
+ $colref->{'style'} = $1;
+ }
+ if ( $col =~ s!/CLASS:([^/]+)!!io ) {
+ $colref->{'class'} = $1;
+ }
+ if ( $col =~ s!/TITLE:([^/]+)!!io ) {
+ $colref->{'title'} = $1;
+ }
+ if ( $col =~ s!/ALIGN:([^\/]+)!!io ) {
+ $colref->{'align'} = $1;
+ }
+ if ( $col =~ /__(.*?)__/gio ) {
+ my @subcols;
+ while ( $col =~ s/^(.*?)__(.*?)__//o ) {
+ push ( @subcols, $1 ) if ($1);
+ push ( @subcols, "__$2__" );
+ $colref->{'attribute'} = $2;
+ }
+ push ( @subcols, $col );
+ @{ $colref->{'output'} } = @subcols;
+ }
+ else {
+ @{ $colref->{'output'} } = ( "__" . $col . "__" );
+ $colref->{'attribute'} = $col;
+ }
+
+ if ( !$colref->{'title'} && grep { /^__(.*?)__$/io }
+ @{ $colref->{'output'} } )
+ {
+ $colref->{'title'} = $1;
+ $colref->{'attribute'} = $1;
+ }
+
+
+ push @Columns, $colref;
+}
+ return(@Columns);
+</%init>
diff --git a/rt/html/RTx/Statistics/Elements/CollectionAsTable/Row b/rt/html/RTx/Statistics/Elements/CollectionAsTable/Row
new file mode 100644
index 000000000..bcfabe5c3
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/CollectionAsTable/Row
@@ -0,0 +1,112 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
+%# <jesse@bestpractical.com>
+%#
+%# (Except where explicitly superseded by other copyright notices)
+%#
+%#
+%# LICENSE:
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+%#
+%# You should have received a copy of the GNU General Public License
+%# along with this program; if not, write to the Free Software
+%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%#
+%#
+%# CONTRIBUTION SUBMISSION POLICY:
+%#
+%# (The following paragraph is not intended to limit the rights granted
+%# to you to modify and distribute this software under the terms of
+%# the GNU General Public License and is only of importance to you if
+%# you choose to contribute your changes and enhancements to the
+%# community by submitting them to Best Practical Solutions, LLC.)
+%#
+%# By intentionally submitting any modifications, corrections or
+%# derivatives to this work, or any other work intended for use with
+%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+%# you are the copyright holder for those contributions and you grant
+%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+%# royalty-free, perpetual, license to use, copy, create derivative
+%# works based on those contributions, and sublicense and distribute
+%# those contributions and any derivatives thereof.
+%#
+%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$i => undef
+@Format => undef
+$record => undef
+$maxitems => undef
+$Depth => undef
+$Warning => undef
+</%ARGS>
+
+<%PERL>
+$m->out('<TR class="' . ( $Warning ? 'warnline' : $i % 2 ? 'oddline' : 'evenline' ) . '" >' );
+my $item;
+foreach my $column (@Format) {
+ if ( $column->{title} eq 'NEWLINE' ) {
+ while ( $item < $maxitems ) {
+ $m->out(qq{<td class="collection-as-table">&nbsp;</td>\n});
+ $item++;
+ }
+ $item = 0;
+ $m->out('</TR>');
+ $m->out('<TR class="'
+ . ( $Warning ? 'warnline' : $i % 2 ? 'oddline' : 'evenline' )
+ . '" >' );
+ next;
+ }
+ $item++;
+ $m->out('<td class="collection-as-table" ');
+ $m->out( 'align="' . $column->{align} . '"' ) if ( $column->{align} );
+ $m->out( 'style="' . $column->{style} . '"' ) if ( $column->{style} );
+ $m->out('>');
+ foreach my $subcol ( @{ $column->{output} } ) {
+ if ( $subcol =~ /^__(.*?)__$/o ) {
+ my $col = $1;
+ my $value = $m->comp(
+ '/RTx/Statistics/Elements/StatColumnMap',
+ Name => $col,
+ Attr => 'value'
+ );
+ my @out;
+
+ if ( $value && ref($value) ) {
+
+ # All HTML snippets are returned by the callback function
+ # as scalar references. Data fetched from the objects are
+ # plain scalars, and needs to be escaped properly.
+ @out =
+ map {
+ ref($_) ? $$_ : $m->interp->apply_escapes( $_ => 'h' )
+ } &{$value}( $record, $i, $column->{keyname} );
+ ;
+ }
+ else {
+
+ # Simple value; just escape it.
+ @out = $m->interp->apply_escapes( $value => 'h' );
+ }
+ s/\n/<br>/gs for @out;
+ $m->out( @out );
+ }
+ else {
+ $m->out($subcol);
+ }
+ }
+ $m->out('</td>');
+}
+$m->out('</TR>');
+</%PERL>
diff --git a/rt/html/RTx/Statistics/Elements/ControlsAsTable/ControlBox b/rt/html/RTx/Statistics/Elements/ControlsAsTable/ControlBox
new file mode 100644
index 000000000..ce043e294
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/ControlsAsTable/ControlBox
@@ -0,0 +1,103 @@
+<table class="box" bgcolor="#336699" style="border-style:none solid solid solid;border-width:1px;border-color:#2E2E8C;" cellpadding="0" cellspacing="0">
+ <tbody>
+ <tr>
+ <th style="color: rgb(51, 102, 153);" class="titlebox">
+ <span class="titleboxclose">
+ <a href="#" onclick="hideshow('stats_control')">X</a></span>&nbsp;
+ <span class="titleboxtitle" style="color: rgb(255, 255, 255);">
+ <b><% $Title %></b></span>
+ </th>
+ <th style="color: rgb(51, 102, 153);" class="titleboxright">
+ <span class="titleboxright">&nbsp;</span>
+ </th>
+ </tr>
+ <tr id="element-stats_control">
+ <td colspan="3" class="" bgcolor="#dddddd">
+ <table border="0" cellpadding="1" cellspacing="0">
+% if (defined $ShowStatus) {
+ <tr>
+ <td class="collection-as-table" style="text-align:left;">Show Status:</td>
+ <td COLSPAN=3 class="collection-as-table" style="text-align:left;">
+ <& /Elements/SelectStatus, Name=>"status", Default => $Status, DefaultValue => undef &>
+ </td>
+ </tr>
+% }
+% if (defined $ShowSingleQueue) {
+ <tr>
+ <td class="collection-as-table" style="text-align:left;">Show Queue:</td>
+ <td COLSPAN=3 class="collection-as-table" style="text-align:left;">
+ <& /Elements/SelectQueue, Name=>"Queue", Default=>$Queue ,ShowNullOption=>0,
+ CheckQueueRight=>'SeeQueue' &>
+ </td>
+ </tr>
+% }
+% if (defined $ShowDates) {
+ <tr>
+ <& /RTx/Statistics/Elements/DateSelectRow, Label => "Start Date:",
+ refMonth => $sMonth, nameMonth => "sMonth",
+ refDay => $sDay, nameDay => "sDay",
+ refYear => $sYear, nameYear => "sYear" &>
+ </tr>
+ <tr>
+ <& /RTx/Statistics/Elements/DateSelectRow, Label => "End Date:",
+ refMonth => $eMonth, nameMonth => "eMonth",
+ refDay => $eDay, nameDay => "eDay",
+ refYear => $eYear, nameYear => "eYear" &>
+ </tr>
+ <tr>
+ <td class="collection-as-table" style="text-align:left;">Show Weekends:</td>
+ <td class="collection-as-table" style="text-align:left;">
+ <select name=weekends>
+ <option value=0 <% (!$weekends) && 'selected' %> >No</option>
+ <option value=1 <% $weekends && 'selected' %> >Yes</option>
+ </select>
+ </td>
+ </tr>
+% }
+% if (defined $ShowMultiQueues) {
+ <tr>
+% if (defined $ShowDates) {
+%# If we're showing the dates, we put these side by side.
+ <td COLSPAN=2 class="collection-as-table" style="text-align:left;">Select All Queues: <input type=checkbox name="AddAllCheck"></td>
+ <td COLSPAN=3 class="collection-as-table" >
+ <& /RTx/Statistics/Elements/SelectMultiQueue, Name=>"queues", Selected=>$queues_ref,
+ ShowNullOption=>0, CheckQueueRight=>'SeeQueue', Size => 10, NamedValues => 1 &>
+ </td>
+% } else {
+ <td COLSPAN=3 class="collection-as-table" style="text-align:left;">
+ <& /RTx/Statistics/Elements/SelectMultiQueue, Name=>"queues", Selected=>$queues_ref,
+ ShowNullOption=>0, CheckQueueRight=>'SeeQueue', Size => 10, NamedValues => 1 &>
+ </td>
+ </tr>
+ <tr>
+ <td class="collection-as-table" style="text-align:left;">Select All Queues: <input type=checkbox name="AddAllCheck"></td>
+% }
+ </tr>
+% }
+ <& /RTx/Statistics/Elements/ControlsAsTable/UpdatePage &>
+ </table>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+
+<BR>
+<%args>
+$Title => undef
+$ShowMultiQueues => undef
+$queues_ref => undef
+$ShowDates => undef
+$sMonth => undef
+$sDay => undef
+$sYear => undef
+$eMonth => undef
+$eDay => undef
+$eYear => undef
+$weekends => undef
+$ShowSingleQueue => undef
+$Queue => undef
+$ShowStatus => undef
+$Status => undef
+</%args>
+
diff --git a/rt/html/RTx/Statistics/Elements/ControlsAsTable/UpdatePage b/rt/html/RTx/Statistics/Elements/ControlsAsTable/UpdatePage
new file mode 100644
index 000000000..b4ccfd56f
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/ControlsAsTable/UpdatePage
@@ -0,0 +1,5 @@
+<tr>
+ <td colspan="4" style="text-align:center;padding-top:3px; background-color:#C8C8C8;">
+ <INPUT TYPE="submit" VALUE="<&|/l&>Update Page</&>">
+ </td>
+</tr>
diff --git a/rt/html/RTx/Statistics/Elements/DateSelectRow b/rt/html/RTx/Statistics/Elements/DateSelectRow
new file mode 100644
index 000000000..325e168c9
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/DateSelectRow
@@ -0,0 +1,55 @@
+ <td class="collection-as-table" style="text-align:left;"><% $Label %></td>
+ <td class="collection-as-table" style="text-align:left;">
+ <select name=<% $nameMonth %> >
+% for ($n=0;$n<=$#Statistics::months;$n++){
+% if ($$refMonth eq $n){
+% $selected ="selected";
+% }else {
+% $selected ="";
+% }
+ <option value=<% $n %> <% $selected %> ><% $Statistics::months[$n] %></option>
+%}
+ </select>
+ </td>
+ <td class="collection-as-table" style="text-align:left;">
+ <select name=<% $nameDay %> >
+% for ($n=1;$n<=31;$n++){
+% if ($$refDay == $n ){
+% $selected ="selected";
+% }else {
+% $selected ="";
+% }
+ <option value=<% $n %> <% $selected %> ><% $n %></option>
+% }
+ </select>
+ </td>
+ <td class="collection-as-table" style="text-align:left;">
+ <select name=<% $nameYear %> >
+%
+% for ($n=0;$n <= scalar @Statistics::years-1;$n++){
+% if ($Statistics::years[$n] == $$refYear){
+% $selected ="selected";
+% }else{
+% $selected ="";
+% }
+ <option value=<% $Statistics::years[$n] %> <% $selected %> ><% $Statistics::years[$n] %></option>
+% }
+ </select>
+ </td>
+
+
+<%args>
+$Label => undef
+$refMonth => undef
+$nameMonth => undef
+$refDay => undef
+$nameDay => undef
+$refYear => undef
+$nameYear => undef
+</%args>
+<%init>
+use RTx::Statistics;
+my $n;
+my $selected;
+
+</%init>
diff --git a/rt/html/RTx/Statistics/Elements/DurationAsString b/rt/html/RTx/Statistics/Elements/DurationAsString
new file mode 100755
index 000000000..c0b4d9af4
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/DurationAsString
@@ -0,0 +1,18 @@
+<%$days|'00'%> days <%$hours|'00'%>:<%$minutes|'00'%>
+<%INIT>
+
+my $MINUTE = 60;
+my $HOUR = $MINUTE*60;
+my $DAY = $HOUR * 24;
+my $WEEK = $DAY * 7;
+my $days = int($Duration / $DAY);
+$Duration = $Duration % $DAY;
+my $hours = int($Duration / $HOUR);
+$hours = sprintf("%02d", $hours);
+$Duration = $Duration % $HOUR;
+my $minutes = int($Duration/$MINUTE);
+$minutes = sprintf("%02d", $minutes);
+</%INIT>
+<%ARGS>
+$Duration => undef
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/Elements/GraphBox b/rt/html/RTx/Statistics/Elements/GraphBox
new file mode 100644
index 000000000..3dc06973e
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/GraphBox
@@ -0,0 +1,27 @@
+<div style="float:left; padding-right:30px;">
+<table class="box" bgcolor="#336699" style="border-style:none solid solid solid;border-width:1px;border-color:#2E2E8C;" cellpadding="0" cellspacing="0">
+ <tbody><tr>
+ <th style="color: rgb(51, 102, 153);" class="titlebox">
+ <span class="titleboxclose">
+ <a href="#" onclick="hideshow('stats_chart')">X</a></span>&nbsp;
+
+ <span class="titleboxtitle">
+ <b><a href="<% $GraphURL %>">Download Chart as Image</a></b>
+ </span>
+ </th>
+ <th style="color: rgb(51, 102, 153);" class="titleboxright">
+ <span class="titleboxright">&nbsp;</span>
+ </th>
+ </tr>
+
+ <tr id="element-stats_chart">
+ <td colspan="3" class="" bgcolor="#dddddd">
+ <img src="<% $GraphURL %>" ALT="Result Graph" >
+ </td>
+ </tr>
+ </tbody>
+</table>
+</div>
+<%args>
+$GraphURL => undef
+</%args>
diff --git a/rt/html/Ticket/Elements/ShowMemberOf b/rt/html/RTx/Statistics/Elements/SelectMultiQueue
index e443132bc..637f6dc80 100644..100755
--- a/rt/html/Ticket/Elements/ShowMemberOf
+++ b/rt/html/RTx/Statistics/Elements/SelectMultiQueue
@@ -43,15 +43,39 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<UL>
-% my $memberof = $Ticket->MemberOf;
-% while (my $member_of = $memberof->Next) {
-<LI><a href="<%$RT::WebPath%>/Ticket/Display.html?id=<%$member_of->Id%>"><%$member_of->Id%></a>: <%$member_of->Subject%> [<%$member_of->Status%>]
+<SELECT NAME ="<%$Name%>" multiple size="<% $Size %>">
+% if ($ShowNullOption) {
+<OPTION VALUE="">-</OPTION>
% }
-</UL>
+% while (my $queue=$q->Next) {
+% if ($ShowAllQueues || $queue->CurrentUserHasRight($CheckQueueRight)) {
+% my $targ="," . $queue->Name . ",";
+<OPTION VALUE="<%($NamedValues ? $queue->Name : $queue->Id) %>" <%( ($sel_list =~ m/$targ/) ? 'SELECTED' : '')%>><%$queue->Name%>
+% if (($Verbose) and ($queue->Description) ){
+(<%$queue->Description%>)
+% }
+</OPTION>
+% }
+% }
+</SELECT>
+<%ARGS>
+$CheckQueueRight => 'CreateTicket'
+$ShowNullOption => 1
+$ShowAllQueues => 1
+$Name => undef
+$Verbose => undef
+$NamedValues => 0
+$Selected => undef # ref to array containing selected queue names
+$Lite => 0
+$Size => 5
+</%ARGS>
<%INIT>
+
+# put list of queue names into string, starting and ending with commas
+my $sel_list = "," . join(",", @$Selected) . ",";
+
+my $q=new RT::Queues($session{'CurrentUser'});
+$q->UnLimit;
+
</%INIT>
-<%ARGS>
-$Ticket => undef
-</%ARGS>
diff --git a/rt/html/RTx/Statistics/Elements/StatColumnMap b/rt/html/RTx/Statistics/Elements/StatColumnMap
new file mode 100644
index 000000000..aef9e2f3e
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/StatColumnMap
@@ -0,0 +1,173 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
+%# <jesse@bestpractical.com>
+%#
+%# (Except where explicitly superseded by other copyright notices)
+%#
+%#
+%# LICENSE:
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+%#
+%# You should have received a copy of the GNU General Public License
+%# along with this program; if not, write to the Free Software
+%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%#
+%#
+%# CONTRIBUTION SUBMISSION POLICY:
+%#
+%# (The following paragraph is not intended to limit the rights granted
+%# to you to modify and distribute this software under the terms of
+%# the GNU General Public License and is only of importance to you if
+%# you choose to contribute your changes and enhancements to the
+%# community by submitting them to Best Practical Solutions, LLC.)
+%#
+%# By intentionally submitting any modifications, corrections or
+%# derivatives to this work, or any other work intended for use with
+%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+%# you are the copyright holder for those contributions and you grant
+%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+%# royalty-free, perpetual, license to use, copy, create derivative
+%# works based on those contributions, and sublicense and distribute
+%# those contributions and any derivatives thereof.
+%#
+%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+$Name => undef
+$Attr => undef
+</%ARGS>
+
+
+<%ONCE>
+our ( $STAT_COLUMN_MAP );
+
+sub StatColumnMap {
+ my $name = shift;
+ my $attr = shift;
+
+ # First deal with the simple things from the map
+ if ( $STAT_COLUMN_MAP->{$name} ) {
+ return ( $STAT_COLUMN_MAP->{$name}->{$attr} );
+ }
+
+ # now, let's deal with harder things, like Custom Fields
+
+ elsif ( $name =~ /^(?:CF|CustomField)\.\{(.+)\}$/ ) {
+ my $field = $1;
+
+ if ( $attr eq 'attribute' ) {
+ return (undef);
+ }
+ elsif ( $attr eq 'title' ) {
+ return ( $field );
+ }
+ elsif ( $attr eq 'value' ) {
+ # Display custom field contents, separated by newlines.
+ # For Image custom fields we also show a thumbnail here.
+ return sub {
+ my $values = $_[0]->CustomFieldValues($field);
+ return map {
+ (
+ ($_->CustomFieldObj->Type eq 'Image')
+ ? \($m->scomp( '/Elements/ShowCustomFieldImage', Object => $_ ))
+ : $_->Content
+ ),
+ \'<br>',
+ } @{ $values->ItemsArrayRef }
+ };
+ }
+ }
+}
+
+sub LinkCallback {
+ my $method = shift;
+
+ my $mode = $RT::Ticket::LINKTYPEMAP{$method}{Mode};
+ my $type = $RT::Ticket::LINKTYPEMAP{$method}{Type};
+ my $mode_uri = $mode.'URI';
+ my $local_type = 'Local'.$mode;
+
+ return sub {
+ map {
+ \'<A HREF="',
+ $_->$mode_uri->Resolver->HREF,
+ \'">',
+ ( $_->$mode_uri->IsLocal ? $_->$local_type : $_->$mode ),
+ \'</A><BR>',
+ } @{ $_[0]->Links($mode,$type)->ItemsArrayRef }
+ }
+}
+
+$STAT_COLUMN_MAP = {
+ LastUpdated => {
+ attribute => 'LastUpdated',
+ title => 'Last Updated',
+ value => sub { return $_[0]->LastUpdatedObj->AsString }
+ },
+
+ Statistics_Date => {
+ title => 'Date',
+ value => sub { return $_[0]{values}{Statistics_Date} }
+ },
+
+ Statistics_Created_Count => {
+ title => 'Created',
+ value => sub { return $_[0]{values}{Statistics_Created_Count} }
+ },
+
+ Statistics_Resolved_Count => {
+ title => 'Resolved',
+ value => sub { return $_[0]{values}{Statistics_Resolved_Count} }
+ },
+
+ Statistics_Deleted_Count => {
+ title => 'Deleted',
+ value => sub { return $_[0]{values}{Statistics_Deleted_Count} }
+ },
+
+ Statistics_Totals => {
+ title => 'Totals',
+ value => sub { return $_[0]{values}{Statistics_Totals} }
+ },
+
+ Statistics_Status => {
+ title => 'Status',
+ value => sub { return $_[0]{values}{Statistics_Status} }
+ },
+
+ Statistics_Dynamic => {
+ # Depends on having a KEY as second param
+ value => sub {
+ my $record = shift;
+ my $line = shift;
+ my $key = shift;
+ return $$record{values}{$key}
+ }
+ },
+
+ # Everything from LINKTYPEMAP
+ (map {
+ $_ => { value => LinkCallback( $_ ) }
+ } keys %RT::Ticket::LINKTYPEMAP),
+
+ '_CLASS' => {
+ value => sub { return $_[1] % 2 ? 'oddline' : 'evenline' }
+ },
+
+};
+</%ONCE>
+<%init>
+$m->comp( '/Elements/Callback', STAT_COLUMN_MAP => $STAT_COLUMN_MAP, _CallbackName => 'StatColumnMap');
+return StatColumnMap($Name, $Attr);
+</%init>
diff --git a/rt/html/RTx/Statistics/Elements/Tabs b/rt/html/RTx/Statistics/Elements/Tabs
new file mode 100755
index 000000000..4fde113ea
--- /dev/null
+++ b/rt/html/RTx/Statistics/Elements/Tabs
@@ -0,0 +1,72 @@
+%# BEGIN LICENSE BLOCK
+%#
+%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+%#
+%# (Except where explictly superceded by other copyright notices)
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+%#
+%# Unless otherwise specified, all modifications, corrections or
+%# extensions to this work which alter its source code become the
+%# property of Best Practical Solutions, LLC when submitted for
+%# inclusion in the work.
+%#
+%#
+%# END LICENSE BLOCK
+<& /Elements/Tabs,
+ tabs => $tabs,
+ current_toptab => 'RTx/Statistics/index.html',
+ current_tab => $current_tab,
+ Title => $Title &>
+
+<%INIT>
+ my $tabs = { A => { title => loc('Tickets per Day'),
+ path => 'RTx/Statistics/CallsQueueDay/index.html',
+ },
+ B => { title => loc('Tickets by status'),
+ path => 'RTx/Statistics/OpenStalled/index.html',
+ },
+ C => { title => loc('Multiple Queues'),
+ path => 'RTx/Statistics/CallsMultiQueue/index.html',
+ },
+ D => { title => loc('Ticket Trends by Day'),
+ path => 'RTx/Statistics/DayOfWeek/index.html',
+ },
+ E => { 'title' => loc('Time to Resolve'),
+ path => 'RTx/Statistics/Resolution/index.html',
+ },
+ F => { 'title' => loc('Resolve Time Graph'),
+ path => 'RTx/Statistics/TimeToResolve/index.html',
+ },
+ Z => { 'title' => loc('FAQ'),
+ path => 'RTx/Statistics/FAQ/index.html',
+ },
+ };
+
+ # Now let callbacks add their extra tabs
+ $m->comp('/Elements/Callback', tabs => $tabs, %ARGS);
+
+ foreach my $tab (sort keys %{$tabs}) {
+ if ($tabs->{$tab}->{'path'} eq $current_tab) {
+ $tabs->{$tab}->{"subtabs"} = $subtabs;
+ $tabs->{$tab}->{"current_subtab"} = $current_subtab;
+ }
+ }
+
+</%INIT>
+
+
+<%ARGS>
+$subtabs => undef
+$current_tab => undef
+$current_subtab => undef
+$Title => undef
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/FAQ/index.html b/rt/html/RTx/Statistics/FAQ/index.html
new file mode 100644
index 000000000..e7839eaad
--- /dev/null
+++ b/rt/html/RTx/Statistics/FAQ/index.html
@@ -0,0 +1,23 @@
+<& /Elements/Header, Title => 'FAQ and known issues' &>
+<& /RTx/Statistics/Elements/Tabs, Title => loc("FAQ and Known Issues") &>
+<hr noshade size="1">
+<p>This page will be used to contain known issues and FAQ`s for the Statistics
+package<br />
+This will also be used to clarify limitations of the package as they stand.</p>
+
+<p><strong>What Version of the Statistics package is this?</strong></p>
+<p>0.1.8</p>
+
+<p><strong>What time zone are the charts set to?</strong></p>
+<p>Because of the new programming method of the date functions, the charts are currently built in GMT(UTC). This may once again be
+customisable in a future release.</p>
+
+<p><strong>What is the default date period and queue?</strong></p>
+<p>The default date period is the previous 10 days, except where the chart is over a fixed 7 day period. The default queue is either
+General, or another queue set in your local configuration.</p>
+
+<p><strong>What are the limitations of the date function?</strong></p>
+<p>It has few, but it will not let you chose less than one day. you cannot select an end date before the start date and it is not
+recommended to select a date in the future or an illegal date, such at 30th February. Code has been put in place to trap these, but it may
+not be fool proof.</p>
+<hr size="1" noshade>
diff --git a/rt/html/RTx/Statistics/OpenStalled/Elements/Chart b/rt/html/RTx/Statistics/OpenStalled/Elements/Chart
new file mode 100755
index 000000000..9505881e8
--- /dev/null
+++ b/rt/html/RTx/Statistics/OpenStalled/Elements/Chart
@@ -0,0 +1,27 @@
+<%perl>
+$r->content_type("image/$format");
+print $graph->plot(\@data)->$format();
+$m->abort();
+print $#data+1 . " Elements:<p>";
+for (0..$#data) {
+print $data[$_];
+print "<p>";
+}
+</%perl>
+<%INIT>
+use GD::Graph::bars;
+
+my @data;
+my $graph = GD::Graph::bars->new($Statistics::GraphWidth,$Statistics::GraphHeight);
+$graph->set(export_format => "png",
+ x_label => 'Queue name',
+ y_label => 'Total per queue by status');
+my $format = $graph->export_format;
+$graph->set_legend(split /,/ , $ARGS{set_legend});
+push @data, [split /,/ , $ARGS{x_labels}];
+push @data, [split /,/ , $ARGS{data1}];
+push @data, [split /,/ , $ARGS{data2}];
+push @data, [split /,/ , $ARGS{data3}];
+</%INIT>
+<%ARGS>
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/OpenStalled/Results.tsv b/rt/html/RTx/Statistics/OpenStalled/Results.tsv
new file mode 100644
index 000000000..2ec1e0c4a
--- /dev/null
+++ b/rt/html/RTx/Statistics/OpenStalled/Results.tsv
@@ -0,0 +1,114 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2005 Best Practical Solutions, LLC
+%# <jesse@bestpractical.com>
+%#
+%# (Except where explicitly superseded by other copyright notices)
+%#
+%#
+%# LICENSE:
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+%#
+%# You should have received a copy of the GNU General Public License
+%# along with this program; if not, write to the Free Software
+%# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+%#
+%#
+%# CONTRIBUTION SUBMISSION POLICY:
+%#
+%# (The following paragraph is not intended to limit the rights granted
+%# to you to modify and distribute this software under the terms of
+%# the GNU General Public License and is only of importance to you if
+%# you choose to contribute your changes and enhancements to the
+%# community by submitting them to Best Practical Solutions, LLC.)
+%#
+%# By intentionally submitting any modifications, corrections or
+%# derivatives to this work, or any other work intended for use with
+%# Request Tracker, to Best Practical Solutions, LLC, you confirm that
+%# you are the copyright holder for those contributions and you grant
+%# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
+%# royalty-free, perpetual, license to use, copy, create derivative
+%# works based on those contributions, and sublicense and distribute
+%# those contributions and any derivatives thereof.
+%#
+%# END BPS TAGGED BLOCK }}}
+<%ARGS>
+@queues => @Statistics::OpenStalledQueueList
+</%ARGS>
+
+<%INIT>
+use RTx::Statistics;
+use Time::Local;
+
+ my $n = 0;
+ my @data;
+ my @msgs;
+ my %totals;
+ my $QueryString;
+ my $now = new RT::Date($session{CurrentUser});
+ my $tix = new RT::Tickets($session{'CurrentUser'});
+
+ my %queues = map {
+ $_ => 1;
+ } (@queues);
+
+ # set content type
+ $r->content_type('application/vnd.ms-excel');
+
+ $QueryString = "queues=" . join("&queues=", @queues);
+
+ my $queue = new RT::Queues($session{CurrentUser});
+ $queue->UnLimit;
+
+ my $QueueObj = new RT::Queue($session{'CurrentUser'});
+ $QueueObj->Load($queue);
+
+ # Put out some data about the generation of this file
+ $m->out("Tickets by Status by Queue for Queues:\t" . join(',', @queues) . "\tGenerated at:\t" . Statistics::FormatDate("%x %X", $now). "\n\n");
+
+ # basically the same as index.html
+
+ # Output header row
+ $m->out("Status");
+ for ( sort keys %queues) {
+ push @data, $_;
+ my $Queueobj = new RT::Queue($session{'CurrentUser'});
+ $Queueobj->Load($_);
+ next if !$Queueobj->CurrentUserHasRight('SeeQueue');
+ $m->out("\t" . $_);
+ }
+ $m->out("\tTotals\n");
+
+ foreach my $s (qw(new open stalled)) {
+ $m->out("$s");
+ my $total=0;
+ foreach my $q (sort keys %queues) {
+ $tix = new RT::Tickets($session{'CurrentUser'});
+ $tix->LimitQueue(VALUE => "$q");
+ $tix->LimitStatus(VALUE => "$s");
+ $totals{$q} += $tix->Count; # Add up columns for each queue
+ $m->out("\t" . $tix->Count);
+ $total += $tix->Count;
+ }
+ $m->out("\t$total\n");
+ $totals{"Totals"} += $total;
+ }
+ $m->out("Totals");
+ foreach my $q (sort keys %queues) {
+ $m->out("\t" . $totals{$q});
+ }
+ $m->out("\t" . $totals{"Totals"} . "\n");
+
+ $m->abort();
+</%INIT>
diff --git a/rt/html/RTx/Statistics/OpenStalled/index.html b/rt/html/RTx/Statistics/OpenStalled/index.html
new file mode 100755
index 000000000..d0cd9f158
--- /dev/null
+++ b/rt/html/RTx/Statistics/OpenStalled/index.html
@@ -0,0 +1,188 @@
+<& /Elements/Header, Title => loc('New, Open and Stalled tickets by Queue') &>
+<& /RTx/Statistics/Elements/Tabs, Title => loc('New, Open and Stalled tickets by Queue') &>
+
+<h3>Description</h3>
+<p>The purpose of this page is to show a snapshot of the current status of tickets by Queue. You can multi select Queues from the dropdown
+list or simply show all available queues. This will indicate how many tickets have not yet been viewed (New), how many have been at least
+viewed once (Open) and how many have had their status changed to stalled.</p>
+
+<form method="POST" action="index.html">
+
+%my $tix = new RT::Tickets($session{'CurrentUser'});
+%if ($queue) {
+% $tix->LimitQueue (VALUE => $queue);
+%}
+
+
+%my $title = "New, Open and Stalled Tickets in " . join(', ', @queues);
+<& /Elements/TitleBoxStart, title => $title, title_href => "/RTx/Statistics/OpenStalled/index.html?$QueryString"&>
+<TABLE BORDER=0 cellspacing=0 cellpadding=1 WIDTH="100%">
+% if ($ShowHeader) {
+<& /RTx/Statistics/Elements/CollectionAsTable/Header,
+ Format => \@RowFormat,
+ FormatString => $RowFormat,
+ AllowSorting => $AllowSorting,
+ Order => $Order,
+ Query => undef,
+ Rows => $Rows,
+ Page => $Page,
+ OrderBy => $OrderBy ,
+ BaseURL => $BaseURL,
+ maxitems => $maxitems &>
+% }
+
+% for ( sort keys %queues_to_show) {
+% push @data, $_;
+% }
+% my @legend;
+% my $total = 0;
+% my $line = 0;
+%# NOTE need to handle all status values (see share/html/Elements/SelectStatus).
+% foreach my $s (qw(new open stalled)) {
+% $line++;
+% push @legend, $s;
+% $total=0;
+% foreach my $q (sort keys %queues_to_show) {
+% $tix = new RT::Tickets($session{'CurrentUser'});
+% $tix->LimitQueue(VALUE => "$q");
+% $tix->LimitStatus(VALUE => "$s");
+% push @data, $tix->Count;
+% $totals{$q} += $tix->Count; # Add up columns for each queue
+% $total += $tix->Count;
+% $values{$q} = $tix->Count;
+% }
+% $totals{"Totals"} += $total;
+% $values{Statistics_Status} = $s;
+% $values{Statistics_Totals} = $total;
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@RowFormat, i => $line, record => $record, maxitems => $maxitems &>
+% }
+% $values{Statistics_Status} = "Totals";
+% foreach my $q (sort keys %queues_to_show) {
+% $values{$q} = $totals{$q};
+% }
+% $values{Statistics_Totals} = $totals{"Totals"};
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@BoldRowFormat, i => $line+1, record => $record, maxitems => $maxitems &>
+</table>
+<& /Elements/TitleBoxEnd&>
+
+<hr>
+
+<BR />
+<BR />
+
+% use Data::Dumper;
+% Statistics::DebugLog("Dump of data array is " . Dumper(@data) . "\n");
+% my $url = 'Elements/Chart?x_labels=';
+% for (1..(scalar keys %queues_to_show)) {
+% $url .= $m->interp->apply_escapes((shift @data),'u') . ',';
+% }
+% chop $url;
+% $url .= '&data1=' ;
+% for (1..(scalar keys %queues_to_show)) {
+% $url .= $m->interp->apply_escapes((shift @data),'u') . ',';
+% }
+% chop $url;
+% $url .= '&data2=' ;
+% for (1..(scalar keys %queues_to_show)) {
+% $url .= $m->interp->apply_escapes((shift @data),'u') . ',';
+% }
+% chop $url;
+% $url .= '&data3=' ;
+% for (1..(scalar keys %queues_to_show)) {
+% $url .= $m->interp->apply_escapes((shift @data),'u') . ',';
+% }
+% $url .= '&set_legend='.(join ",", @legend);
+
+
+<& /RTx/Statistics/Elements/GraphBox, GraphURL => $url &>
+
+<& /RTx/Statistics/Elements/ControlsAsTable/ControlBox, Title => "Select Queues", ShowMultiQueues => 1, queues_ref => \@queues &>
+
+<a href="<%$RT::WebPath%>/RTx/Statistics/OpenStalled/index.html?<% $QueryString %>"><&|/l&>Bookmarkable link</&></a>
+%# | <a href="<%$RT::WebPath%>/RTx/Statistics/OpenStalled/Results.tsv?<%$QueryString%>"><&|/l&>spreadsheet</&></a>
+<BR>
+<BR>
+
+</FORM>
+
+% Statistics::DebugInit( $m );
+
+<%ARGS>
+@queues => @Statistics::OpenStalledQueueList
+$AllowSorting => undef
+$Order => undef
+$OrderBy => undef
+$ShowNavigation => 1
+$ShowHeader => 1
+$Rows => 50
+$Page => 1
+$BaseURL => undef
+$AddAllCheck => undef
+</%ARGS>
+
+<%INIT>
+ use RTx::Statistics;
+
+ my $n = 0;
+ my @data;
+ my @msgs;
+ my %totals;
+ my $QueryString;
+ my %queues_to_show;
+ my $maxitems;
+ my $RowFormat;
+ my $BoldRowFormat;
+ my %record;
+ my %values;
+ my $record = \%record;
+
+ $record{values} = \%values;
+
+ Statistics::DebugClear();
+
+ # Handle the Add All Checkbox
+ if($AddAllCheck eq "on") {
+ $AddAllCheck = undef;
+ undef (@queues);
+ my $q=new RT::Queues($session{'CurrentUser'});
+ $q->UnLimit;
+ while (my $queue=$q->Next) {
+ next if !$queue->CurrentUserHasRight('SeeQueue');
+ push @queues, $queue->Name;
+ }
+ }
+
+ # If the user has the right to see the queue, put it into the map
+ for my $q (@queues) {
+ my $Queueobj = new RT::Queue($session{'CurrentUser'});
+ $Queueobj->Load($q);
+ next if !$Queueobj->CurrentUserHasRight('SeeQueue');
+ $queues_to_show{$q} = 1;
+ }
+
+ $maxitems = (scalar @queues) + 2;
+
+ # Build the new query string
+ $QueryString = "queues=" . join("&queues=", @queues);
+
+ # Build the format strings
+ $RowFormat = "'__Statistics_Status__'";
+ $BoldRowFormat = "'<B>__Statistics_Status__</B>'";
+ for my $q (@queues) {
+ $RowFormat .= ",'__Statistics_Dynamic__/KEY:$q/TITLE:$q/STYLE:text-align:right;'";
+ $BoldRowFormat .= ",'<B>__Statistics_Dynamic__</B>/KEY:$q/TITLE:$q/STYLE:text-align:right;'";
+ }
+ $RowFormat .= ",'<B>__Statistics_Totals__</B>/STYLE:text-align:right;'";
+ $BoldRowFormat .= ",'<B>__Statistics_Totals__</B>/STYLE:text-align:right;'";
+ # Parse the formats into structures.
+ my (@RowFormat) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $RowFormat);
+ my (@BoldRowFormat) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $BoldRowFormat);
+
+
+ my $queue = new RT::Queues($session{CurrentUser});
+ $queue->UnLimit;
+
+ my $QueueObj = new RT::Queue($session{'CurrentUser'});
+ $QueueObj->Load($queue);
+
+</%INIT>
diff --git a/rt/html/RTx/Statistics/Resolution/Elements/Chart b/rt/html/RTx/Statistics/Resolution/Elements/Chart
new file mode 100755
index 000000000..fa0ac5538
--- /dev/null
+++ b/rt/html/RTx/Statistics/Resolution/Elements/Chart
@@ -0,0 +1,29 @@
+<%perl>
+$r->content_type("image/$format");
+print $graph->plot(\@data)->$format();
+$m->abort();
+print $#data+1 . " Elements:<p>";
+for (0..$#data) {
+print $data[$_];
+print "<p>";
+}
+</%perl>
+<%INIT>
+use GD::Graph::lines;
+
+my @data;
+my $graph = GD::Graph::lines->new($Statistics::GraphWidth,$Statistics::GraphHeight);
+$graph->set(export_format => "png",
+ x_label => 'Days',
+ y_label => 'Average time in Days');
+
+push @data, [split /,/ , $ARGS{x_labels}];
+push @data, [split /,/ , $ARGS{data1}];
+push @data, [split /,/ , $ARGS{data2}];
+push @data, [split /,/ , $ARGS{data3}];
+
+my $format = $graph->export_format;
+#$r->content_type("image/$format");
+</%INIT>
+<%ARGS>
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/Resolution/index.html b/rt/html/RTx/Statistics/Resolution/index.html
new file mode 100644
index 000000000..d9885b093
--- /dev/null
+++ b/rt/html/RTx/Statistics/Resolution/index.html
@@ -0,0 +1,269 @@
+<& /Elements/Header, Title => 'Time to Resolution' &>
+<& /RTx/Statistics/Elements/Tabs, Title => loc("Time To Resolve tickets by Queue for : " .$QueueObj->Name()) &>
+<h3>Description</h3>
+<p>This page shows details of resolution of tickets in the selected queue. It displays tickets created on each day in your selected date
+range. Of those tickets created on that day, how many have been resolved and the total time it has taken for all tickets created on that
+day to be resolved.</p>
+<p>At the bottom of the chart is shows total time taken to resolve all tickets
+in the selected date range and the average time per ticket to
+resolve.</p>
+
+<form method="POST" action="index.html">
+
+%my $title = "Time to resolve in " . $QueueObj->Name() . " per day from " .
+% Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[0]) . " through " .
+% Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[$#dates-1]);
+<&|/Elements/TitleBox,
+ title => $title,
+ title_href => "/RTx/Statistics/Resolution/index.html?$QueryString" &>
+<TABLE BORDER=0 cellspacing=0 cellpadding=1 WIDTH=100%>
+% if ($ShowHeader) {
+<& /RTx/Statistics/Elements/CollectionAsTable/Header,
+ Format => \@Format,
+ FormatString => $Format,
+ AllowSorting => $AllowSorting,
+ Order => $Order,
+ Query => undef,
+ Rows => $Rows,
+ Page => $Page,
+ OrderBy => $OrderBy ,
+ BaseURL => $BaseURL,
+ maxitems => $maxitems &>
+% }
+% my $line = 1;
+% LINE: for my $d (0..$#dates ) {
+% if ($d == $#dates ){
+% next LINE;
+% }
+% my $x = 1;
+% $values{Statistics_Date} = Statistics::FormatDate($Statistics::PerDayDateFormat, $dates[$d]);
+% my $tix = new RT::Tickets($session{'CurrentUser'});
+% $tix->LimitCreated(VALUE => $dates[$d]->ISO, OPERATOR => ">=");
+% if ($dates[$d+1]) {
+% $tix->LimitCreated(VALUE => $dates[$d+1]->ISO, OPERATOR => "<=");
+% }
+% if ($Queue) {
+% $tix->LimitQueue (VALUE => $Queue);
+% }
+% $values{Statistics_Created_Count} = $tix->Count;
+% $tix->LimitStatus(VALUE => "resolved");
+% $values{Statistics_Resolved_Count} = $tix->Count;
+% if ($tix->Count) {
+% my @tix = @{$tix->ItemsArrayRef};
+% my $total;
+% $total += ($_->ResolvedObj->Unix - $_->CreatedObj->Unix) for @tix;
+% $size+= ($#tix +1);
+% $grandtotal += $total;
+% $values{Duration} = Statistics::DurationAsString($total);
+% $data[$x++][$d] = int ($total );
+% } else {
+% $values{Duration} = "N/A";
+% }
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@Format, i => $line, record => $record, maxitems => $maxitems &>
+% $line++;
+%}
+% $size =1 if $size==0;
+% $values{text} = "Average time to resolve = " . Statistics::DurationAsString($grandtotal / $size);
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@OneCellFormat, i => $line, record => $record, maxitems => $maxitems &>
+% $line++;
+% $values{text} = "Total time to resolve = " . Statistics::DurationAsString( $grandtotal );
+<& /RTx/Statistics/Elements/CollectionAsTable/Row, Format => \@OneCellFormat, i => $line, record => $record, maxitems => $maxitems &>
+% $line++;
+</table>
+</&>
+
+<hr>
+
+<BR />
+<BR />
+
+<%perl>
+# Create the graph URL
+
+# change the total time to resolve to a floating point number of days
+foreach my $dat(@{$data[1]} ){
+ $dat = ($dat / $Statistics::secsPerDay);
+ $dat = sprintf("%0.4f", $dat);
+}
+
+my $url = 'Elements/Chart?x_labels=';
+for (0..$diff-1) {
+ $url .= $data[0][$_] . ",";
+}
+chop $url;
+shift @data;
+$url .= "&data1=";
+for(0..$diff-1) {
+ $data[0][$_] = 0 if !$data[0][$_];
+ $url .= $data[0][$_] . ",";
+}
+</%perl>
+
+<& /RTx/Statistics/Elements/GraphBox, GraphURL => $url &>
+
+<& /RTx/Statistics/Elements/ControlsAsTable/ControlBox,
+ Title => "Change Queue or Dates",
+ ShowDates => 1, sMonth => \$sMonth, sDay => \$sDay, sYear => \$sYear,
+ eMonth => \$eMonth, eDay => \$eDay, eYear => \$eYear,
+ weekends => $weekends,
+ ShowSingleQueue => 1, Queue => $Queue
+ &>
+
+</form>
+
+<%ARGS>
+$max => $Statistics::TimeToResolveMaxRows
+$Queue => undef
+$weekends =>$Statistics::TimeToResolveWeekends
+$sMonth=>undef
+$sDay=>undef
+$sYear=>undef
+$eMonth=>undef
+$eDay=>undef
+$eYear=>undef
+$days=>undef
+$currentMonth=>undef
+
+$AllowSorting => undef
+$Order => undef
+$OrderBy => undef
+$ShowNavigation => 1
+$ShowHeader => 1
+$Rows => 50
+$Page => 1
+$BaseURL => undef
+</%ARGS>
+
+<%INIT>
+use RTx::Statistics;
+use Time::Local;
+my $n = 0;
+my @data = ([]);
+my @dates;
+my @msgs;
+my $size;
+my $selected;
+my $grandtotal = 0;
+my $diff;
+my $sEpoch=0;
+my $eEpoch=0;
+my $QueryString;
+
+my $maxitems = 4;
+my %record;
+my %values;
+my $record = \%record;
+
+$record{values} = \%values;
+
+
+# If debugging, set things up and display all the args
+Statistics::DebugClear();
+Statistics::DebugLog("CallsQueueDay/index.html ARGS:\n");
+for my $key (keys %ARGS) {
+ Statistics::DebugLog("ARG{ $key }=" . $ARGS{$key} . "\n");
+}
+
+my $Format = qq{ Statistics_Date,
+ '__Statistics_Created_Count__/STYLE:text-align:right;',
+ '__Statistics_Resolved_Count__/STYLE:text-align:right;',
+ '__Statistics_Dynamic__/KEY:Duration/TITLE:Time To Resolve/STYLE:text-align:right;' };
+my $BoldFormat = qq{ '<B>__Statistics_Date__</B>',
+ '<B>__Statistics_Created_Count__</B>/STYLE:text-align:right;',
+ '<B>__Statistics_Resolved_Count__</B>/STYLE:text-align:right;',
+ '<B>__Statistics_Dynamic__</B>/KEY:Duration/TITLE:Time To Resolve/STYLE:text-align:right;' };
+
+# TODO need way to make this cell do colspan
+my $OneCellFormat = qq{ '<B>__Statistics_Dynamic__</B>/KEY:text/STYLE:text-align:left;','','','' };
+
+my (@Format) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $Format);
+my (@BoldFormat) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $BoldFormat);
+my (@OneCellFormat) = $m->comp('/RTx/Statistics/Elements/CollectionAsTable/ParseFormat', Format => $OneCellFormat);
+
+Statistics::DebugLog("CallsQueueDay/index.html Format array=" . join(',', @Format) . "\n");
+
+if ($sDay > $Statistics::monthsMaxDay{$sMonth}) {
+ $sDay = $Statistics::monthsMaxDay{$sMonth};
+}
+
+if ($eDay > $Statistics::monthsMaxDay{$eMonth}) {
+ $eDay = $Statistics::monthsMaxDay{$eMonth};
+}
+
+if ($sYear){
+ $sEpoch = timelocal(0, 0, 0, $sDay, $sMonth, $sYear-1900);
+}
+if ($eYear){
+Statistics::DebugLog("eMonth = " . $eMonth . "\n");
+ $eEpoch = timelocal(0, 0, 0, $eDay, $eMonth, $eYear-1900);
+} else {
+ # This case happens when the page is first loaded
+ my @local = localtime(time);
+ ($eDay, $eMonth, $eYear) = ($local[3], $local[4], $local[5]);
+ $eYear += 1900;
+ $eEpoch = timelocal(0, 0, 0, $local[3], $local[4], $local[5], $local[6], $local[7], $local[8]);
+Statistics::DebugLog("Setting eEpoch=$eEpoch from current time.\n");
+}
+
+if (($eEpoch < $sEpoch) || ($sEpoch == 0)) {
+ # We have an end, but not a start, or, overlapping.
+
+ # if $currentMonth is set, just set the day to 1
+ if($currentMonth) {
+ # set start vars from end, but with day set to 1
+ (undef, undef, undef, $sDay, $sMonth, $sYear) = localtime($eEpoch);
+ $sDay=1;
+ $sEpoch = timelocal(0, 0, 0, $sDay, $sMonth, $sYear);
+ } else {
+ # If the user has specified how many days back to go, use that,
+ # If not, set start to configured default period before end
+ if(defined $days) {
+ $sEpoch = $eEpoch - ($days * $Statistics::secsPerDay);
+ } else {
+ $sEpoch = $eEpoch - ($Statistics::PerDayPeriod * $Statistics::secsPerDay);
+ }
+ (undef, undef, undef, $sDay, $sMonth, $sYear) = localtime($sEpoch);
+ }
+ $sYear += 1900;
+}
+
+# Compute days to chart.
+# The +1 is because we need to generate one more date. If the user
+# selected a 10 day range, we need to generate 11 days.
+$diff = int(($eEpoch - $sEpoch + $Statistics::secsPerDay - 1) / $Statistics::secsPerDay)+1;
+Statistics::DebugLog("Setting diff=$diff\n");
+
+Statistics::DebugLog("sEpoch=$sEpoch, components=" . join(',', localtime($sEpoch)) . "\n");
+Statistics::DebugLog("eEpoch=$eEpoch, components=" . join(',', localtime($eEpoch)) . "\n");
+
+my $QueueObj = new RT::Queue($session{'CurrentUser'});
+if (!defined $Queue) {
+ $QueueObj->Load($Statistics::TimeToResolveQueue);
+ $Queue = $QueueObj->Id();
+}
+
+# Set up the string for the current query for bookmarkable link
+$QueryString = "sDay=$sDay&sMonth=$sMonth&sYear=$sYear&eDay=$eDay&eMonth=$eMonth&eYear=$eYear&weekends=$weekends&Queue=$Queue";
+
+# Set up the end date to be midnight(morning) of the date after the one the user wanted.
+my $endRange = $eEpoch + $Statistics::secsPerDay;
+$QueueObj->Load($Queue);
+# NOTE: list loop starts at the end of the date range, unshifting dates onto
+# the arrays, so that they end up in start to finish order.
+$eEpoch += $Statistics::secsPerDay;
+$n = 0;
+until ($#dates == $diff ) {
+ my $date = new RT::Date($session{CurrentUser});
+ $date->Set(Value=>$endRange - $n, Format => 'unix');
+ # Note: we used to adjust the time to local midnight, but
+ # none of the other date entry fields in RT seem to adjust, so we've stopped.
+ #Statistics::DebugLog("Before adjust to midnight date " . Statistics::FormatDate("%c", $date) . "\n");
+ $n+= $Statistics::secsPerDay;
+ # If we aren't showing weekends and this is one, decrement the number
+ # of days to show and skip to the next date.
+ if(!$weekends and Statistics::RTDateIsWeekend($date)) {$diff--; next;}
+ unshift @dates, $date;
+Statistics::DebugLog("pushing date " . Statistics::FormatDate("%c", $date) . "\n");
+ unshift @{ $data[0] }, Statistics::FormatDate($Statistics::PerDayLabelDateFormat, $date);
+}
+</%INIT>
diff --git a/rt/html/RTx/Statistics/TimeToResolve/Elements/Chart b/rt/html/RTx/Statistics/TimeToResolve/Elements/Chart
new file mode 100755
index 000000000..a069a7bfb
--- /dev/null
+++ b/rt/html/RTx/Statistics/TimeToResolve/Elements/Chart
@@ -0,0 +1,23 @@
+<%perl>
+print $graph->plot(\@data)->$format();
+$m->abort();
+</%perl>
+<%INIT>
+use GD::Graph::points;
+
+my @data;
+my $graph = GD::Graph::points->new(400,300);
+$graph->set(export_format => "png",
+ marker_size => $ARGS{marker_size},
+ x_label => 'Average time to resolve (Days)',
+ y_label => 'Number of tickets resolved' );
+#$r->content_type("image/$format");
+my $format = $graph->export_format;
+push @data, [split /,/ , $ARGS{x_labels}];
+for (1..((scalar keys %ARGS)-2)) {
+ push @data, [split /,/ , $ARGS{"data".$_}];
+}
+
+</%INIT>
+<%ARGS>
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/TimeToResolve/index.html b/rt/html/RTx/Statistics/TimeToResolve/index.html
new file mode 100755
index 000000000..2124b538d
--- /dev/null
+++ b/rt/html/RTx/Statistics/TimeToResolve/index.html
@@ -0,0 +1,75 @@
+<& /Elements/Header, Title => 'Time to Resolve in Queue' &>
+<& /RTx/Statistics/Elements/Tabs, Title => 'Time to Resolve, by ticket in Queue:' . $QueueObj->Name() &>
+
+<h3>Description</h3>
+<p>This page displays the same information as the Time to Resolve chart, but in a scattergraph format and only for the previous 7 calendar
+days. It only displays data for tickets which have been resolved. Each division on the Days axis is one day and the granularity of this chart
+is 30 minutes.</p>
+<form method="POST">
+
+<table>
+ <tr>
+ <td>Show Queue:</td>
+ <td COLSPAN=3><& /Elements/SelectQueue, Name=>"queue", Default=>$queue ,ShowNullOption=>0,
+ CheckQueueRight=>'SeeQueue' &></td>
+ </tr>
+</table>
+<INPUT TYPE="submit" VALUE="Update Page"</INPUT>
+</form>
+
+<BR>
+% my $url = 'Elements/Chart?x_labels=';
+% my $i;
+% $url .= join ",", (map {(int($_/2) == $_/2 && (++$i)%2) ? $_/2 : ""} grep {$counts[$_]} 0..($#counts-1)), "longer";
+% $url .= '&';
+% $url .= "marker_size=1&";
+% $url .= "data1=".(join ",", map { $_ || () } @counts)."&";
+% chop $url;
+<IMG SRC="<% $url %>">
+
+<BR>
+
+%Statistics::DebugInit($m);
+
+<%ARGS>
+$queue => undef
+</%ARGS>
+
+<%INIT>
+use RTx::Statistics;
+
+my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
+my $n = 0;
+my @data = ([]);
+my @msgs;
+my @counts;
+
+Statistics::DebugClear();
+Statistics::DebugLog("TimeToResolve/index.html ARGS:\n");
+for my $key (keys %ARGS) {
+ Statistics::DebugLog("ARG{ $key }=" . $ARGS{$key} . "\n");
+}
+
+my $QueueObj = new RT::Queue($session{'CurrentUser'});
+if (!defined $queue) {
+ $QueueObj->Load($Statistics::TimeToResolveGraphQueue);
+ $queue = $QueueObj->Id();
+} else {
+ $QueueObj->Load($queue);
+}
+
+
+my $tix = new RT::Tickets($session{'CurrentUser'});
+$tix->LimitQueue (VALUE => $queue) if $queue;
+$tix->LimitStatus(VALUE => "resolved");
+$tix->UnLimit;
+if ($tix->Count) {
+ while (my $t = $tix->RT::SearchBuilder::Next) { # BLOODY HACK
+ my $when = $t->ResolvedObj->Unix - $t->CreatedObj->Unix;
+ next unless $when > 0; # Doubly bloody hack
+ my $max = (60*60*24*2) / 1800;
+ my $x = int($when / 1800);
+ $counts[$x > $max ? $max : $x]++;
+ }
+}
+</%INIT>
diff --git a/rt/html/RTx/Statistics/UserTest/Elements/Chart b/rt/html/RTx/Statistics/UserTest/Elements/Chart
new file mode 100755
index 000000000..99eb2a2b1
--- /dev/null
+++ b/rt/html/RTx/Statistics/UserTest/Elements/Chart
@@ -0,0 +1,28 @@
+<%perl>
+print $graph->plot(\@data)->$format();
+$m->abort();
+print $#data+1 . " Elements:<p>";
+for (0..$#data) {
+print $data[$_];
+print "<p>";
+}
+</%perl>
+<%INIT>
+use GD::Graph::lines;
+
+my @data;
+my $graph = GD::Graph::lines->new(640,480);
+$graph->set(export_format => "png",
+ x_label => 'Days',
+ y_label => 'Average time in Days');
+
+push @data, [split /,/ , $ARGS{x_labels}];
+push @data, [split /,/ , $ARGS{data1}];
+push @data, [split /,/ , $ARGS{data2}];
+push @data, [split /,/ , $ARGS{data3}];
+
+my $format = $graph->export_format;
+#$r->content_type("image/$format");
+</%INIT>
+<%ARGS>
+</%ARGS>
diff --git a/rt/html/RTx/Statistics/UserTest/index.html b/rt/html/RTx/Statistics/UserTest/index.html
new file mode 100755
index 000000000..7bc25da70
--- /dev/null
+++ b/rt/html/RTx/Statistics/UserTest/index.html
@@ -0,0 +1,54 @@
+<& /Elements/Header, Title => 'Time to Resolve in Queue' &>
+<& /RTx/Statistics/Elements/Tabs, Title => 'Time to Resolve, by ticket in Queue:' . $QueueObj->Name() &>
+
+
+<form method="POST">
+
+See Queue:<BR>
+<& /Elements/SelectQueue, Name=>"queue", Default => "$queue" &>
+<BR>
+<INPUT TYPE="submit" VALUE="Go!"</INPUT>
+</form>
+
+<BR>
+% my $url = 'Elements/Chart?x_labels=';
+% my $i;
+% $url .= join ",", (map {(int($_/2) == $_/2 && (++$i)%2) ? $_/2 : ""} grep {$counts[$_]} 0..($#counts-1)), "longer";
+% $url .= '&';
+% $url .= "marker_size=1&";
+% $url .= "data1=".(join ",", map { $_ || () } @counts)."&";
+% chop $url;
+<IMG SRC="<% $url %>">
+
+<BR>
+
+<%ARGS>
+$queue => $Statistics::TimeToResolveGraphQueue;
+</%ARGS>
+
+<%INIT>
+use RTx::Statistics;
+
+my @days = qw(Sun Mon Tue Wed Thu Fri Sat);
+my $n = 0;
+my @data = ([]);
+my @msgs;
+my @counts;
+
+my $QueueObj = new RT::Queue($session{'CurrentUser'});
+$QueueObj->Load($queue);
+
+my $tix = new RT::Tickets($session{'CurrentUser'});
+$tix->LimitQueue (VALUE => $queue) if $queue;
+$tix->LimitStatus(VALUE => "resolved");
+$tix->UnLimit;
+if ($tix->Count) {
+ while (my $t = $tix->RT::SearchBuilder::Next) { # BLOODY HACK
+ my $when = $t->ResolvedObj->Unix - $t->CreatedObj->Unix;
+ next unless $when > 0; # Doubly bloody hack
+ my $max = (60*60*24*2) / 1800;
+ my $x = int($when / 1800);
+ $counts[$x > $max ? $max : $x]++;
+ }
+}
+</%INIT>
diff --git a/rt/html/RTx/Statistics/index.html b/rt/html/RTx/Statistics/index.html
new file mode 100755
index 000000000..41490de18
--- /dev/null
+++ b/rt/html/RTx/Statistics/index.html
@@ -0,0 +1,59 @@
+%# BEGIN LICENSE BLOCK
+%#
+%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
+%#
+%# (Except where explictly superceded by other copyright notices)
+%#
+%# Copyright this file (c) 2003 Harald Wagener <hwagener@hamburg.fcb.com>
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+%#
+%# Unless otherwise specified, all modifications, corrections or
+%# extensions to this work which alter its source code become the
+%# property of Best Practical Solutions, LLC when submitted for
+%# inclusion in the work.
+%#
+%#
+%# END LICENSE BLOCK
+<& /Elements/Header, Title => loc('RT Statistics') &>
+<& /RTx/Statistics/Elements/Tabs, Title => loc('RT Statistics') &>
+
+<&|/l&><h2>Description</h2>
+<p>These 6 options below enable you to display management data from the RT Database in table and graphical forms, enabling trends, bottlenecks, load problems etc to be identified.
+Each contains a description of how the data is displayed and describes the options available to you.</p></&>
+<ul>
+<li><strong><a href="CallsQueueDay/index.html">
+<&|/l&>Tickets per day per Queue</&></a></strong><br />
+<&|/l&>View the number of tickets created, resolved or deleted in a<br /> specific Queue, over the requested period of days</&>
+</li>
+<li><strong><a href="OpenStalled/index.html">
+<&|/l&>Tickets status by Queue</&></a></strong><br>
+<&|/l&>View numbers of new, open and stalled tickets in a selected Queue</&>
+</li>
+<li><strong><a href="CallsMultiQueue/index.html">
+<&|/l&>Tickets per Day in Multiple Queues</&>
+</a></strong><br>
+<&|/l&>View tickets created, resolved or deleted on in one or more Queues<br /> over a specified time period</&>
+</li>
+<li><strong><a href="DayOfWeek/index.html">
+<&|/l&>Tickets per Day of Week (absolute)</&></a></strong><br>
+<&|/l&>View trends showing when tickets are created, resolved or deleted</&>
+</li>
+<li><strong><a href="Resolution/index.html">
+<&|/l&>Time to Resolve</&></a></strong><br>
+<&|/l&>View how long tickets take to be resolved by Queue</&>
+</li>
+</li>
+<li><strong><a href="TimeToResolve/index.html">
+<&|/l&>Time to Resolve (scatter graph)</&></a></strong><br>
+<&|/l&>View a detailed scatter graph of time to resolve tickets by Queue</&>
+</li>
+</ul>
diff --git a/rt/html/Reports/Activity/ActivityDetail.html b/rt/html/Reports/Activity/ActivityDetail.html
new file mode 100644
index 000000000..ef0d830f7
--- /dev/null
+++ b/rt/html/Reports/Activity/ActivityDetail.html
@@ -0,0 +1,83 @@
+<&|Elements/Wrapper, %ARGS, title => loc("Activity detail"),
+ path => "Reports/Activity/ActivityDetail.html",
+ &>
+
+<& Elements/MiniPlot, data => \%counts &>
+
+<table style="width: 100%">
+<tr class="titlerow">
+<th>Queue</th><th>Activity</th><th>Date</th><th>Time</th><th>Ticket #</th><th>User</th><th>Short description</th>
+</tr>
+% for my $item (@items) {
+<tr>
+<td><% $item->{queue} %></td>
+<td><% $item->{status} %></td>
+<td><% $item->{date} %></td>
+<td><% $item->{time} %></td>
+<td><% $item->{id} %></td>
+<td><% $item->{actor} %></td>
+<td><% $item->{notes} %></td>
+</tr>
+% }
+</table>
+
+</&>
+<%args>
+$query => 'id > 0'
+$start => "2005/01/01"
+$end => "2006/01/01"
+</%args>
+<%init>
+
+
+my $summary_tickets = RT::Tickets->new($session{'CurrentUser'});
+$summary_tickets->FromSQL($query . " AND ( Updated >= '$start' AND Updated <= '$end')");
+my %counts;
+while (my $ticket = $summary_tickets->Next) {
+ my $txns = $ticket->Transactions;
+ $txns->Limit(FIELD => 'Created', OPERATOR => '>=', VALUE => $start);
+ $txns->Limit(FIELD => 'Created', OPERATOR => '<=', VALUE => $end);
+ # I think they really don't just want status changes
+ $txns->Limit(FIELD => 'Type', VALUE => 'Status', ENTRYAGGREGATOR => 'OR');
+ $txns->Limit(FIELD => 'Type', VALUE => 'Create');
+
+ while (my $txn = $txns->Next){
+ my $date = substr($txn->Created, 0, 10);
+ # we don't have data on the status of a new ticket, default to 'new'
+ $counts{$date}{$txn->NewValue || 'new'}++;
+ }
+}
+
+
+my $tickets = RT::Tickets->new($session{'CurrentUser'});
+$tickets->FromSQL($query);
+my @items;
+while (my $ticket = $tickets->Next) {
+ my $txns = $ticket->Transactions;
+ $txns->Limit(FIELD => 'Created', OPERATOR => '>=', VALUE => $start);
+ $txns->Limit(FIELD => 'Created', OPERATOR => '<=', VALUE => $end);
+ # I think they really don't just want status changes
+ $txns->Limit(FIELD => 'Type', VALUE => 'Status', ENTRYAGGREGATOR => 'OR');
+ $txns->Limit(FIELD => 'Type', VALUE => 'Create');
+
+ while (my $txn = $txns->Next) {
+ push @items, { queue => $txn->TicketObj->QueueObj->Name,
+ id => $txn->TicketObj->id,
+ date => (split ' ', $txn->CreatedObj->ISO)[0],
+ time => (split ' ', $txn->CreatedObj->ISO)[1],
+ status => $txn->NewValue || 'new',
+ actor => $txn->CreatorObj->Name,
+ notes => ($txn->Content ne 'This transaction appears to have no content' ? substr($txn->Content, 0, 60) : $txn->BriefDescription)
+ };
+ }
+}
+
+@items = sort {
+ $a->{queue} cmp $b->{'queue'}
+ || $a->{'status'} cmp $b->{'status'}
+ || $a->{'id'} <=> $b->{'id'}
+ || $a->{'actor'} cmp $b->{'actor'}
+ || $a->{'notes'} <=> $b->{'notes'}
+} @items;
+
+</%init>
diff --git a/rt/html/Reports/Activity/ActivitySummary.html b/rt/html/Reports/Activity/ActivitySummary.html
new file mode 100644
index 000000000..7bb756fbc
--- /dev/null
+++ b/rt/html/Reports/Activity/ActivitySummary.html
@@ -0,0 +1,61 @@
+<&|Elements/Wrapper, %ARGS, title => loc("Activity summary"),
+ path => "Reports/Activity/ActivitySummary.html",
+ &>
+
+<& Elements/MiniPlot, data => \%queues &>
+
+<table style="width: 100%">
+<tr class="titlerow">
+<th>Queue</th>
+% for my $status (sort keys %status) {
+<th><% $status %></th>
+% }
+<th>Total</th>
+</tr>
+% for my $queue (sort keys %queues) {
+<th class="label"><% $queue %></th>
+% for my $status (sort keys %status) {
+<td><% $queues{$queue}{$status} || 0 %>
+% }
+<td><% $total{$queue} %></td>
+</tr>
+% }
+<tr class="grandtotal">
+<th class="label" >Grand Total</th>
+% for my $status (sort keys %status) {
+<td><% $status{$status} %></td>
+% }
+<td><% $total %></td>
+</table>
+</&>
+<%args>
+$query => 'id > 0'
+$start => "2005/01/01"
+$end => "2006/01/01"
+</%args>
+<%init>
+
+my $tickets = RT::Tickets->new($session{'CurrentUser'});
+$tickets->FromSQL($query . " AND ( Updated >= '$start' AND Updated <= '$end')");
+
+my %queues;
+my %status;
+my %total;
+my $total;
+while (my $ticket = $tickets->Next) {
+ my $txns = $ticket->Transactions;
+ $txns->Limit(FIELD => 'Created', OPERATOR => '>=', VALUE => $start);
+ $txns->Limit(FIELD => 'Created', OPERATOR => '<=', VALUE => $end);
+ $txns->Limit(FIELD => 'Type', VALUE => 'Status', ENTRYAGGREGATOR => 'OR');
+ $txns->Limit(FIELD => 'Type', VALUE => 'Create');
+
+ while (my $txn = $txns->Next) {
+ $queues{$txn->TicketObj->QueueObj->Name}{$txn->NewValue || 'new'}++;
+ $status{$txn->NewValue || 'new'}++;
+ $total{$txn->TicketObj->QueueObj->Name}++;
+ $total++;
+ }
+}
+
+
+</%init>
diff --git a/rt/html/Reports/Activity/Elements/LimitReport b/rt/html/Reports/Activity/Elements/LimitReport
new file mode 100644
index 000000000..7c4aac73b
--- /dev/null
+++ b/rt/html/Reports/Activity/Elements/LimitReport
@@ -0,0 +1,23 @@
+<form action="index.html" method="POST" enctype="multipart/form-data">
+Query:
+<textarea name="query" rows="5" cols="80"><% $query %></textarea><br />
+
+Report type: <select name="type">
+<option value="ActivityDetail" <% $ARGS{path} =~ /ActivityDetail/ ? 'selected' : '' %>>Activity detail</option>
+<option value="ActivitySummary" <% $ARGS{path} =~ /ActivitySummary/ ? 'selected' : '' %>>Activity summary</option>
+<option value="ResolutionComments" <% $ARGS{path} =~ /ResolutionComments/ ? 'selected' : '' %>>Resolution comments</option>
+<option value="ResolutionStatistics" <% $ARGS{path} =~ /ResolutionStatistics/ ? 'selected' : '' %>>Resolution statistics</option>
+</select><br />
+
+Start date: <input type="text" name="start" value="<% $start %>" /><br />
+End date: <input type="text" name="end" value="<% $end %>" /><br />
+<& /Elements/Submit, Label => loc('Report') &>
+</form>
+<%args>
+$type => undef
+$start => undef
+$end => undef
+$query => undef
+</%args>
+<%init>
+</%init>
diff --git a/rt/html/Reports/Activity/Elements/MiniPlot b/rt/html/Reports/Activity/Elements/MiniPlot
new file mode 100644
index 000000000..f92032818
--- /dev/null
+++ b/rt/html/Reports/Activity/Elements/MiniPlot
@@ -0,0 +1,57 @@
+<table class="miniplot"><tr>
+% for my $major (@major) {
+<td><div class="graph">
+ <ul>
+% my $i = 0;
+% for my $minor (@minor) {
+% my $percent = int( 100 * ($data->{$major}{$minor} || 0) / $max );
+ <li class="c<% ($i % 6) + 1%>" style="width: <% $barwidth %>%;
+ left: <% $baroffset + $each * $i %>%;
+ height: <% $percent %>%;"><div class="data"><% $minor %>: <% $percent %>%</div></li>
+% $i++;
+% }
+ </ul>
+</div></td>
+% }
+</tr><tr>
+% for my $major (@major) {
+<th class="legend"><% $major %></th>
+% }
+</tr>
+</table>
+
+<table class="miniplot"><tr>
+% my $i = 0;
+% for my $minor (@minor) {
+<th><span class="demoblock c<% ($i++ % 6) + 1 %>"></span> <% $minor %></th>
+% }
+</tr>
+</table>
+
+<%args>
+$data
+$major => undef
+$minor => undef
+</%args>
+<%init>
+
+my $max = 1;
+
+my %minor;
+for my $major (keys %{$data}) {
+ for (keys %{$data->{$major}}) {
+ $minor{$_}++;
+ $max = $data->{$major}{$_} if $data->{$major}{$_} > $max;
+ }
+}
+
+my @major = $major ? @{$major} : sort keys %{$data};
+my @minor = $minor ? @{$minor} : sort keys %minor;
+
+return unless @minor and @major;
+
+my $each = int( (100 / @minor) );
+my $barwidth = int( (100 / @minor) * (3/4) );
+my $baroffset = int( (100 / @minor) * (1/8) );
+
+</%init>
diff --git a/rt/html/Reports/Activity/Elements/PrintFooter b/rt/html/Reports/Activity/Elements/PrintFooter
new file mode 100644
index 000000000..fa9f47582
--- /dev/null
+++ b/rt/html/Reports/Activity/Elements/PrintFooter
@@ -0,0 +1,7 @@
+<hr/>
+<div style="text-align: center;">
+<%$RT::ReportFooterMessage || 'Proprietary and Confidential' %>
+</div>
+</body>
+</html>
+%$m->abort();
diff --git a/rt/html/Reports/Activity/Elements/PrintHeader b/rt/html/Reports/Activity/Elements/PrintHeader
new file mode 100644
index 000000000..b7c4b3419
--- /dev/null
+++ b/rt/html/Reports/Activity/Elements/PrintHeader
@@ -0,0 +1,32 @@
+<%args>
+$title => undef
+$path => undef
+$query => undef
+</%args>
+<HTML>
+<HEAD>
+<TITLE><%$title%></TITLE>
+<link rel="shortcut icon" href="<%$RT::WebImagesURL%>/favicon.png" type="image/png" />
+<link media="all" rel="stylesheet" href="<%$RT::WebPath%>/NoAuth/webrt.css" type="text/css" />
+<link media="print" rel="stylesheet" href="<%$RT::WebPath%>/NoAuth/printrt.css" type="text/css" />
+%# XXX TODO THIS SHOULD NOT BE A TABLE
+<body>
+<table width="100%">
+<tr>
+<td align="left">
+<div id="username">User: <%$session{'CurrentUser'}->Name%></div>
+<div id="reportdate">
+%my $d= RT::Date->new($session{'CurrentUser'}); $d->SetToNow;
+<%$d->AsString%></div>
+</td>
+<td align="center">
+<h1><%$title%></h1>
+</td>
+<td align="right">
+<img src="<%$RT::LogoURL%>" alt="RT Logo"/>
+</td>
+</tr>
+</table>
+<hr/>
+<&|/l&>Report criteria:</&> <%$query%>
+<hr />
diff --git a/rt/html/Reports/Activity/Elements/ScreenFooter b/rt/html/Reports/Activity/Elements/ScreenFooter
new file mode 100644
index 000000000..235b7b306
--- /dev/null
+++ b/rt/html/Reports/Activity/Elements/ScreenFooter
@@ -0,0 +1,13 @@
+<& LimitReport, %ARGS &>
+% if ($show_print_link) {
+<div align="right">
+% my %printable_args = %ARGS;
+% delete $printable_args{$_} for (qw/path title mode/);
+% $printable_args{'mode'} = 'print';
+% my $url = $ARGS{'path'} .'?'. join(';', map { $_."=".$printable_args{$_} } keys %printable_args);
+<a href="<%$RT::WebPath|n%>/<%$url|n%>"><&|/l&>Printable version</&></a>
+</div>
+% }
+<%args>
+$show_print_link => 1
+</%args>
diff --git a/rt/html/Reports/Activity/Elements/ScreenHeader b/rt/html/Reports/Activity/Elements/ScreenHeader
new file mode 100644
index 000000000..080efc0dd
--- /dev/null
+++ b/rt/html/Reports/Activity/Elements/ScreenHeader
@@ -0,0 +1,8 @@
+<%args>
+$title => undef
+$path => undef
+</%args>
+<& /Elements/Header, Title => $title &>
+<& Tabs,
+ current_subtab => $path,
+ Title => $title &>
diff --git a/rt/html/Reports/Activity/Elements/Tabs b/rt/html/Reports/Activity/Elements/Tabs
new file mode 100644
index 000000000..a9498209e
--- /dev/null
+++ b/rt/html/Reports/Activity/Elements/Tabs
@@ -0,0 +1,52 @@
+<& /Elements/Tabs,
+ tabs => $tabs,
+ subtabs => $subtabs,
+ current_toptab => 'Tools/Offline.html',
+ current_tab => 'Reports/Activity/index.html'.$args,
+ Title => $Title &>
+
+<%INIT>
+my $subtabs = {};
+
+my $top = $m->caller_args(-1);
+my $args = "?" . $m->comp( '/Elements/QueryString',
+ query => $top->{query},
+ start => $top->{start},
+ end => $top->{end});
+if ($m->caller_args(-1)->{'query'}) {
+ $current_subtab .= $args;
+ $subtabs = {
+ a => { title => 'Activity detail',
+ path => 'Reports/Activity/ActivityDetail.html'.$args,
+ },
+ b => { title => 'Activity summary',
+ path => 'Reports/Activity/ActivitySummary.html'.$args,
+ },
+ c => { title => 'Resolution comments',
+ path => 'Reports/Activity/ResolutionComments.html'.$args,
+ },
+ d => { title => 'Resolution statistics',
+ path => 'Reports/Activity/ResolutionStatistics.html'.$args,
+ },
+ };
+}
+
+my $tabs = {
+ a => { title => loc('Offline'),
+ path => 'Tools/Offline.html',
+ },
+ r => { title => loc('Reports'),
+ path => 'Reports/Activity/index.html'.$args,
+ subtabs => $subtabs,
+ current_subtab => $current_subtab,
+ }
+ };
+
+</%INIT>
+
+
+<%ARGS>
+$current_tab => undef
+$current_subtab => undef
+$Title => undef
+</%ARGS>
diff --git a/rt/html/Reports/Activity/Elements/Wrapper b/rt/html/Reports/Activity/Elements/Wrapper
new file mode 100644
index 000000000..6f81f5f50
--- /dev/null
+++ b/rt/html/Reports/Activity/Elements/Wrapper
@@ -0,0 +1,16 @@
+<%args>
+$mode => 'screen'
+</%args>
+
+% if ($mode eq 'print') {
+<& PrintHeader, %ARGS &>
+%} else {
+<& ScreenHeader, %ARGS &>
+% }
+<%$m->content |n%>
+% if ($mode eq 'print') {
+<& PrintFooter, %ARGS &>
+%} else {
+<& ScreenFooter, %ARGS &>
+% }
+
diff --git a/rt/html/Reports/Activity/ResolutionComments.html b/rt/html/Reports/Activity/ResolutionComments.html
new file mode 100644
index 000000000..81ca301cc
--- /dev/null
+++ b/rt/html/Reports/Activity/ResolutionComments.html
@@ -0,0 +1,62 @@
+<&|Elements/Wrapper, %ARGS, title => loc("Resolution Comments"),
+ path => "Reports/Activity/ResolutionComments.html",
+ &>
+
+<table style="width: 100%">
+<tr>
+<th>Queue</th><th>Ticket #</th><th>Created</th><th>Resolved</th><th>Time to resolve</th>
+</tr>
+<tr>
+<th colspan="5">Resolution comments</th>
+</tr>
+% for my $item (@items) {
+<tr class="titlerow">
+<td><% $item->{queue} %></td>
+<td><% $item->{id} %></td>
+<td><% $item->{created} %></td>
+<td><% $item->{resolved} %></td>
+<td><% $item->{duration} %></td>
+</tr>
+<tr>
+<td colspan="5"><% $item->{whiteboard} %></td>
+</tr>
+% }
+</table>
+</&>
+
+<%args>
+$query => 'id > 0'
+$start => "2005/01/01"
+$end => "2006/01/01"
+</%args>
+<%init>
+
+use Time::Duration;
+
+my $summary_tickets = RT::Tickets->new( $session{'CurrentUser'} );
+$summary_tickets->FromSQL(
+ $query . " AND (Status = 'resolved') AND ( Updated >= '$start' AND Updated <= '$end')" );
+
+my @items;
+while ( my $ticket = $summary_tickets->Next ) {
+ push @items, {
+ queue => $ticket->QueueObj->Name,
+ id => $ticket->id,
+ created => $ticket->CreatedObj->AsString,
+ resolved => $ticket->ResolvedObj->AsString,
+ duration => Time::Duration::concise(
+ Time::Duration::duration(
+ $ticket->ResolvedObj->Unix - $ticket->CreatedObj->Unix
+ )
+ ),
+ whiteboard => $ticket->FirstCustomFieldValue('Whiteboard')
+ };
+}
+
+@items = sort { $a->{queue} cmp $b->{queue} || $a->{id} <=> $b->{id} } @items;
+
+
+
+
+
+</%init>
diff --git a/rt/html/Reports/Activity/ResolutionStatistics.html b/rt/html/Reports/Activity/ResolutionStatistics.html
new file mode 100644
index 000000000..4ecde2c82
--- /dev/null
+++ b/rt/html/Reports/Activity/ResolutionStatistics.html
@@ -0,0 +1,95 @@
+<&|Elements/Wrapper, %ARGS, title => loc("Resolution statistics"),
+ path => "Reports/Activity/ResolutionStatistics.html",
+ &>
+
+<& Elements/MiniPlot,
+ data => \%plot,
+ major => ['Date range','Last 30 days','Last 60 days','Last 90 days','Ever'],
+ minor => [(sort keys %queues), "Average"]
+ &>
+
+<table style="width: 100%">
+<tr>
+<td></td><th colspan="4">Number of tickets closed / Average resolution time per ticket</th>
+</tr>
+<tr class="titlerow">
+<th>Queue</th>
+<th>Date range</th>
+<th>Last 30 days</th>
+<th>Last 60 days</th>
+<th>Last 90 days</th>
+<th>Ever</th>
+</tr>
+% for my $queue (sort keys %queues) {
+<tr>
+<th><% $queue %></th>
+% for my $period ('Date range','Last 30 days','Last 60 days','Last 90 days','Ever') {
+<td><% scalar @{$closed{$period}{$queue}} %> / <% $average_resolve_times{$period}{$queue} %></td>
+% }
+</tr>
+% }
+<tr class="grandtotal">
+<th>Ticket average</th>
+% for my $period ('Date range','Last 30 days','Last 60 days','Last 90 days','Ever') {
+<td><% $average_resolve_times{$period}{_all_count} %> / <% $average_resolve_times{$period}{_all} %></td>
+% }
+</tr>
+</table>
+
+</&>
+<%args>
+$query => 'id > 0'
+$start => "2005/01/01"
+$end => "2006/01/01"
+</%args>
+<%init>
+
+my $in_30_days = RT::Date->new($session{'CurrentUser'});
+$in_30_days->Set(Format => 'Unix', Value => ( time - (86400*30)));
+my $in_60_days = RT::Date->new($session{'CurrentUser'});
+$in_60_days->Set(Format => 'Unix', Value => ( time - (86400*60)));
+my $in_90_days = RT::Date->new($session{'CurrentUser'});
+$in_90_days->Set(Format => 'Unix', Value => ( time - (86400*90)));
+
+my %queries;
+$queries{'Date range'} = "(Resolved >= '$start' AND Resolved <= '$end')";
+$queries{'Last 30 days'} = "(Resolved >= '".$in_30_days->ISO."')";
+$queries{'Last 60 days'} = "(Resolved >= '".$in_60_days->ISO."')";
+$queries{'Last 90 days'} = "(Resolved >= '".$in_90_days->ISO."')";
+$queries{'Ever'} = "(Status = 'resolved' OR Status = 'rejected')";
+
+
+my %closed;
+my %queues;
+foreach my $period (keys %queries) {
+ my $tix = RT::Tickets->new($session{'CurrentUser'});
+ $tix->FromSQL($query . " AND " .$queries{$period});
+
+ while (my $ticket = $tix->Next) {
+ push @{ $closed{$period}{$ticket->QueueObj->Name}}, $ticket;
+ $queues{$ticket->QueueObj->Name}++;
+ }
+}
+
+my %restimes;
+my %average_resolve_times;
+my %plot;
+use Time::Duration;
+foreach my $period ( keys %closed ) {
+ foreach my $queue ( keys %{$closed{$period}} ) {
+ foreach my $ticket (@{$closed{$period}{$queue}} ) {
+ push @{$restimes{$period}{$queue}}, ( $ticket->ResolvedObj->Unix - $ticket->CreatedObj->Unix);
+ }
+
+ my $total_time = 0;
+ $total_time+= $_ for @{$restimes{$period}{$queue}};
+ $average_resolve_times{$period}{'_all_time'} += $total_time;
+ $average_resolve_times{$period}{'_all_count'} += @{$restimes{$period}{$queue}};
+ $plot{$period}{$queue} = $total_time / @{$restimes{$period}{$queue}};
+ $average_resolve_times{$period}{$queue} = Time::Duration::concise(Time::Duration::duration($plot{$period}{$queue}));
+ }
+ $plot{$period}{Average} = $average_resolve_times{$period}{'_all_time'} / $average_resolve_times{$period}{'_all_count'};
+ $average_resolve_times{$period}{'_all'} = Time::Duration::concise(Time::Duration::duration($plot{$period}{Average}));
+}
+
+</%init>
diff --git a/rt/html/Reports/Activity/index.html b/rt/html/Reports/Activity/index.html
new file mode 100644
index 000000000..1f6ddb0d5
--- /dev/null
+++ b/rt/html/Reports/Activity/index.html
@@ -0,0 +1,29 @@
+<&| Elements/Wrapper, %ARGS, title => loc("Activity reports"), show_print_link => 0 &>
+
+
+</&>
+
+<%args>
+$type => undef
+$start => undef
+$end => undef
+$query => "Status = 'resolved'"
+</%args>
+<%init>
+
+unless ($start) {
+ my $then = RT::Date->new($session{'CurrentUser'});
+ $then->Set(Format => 'Unix', Value => time - (86400*7));
+ $ARGS{start} = substr($then->ISO,0,10);
+}
+
+unless ($end) {
+ my $now = RT::Date->new($session{'CurrentUser'});
+ $now->SetToNow();
+ $ARGS{end} = substr($now->ISO,0,10);
+}
+
+if ($type) {
+ $m->redirect($type . ".html?" . $m->comp('/Elements/QueryString', query => $query, start => $start, end => $end));
+}
+</%init>
diff --git a/rt/html/Search/Elements/PickRestriction b/rt/html/Search/Elements/PickRestriction
deleted file mode 100644
index ff9b86ba5..000000000
--- a/rt/html/Search/Elements/PickRestriction
+++ /dev/null
@@ -1,142 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<FORM ACTION="<%$RT::WebPath%>/Search/Listing.html" METHOD="GET">
-<INPUT TYPE=HIDDEN NAME="Bookmark" VALUE="<% $session{'tickets'}->FreezeLimits()%>">
-<& /Elements/TitleBoxStart, title => loc('Refine search')&>
-<INPUT TYPE=HIDDEN NAME="CompileRestriction" VALUE=1>
-
-<ul>
-<li><&|/l&>Owner is</&> <& /Elements/SelectBoolean, Name => "OwnerOp",
- TrueVal=> '=',
- FalseVal => '!='
-&>
-<& /Elements/SelectOwner, Name => "ValueOfOwner" &>
-
-<li>
-<& /Elements/SelectWatcherType, Name => "WatcherRole", AllowNull => 0 &>
-<&|/l&>email address</&>
-<& /Elements/SelectMatch, Name => "WatcherRoleOp" &>
-<INPUT Name="ValueOfWatcherRole" SIZE=20>
-
-<li>
-<&|/l&>Subject</&> <& /Elements/SelectMatch, Name => "SubjectOp" &>
-<INPUT Name="ValueOfSubject" SIZE=20>
-
-<li><&|/l&>Queue</&> <& /Elements/SelectBoolean, Name => "QueueOp" ,
- True => loc("is"),
- False => loc("isn't"),
- TrueVal=> '=',
- FalseVal => '!=' &>
-<& /Elements/SelectQueue, Name => "ValueOfQueue" &>
-
-
-<li><&|/l&>Priority</&> <& /Elements/SelectEqualityOperator, Name => "PriorityOp" &>
-
-<INPUT Name="ValueOfPriority" SIZE=5>
-
-<li>
-<& /Elements/SelectDateType, Name => 'DateType' &>
-<& /Elements/SelectDateRelation, Name=>"DateOp" &>
-<& /Elements/SelectDate, Name => "ValueOfDate", ShowTime => 0, Default => '' &>
-
-<li><&|/l&>Ticket attachment</&>
-
-<& /Elements/SelectAttachmentField, Name => 'AttachmentField' &>
-<& /Elements/SelectBoolean, Name => "AttachmentFieldOp",
- True => loc("matches"),
- False => loc("does not match"),
- TrueVal => 'LIKE',
- FalseVal => 'NOT LIKE'
-&>
-<Input Name="ValueOfAttachmentField" Size=20>
-
-<li><&|/l&>Status</&>
-<& /Elements/SelectBoolean, Name => "StatusOp",
- True => loc("is"),
- False => loc("isn't"),
- TrueVal=> '=',
- FalseVal => '!='
-&>
-<& /Elements/SelectStatus, Name => "ValueOfStatus", SkipDeleted => 1 &>
-
-
-% while ( my $CustomField = $CustomFields->Next ) {
-
-<li><% $CustomField->Name %>
- <& /Elements/SelectCustomFieldOperator, Name => "CustomFieldOp". $CustomField->id,
- True => loc("is"),
- False => loc("isn't"),
- TrueVal=> '=', FalseVal => '!=' &>
-
-<& /Elements/SelectCustomFieldValue, Name => "CustomField".$CustomField->id,
- CustomField => $CustomField,
- &>
-% }
-
-</UL>
-
-<& /Elements/TitleBoxEnd &>
-
-<& /Elements/TitleBoxStart, title => loc('Ordering and sorting')&>
-
-<UL>
-
-<li><&|/l&>Results per page</&> <& /Elements/SelectResultsPerPage, Name => "RowsPerPage",
- Default => $session{'tickets_rows_per_page'} || '50'
-&>
-
-<li><&|/l&>Sort results by</&> <& /Elements/SelectTicketSortBy, Name => "TicketsSortBy",
- Default => $session{'tickets_sort_by'}
-&>
-<& /Elements/SelectSortOrder, Name => 'TicketsSortOrder', Default => $session{'tickets_sort_order'} &>
-
-<li><input type="checkbox" name="HideResults" <%$ARGS{'HideResults'} && 'CHECKED'%>> <&|/l&>Don't show search results</&>
-<li><& /Elements/Refresh, Name => 'RefreshSearchInterval' , Default => $session{'tickets_refresh_interval'} &>
-
-</UL>
-
-
-</DIV>
-
-
-
-<& /Elements/TitleBoxEnd &>
-
-<& /Elements/Submit, Label => loc('Search'), Name => 'Action'&>
-
-</FORM>
-
-
- <%INIT>
-my $CustomFields = RT::CustomFields->new( $session{'CurrentUser'});
- foreach ( $session{'tickets'}->RestrictionValues('Queue') ) {
- # Gotta load up the $queue object, since queues get stored by name now.
- my $queue = RT::Queue->new($session{'CurrentUser'});
- $queue->Load($_);
- $CustomFields->LimitToQueue($queue->Id);
- }
-
- $CustomFields->LimitToGlobal();
-
-</%INIT>
diff --git a/rt/html/Search/Elements/TicketHeader b/rt/html/Search/Elements/TicketHeader
deleted file mode 100644
index ed2f60e4e..000000000
--- a/rt/html/Search/Elements/TicketHeader
+++ /dev/null
@@ -1,40 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<TR>
-<& TicketHeaderCell , Attribute => 'id', Header => '#'&>
-<& TicketHeaderCell , Attribute => 'Subject'&>
-<& TicketHeaderCell , Attribute => 'Status'&>
-<& TicketHeaderCell , Attribute => 'Queue'&>
-<& TicketHeaderCell , Attribute => 'Owner'&>
-<& TicketHeaderCell , Attribute => 'Priority'&>
-</TR>
-<TR>
-<TH class="ticketheader">&nbsp;</TH>
-<& TicketHeaderCell , Attribute => 'Requestor(s)'&>
-<& TicketHeaderCell , Attribute => 'Created'&>
-<& TicketHeaderCell , Attribute => 'Told', Header => 'Last Contact'&>
-<& TicketHeaderCell , Attribute => 'LastUpdated', Header => 'Last Updated'&>
-<& TicketHeaderCell , Attribute => 'TimeLeft', Header => 'Left'&>
-</TR>
-%# loc('Last Notified');
diff --git a/rt/html/Search/Elements/TicketHeaderCell b/rt/html/Search/Elements/TicketHeaderCell
deleted file mode 100644
index 5def9ea37..000000000
--- a/rt/html/Search/Elements/TicketHeaderCell
+++ /dev/null
@@ -1,55 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<%INIT>
-my ($order,$curorder);
- $Attribute =~ s/Obj->(Name|AsString|AgeAsString)//g;
- if ($session{'tickets_sort_order'} =~ /^asc$/i) {
- $order = 'DESC';
- $curorder = 'ASC';
- } else {
- $order = 'ASC';
- $curorder = 'DESC';
- }
-$Header = $Attribute unless ($Header);
-
-</%INIT>
-<th class="ticketheader">
-% if (grep (/^$Attribute$/i, $session{'tickets'}->SortFields)) {
-<A
-% if ($Attribute eq $session{'tickets_sort_by'}) {
-class="currenttab"
-HREF="<% $RT::WebPath%>/Search/Listing.html?Bookmark=<%$session{'tickets'}->FreezeLimits()|u%>&TicketsSortBy=<%$Attribute%>&TicketsSortOrder=<%$order%>&RowsPerPage=<%$session{'tickets_rows_per_page'}%>">
-% } else {
-HREF="<% $RT::WebPath%>/Search/Listing.html?Bookmark=<%$session{'tickets'}->FreezeLimits()|u%>&TicketsSortBy=<%$Attribute%>&TicketsSortOrder=<%$curorder%>&RowsPerPage=<%$session{'tickets_rows_per_page'}%>">
-% }
-<% loc($Header) %>
-</A>
-% } else {
-<% loc($Header) %>
-% }
-</th>
-<%ARGS>
-$Header => undef
-$Attribute => undef
-</%ARGS>
diff --git a/rt/html/Search/Elements/TicketRow b/rt/html/Search/Elements/TicketRow
deleted file mode 100644
index 5d1ad209a..000000000
--- a/rt/html/Search/Elements/TicketRow
+++ /dev/null
@@ -1,55 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<SPAN class="search">
-<TR
-% if ($i%2) {
-CLASS="oddline"
-% } else {
-CLASS="evenline"
-% }
->
-<TD ROWSPAN="2"><B><A HREF="<%$RT::WebPath%>/Ticket/Display.html?id=<%$Ticket->Id%>"><%$Ticket->id%></a></B></TD>
-<TD><B><A HREF="<%$RT::WebPath%>/Ticket/Display.html?id=<%$Ticket->Id%>"><%$Ticket->Subject%></a></B></TD>
-<TD><%loc($Ticket->Status)%></TD>
-<TD><%$Ticket->QueueObj->Name%></TD>
-<TD><%$Ticket->Owner == $RT::Nobody->Id ? loc('Nobody') : $Ticket->OwnerObj->Name%></TD>
-<TD><%$Ticket->Priority%></TD>
-</TR>
-<TR
-% if ($i%2) {
-CLASS="oddline"
-% } else {
-CLASS="evenline"
-% }
-><TD><small><%$Ticket->Requestors->MemberEmailAddressesAsString%></small></TD>
-<TD><SMALL><%$Ticket->CreatedObj->AgeAsString || '-'%></SMALL></TD>
-<TD><SMALL><%$Ticket->ToldObj->AgeAsString || '-'%></SMALL></TD>
-<TD><SMALL><%$Ticket->LastUpdatedObj->AgeAsString || '-'%></SMALL></TD>
-<TD><SMALL><%$Ticket->TimeLeft%></SMALL></TD>
-</TR>
-</SPAN>
-<%ARGS>
-$Ticket => undef
-$i => undef
-</%ARGS>
diff --git a/rt/html/Search/Listing.html b/rt/html/Search/Listing.html
deleted file mode 100644
index 68b1fd75c..000000000
--- a/rt/html/Search/Listing.html
+++ /dev/null
@@ -1,113 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<& /Elements/Header, Title => $title, Refresh => $session{'tickets_refresh_interval'} &>
-<& /Ticket/Elements/Tabs,
- current_tab => 'Search/Listing.html',
- Title => $title &>
-
-%if ($ticketcount && ! $ARGS{'HideResults'}) {
-<TABLE WIDTH=100% border=0 cellpadding=2 CELLSPACING=0>
-<& Elements/TicketHeader, %ARGS &>
-% my $i;
-%while (my $Ticket = $session{'tickets'}->Next) {
-% $i++;
-<& Elements/TicketRow, Ticket => $Ticket, i=> $i, %ARGS &>
-%}
-</TABLE>
-<div align=center>
-<font size=2>
-<a href="<%$RT::WebPath%>/Search/Listing.html?GotoPage=1"><&|/l&>First page</&></a>
-&nbsp;&nbsp;
-% if ( $session{'tickets'}->FirstRow >= $session{'tickets_rows_per_page'}-1 ) {
-<a href="<%$RT::WebPath%>/Search/Listing.html?GotoPage=Prev">&lt;<&|/l&>Previous page</&></a>
-&nbsp;&nbsp;
-% }
-% if ( $session{'tickets'}->FirstRow + $session{'tickets_rows_per_page'} < $ticketcount ) {
-<a href="<%$RT::WebPath%>/Search/Listing.html?GotoPage=Next"><&|/l&>Next page</&>&gt;</a>
-% }
-%#&nbsp;&nbsp;<form method=get action="<%$RT::WebPath%>/Search/Listing.html"><&|/l&>Goto page</&> <input name=GotoPage size=2></form>
-</font>
-</div>
-<!--<div align=right>-->
-<table width="100%" border=0 cellpadding=3 CELLSPACING=1>
-<tr>
-<td align=left>
-(<&|/l, ($session{'tickets'}->FirstRow+1), ($session{'tickets'}->FirstRow() + $session{'tickets'}->RowsPerPage() ) &>[_1] - [_2] shown</&>)
-</td>
-<td align=right>
-
-<a href="<%$RT::WebPath%>/Search/Bulk.html"><&|/l&>Update all these tickets at once</&></a>
-<!--</div>-->
-</td>
-</tr>
-</table>
-
-% }
-<TABLE WIDTH="100%">
-<TR>
-<TD VALIGN="TOP">
-<& /Elements/TitleBoxStart, title => loc('Current search criteria')&>
-
-%my %restrictions=$session{'tickets'}->DescribeRestrictions();
-%foreach my $row (keys %restrictions){
-<%$restrictions{"$row"}%> <A HREF="<% $RT::WebPath %>/Search/Listing.html?DeleteRestriction=<%$row%>">[<&|/l&>delete</&>]</a><br>
-%}
-<BR>
-<BR>
-<A HREF="<% $RT::WebPath%>/Search/Listing.html?Bookmark=<%$session{'tickets'}->FreezeLimits()|nu%>&TicketsSortBy=<%$session{'tickets_sort_by'}%>&TicketsSortOrder=<%$session{'tickets_sort_order'}%>&RowsPerPage=<%$session{'tickets_rows_per_page'}%>"><&|/l&>Bookmarkable URL for this search</&></a>
-<& /Elements/TitleBoxEnd&>
-</TD>
-<TD>
-
-<& Elements/PickRestriction, %ARGS &>
-
-</TD>
-</TR>
-</TABLE>
-
-<%INIT>
-
-my ($title, $ticketcount);
-$session{'i'}++;
-if ($session{'tickets'}) {
- if ($ARGS{'DeleteRestriction'}) {
- $session{'tickets'}->DeleteRestriction($ARGS{'DeleteRestriction'});
- }
- if ( ($ARGS{'ClearRestrictions'}) || ($ARGS{'NewSearch'}) ) {
- $session{'tickets'}->ClearRestrictions;
- $session{'tickets'}->CleanSlate;
- }
-}
- ProcessSearchQuery(ARGS=>\%ARGS);
- $session{'tickets'}->RedoSearch();
- if ( $session{'tickets'}->DescribeRestrictions()) {
- $ticketcount = $session{tickets}->CountAll();
- $title = loc('Found [quant,_1,ticket]', $ticketcount);
- } else {
- $title = loc("Find tickets");
- }
-</%INIT>
-<%CLEANUP>
-$session{'tickets'}->PrepForSerialization();
-</%CLEANUP>
diff --git a/rt/html/Ticket/Create.html b/rt/html/Ticket/Create.html
index c35ed9122..9b38d2608 100644
--- a/rt/html/Ticket/Create.html
+++ b/rt/html/Ticket/Create.html
@@ -388,10 +388,10 @@ if ((!exists $ARGS{'AddMoreAttach'}) and ($ARGS{'id'} eq 'new')) { # new ticket?
my $actions = {
A => {
- html => q[<a href="#basics" onclick="return switchVisibility('Ticket-Create-basics','Ticket-Create-details');">] . loc('Show basics') . q[</a>],
+ html => q[<a href="#basics" onclick="return switchVisibility('Ticket-Create-basics','Ticket-Create-details');" CLASS="fsblackbutton">] . loc('Show basics') . q[</a>],
},
B => {
- html => q[<a href="#details" onclick="return switchVisibility('Ticket-Create-details','Ticket-Create-basics');">] . loc('Show details') . q[</a>],
+ html => q[<a href="#details" onclick="return switchVisibility('Ticket-Create-details','Ticket-Create-basics');" CLASS="fsblackbutton">] . loc('Show details') . q[</a>],
},
};
</%INIT>
diff --git a/rt/html/Ticket/Display.html b/rt/html/Ticket/Display.html
index 7bdd57f93..d0422c008 100644
--- a/rt/html/Ticket/Display.html
+++ b/rt/html/Ticket/Display.html
@@ -46,11 +46,11 @@
%#
%# END BPS TAGGED BLOCK }}}
<& /Elements/Header,
- Title => loc("#[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject) &>
+ Title => loc("Ticket #[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject) &>
<& /Ticket/Elements/Tabs,
Ticket => $TicketObj,
current_tab => 'Ticket/Display.html?id='.$TicketObj->id,
- Title => loc("#[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject) &>
+ Title => loc("Ticket #[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject) &>
<& /Elements/ListActions, actions => \@Actions &>
<& /Elements/Callback, _CallbackName => 'BeforeShowSummary', Ticket => $TicketObj, %ARGS &>
diff --git a/rt/html/Ticket/Elements/AddCustomers b/rt/html/Ticket/Elements/AddCustomers
new file mode 100644
index 000000000..e04c07702
--- /dev/null
+++ b/rt/html/Ticket/Elements/AddCustomers
@@ -0,0 +1,52 @@
+%# Copyright (c) 2004 Ivan Kohler <ivan-rt@420.am>
+%# Copyright (c) 2008 Freeside Internet Services, Inc.
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+<BR>
+<%$msg%><br>
+
+% if (@Customers) {
+
+<br><i>(Check box to link)<i>
+<table>
+% foreach my $customer (@Customers) {
+<tr>
+ <td>
+ <input type="checkbox" name="Ticket-AddCustomer-<% $customer->{'custnum'} %>" VALUE="1" <% scalar(@Customers) == 1 ? 'CHECKED' : '' %>>
+ <A HREF="<%$freeside_url%>/view/cust_main.cgi?<% $customer->{'custnum'} %>"><% &RT::URI::freeside::small_custview($customer->{'custnum'}, &RT::URI::freeside::FreesideGetConfig('countrydefault'), 1) |n %>
+ </td>
+</tr>
+% }
+</table>
+
+% }
+
+<%INIT>
+my ($msg);
+
+my $freeside_url = &RT::URI::freeside::FreesideURL();
+
+my @Customers = ();
+if ( $CustomerString ) {
+ @Customers = &RT::URI::freeside::smart_search( 'search' => $CustomerString );
+}
+
+my @Services = ();
+if ($ServiceString) {
+ @Services = (); #service_search();
+}
+
+</%INIT>
+
+<%ARGS>
+$CustomerString => undef
+$ServiceString => undef
+</%ARGS>
diff --git a/rt/html/Ticket/Elements/EditCustomers b/rt/html/Ticket/Elements/EditCustomers
new file mode 100644
index 000000000..0ba6e447b
--- /dev/null
+++ b/rt/html/Ticket/Elements/EditCustomers
@@ -0,0 +1,63 @@
+%# Copyright (c) 2004 Ivan Kohler <ivan-rt@420.am>
+%# Copyright (c) 2008 Freeside Internet Services, Inc.
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+<TABLE width=100%>
+ <TR>
+ <TD VALIGN=TOP WIDTH=50%>
+ <h3><&|/l&>Current Customers</&></h3>
+
+<table>
+ <tr>
+ <td><i><&|/l&>(Check box to disassociate)</&></i></td>
+ </tr>
+ <tr>
+ <td class="value">
+% foreach my $link ( @{ $Ticket->Customers->ItemsArrayRef } ) {
+
+ <INPUT TYPE=CHECKBOX NAME="DeleteLink--<%$link->Type%>-<%$link->Target%>">
+%# <& ShowLink, URI => $link->TargetURI &><br>
+ <A HREF="<% $link->TargetURI->Resolver->HREF %>"><% $link->TargetURI->Resolver->AsStringLong |n %></A>
+ <BR>
+% }
+ </td>
+ </tr>
+</table>
+
+</TD>
+
+<TD VALIGN=TOP>
+<h3><&|/l&>New Customer Links</&></h3>
+<&|/l&>Find customer</&><BR>
+<input name="CustomerString">
+<input type=submit name="OnlySearchForCustomers" value="<&|/l&>Go!</&>">
+<br><i>cust #, name, company or phone</i>
+<BR>
+%#<BR>
+%#<&|/l&>Find service</&><BR>
+%#<input name="ServiceString">
+%#<input type=submit name="OnlySearchForServices" value="<&|/l&>Go!</&>">
+%#<br><i>username, username@domain, domain, or IP address</i>
+%#<BR>
+
+<& AddCustomers, Ticket => $Ticket,
+ CustomerString => $CustomerString,
+ ServiceString => $ServiceString, &>
+
+</TD>
+</TR>
+</TABLE>
+
+<%ARGS>
+$CustomerString => undef
+$ServiceString => undef
+$Ticket => undef
+</%ARGS>
diff --git a/rt/html/Ticket/Elements/EditLinks b/rt/html/Ticket/Elements/EditLinks
deleted file mode 100644
index bdb8a6b7d..000000000
--- a/rt/html/Ticket/Elements/EditLinks
+++ /dev/null
@@ -1,133 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<TABLE width=100%>
- <TR>
- <TD VALIGN=TOP WIDTH=50%>
- <h3><&|/l&>Current Relationships</&></h3>
-
-<table>
- <tr>
- <td></td>
- <td><i><&|/l&>(Check box to delete)</&></i></td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Depends on</&>:</td>
- <td class="value">
-% while (my $link = $Ticket->DependsOn->Next) {
- <INPUT TYPE=CHECKBOX NAME="DeleteLink--<%$link->Type%>-<%$link->Target%>">
- <& ShowLink, URI => $link->TargetURI &><br>
-% }
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Depended on by</&>:</td>
- <td class="value">
-% while (my $link = $Ticket->DependedOnBy->Next) {
-% my $member = $link->BaseObj;
- <INPUT TYPE=CHECKBOX NAME="DeleteLink-<%$link->Base%>-<%$link->Type%>-">
- <& ShowLink, URI => $link->BaseURI &><br>
-% }
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Parents</&>:</td>
- <td class="value">
-% while (my $link = $Ticket->MemberOf->Next) {
- <INPUT TYPE=CHECKBOX NAME="DeleteLink--<%$link->Type%>-<%$link->Target%>">
- <& ShowLink, URI => $link->TargetURI &><br>
-% }
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Children</&>:</td>
- <td class="value">
-% while (my $link = $Ticket->Members->Next) {
- <INPUT TYPE=CHECKBOX NAME="DeleteLink-<%$link->Base%>-<%$link->Type%>-">
- <& ShowLink, URI => $link->BaseURI &><br>
-% }
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Refers to</&>:</td>
- <td class="value">
-% while (my $link = $Ticket->RefersTo->Next) {
- <INPUT TYPE=CHECKBOX NAME="DeleteLink--<%$link->Type%>-<%$link->Target%>">
- <& ShowLink, URI => $link->TargetURI &><br>
-%}
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Referred to by</&>:</td>
- <td class="value">
-% while (my $link = $Ticket->ReferredToBy->Next) {
- <INPUT TYPE=CHECKBOX NAME="DeleteLink-<%$link->Base%>-<%$link->Type%>-">
- <& ShowLink, URI => $link->BaseURI &><br>
-% }
- </td>
- </tr>
-</table>
-
-</TD>
-<TD VALIGN=TOP>
-<h3><&|/l&>New Relationships</&></h3>
-<i><&|/l&>Enter tickets or URIs to link tickets to. Seperate multiple entries with spaces.</&></i><br>
-<TABLE>
- <TR>
- <TD class="label"><&|/l&>Merge into</&>:</TD>
- <TD class="entry"><input name="<%$Ticket->Id%>-MergeInto"> <i><&|/l&>(only one ticket)</&></i></TD>
- </TR>
- <TR>
- <TD class="label"><&|/l&>Depends on</&>:</TD>
- <TD class="entry"><input name="<%$Ticket->Id%>-DependsOn"></TD>
- </TR>
- <TR>
- <TD class="label"><&|/l&>Depended on by</&>:</TD>
- <TD class="entry"><input name="DependsOn-<%$Ticket->Id%>"></TD>
- </TR>
- <TR>
- <TD class="label"><&|/l&>Parents</&>:</TD>
- <TD class="entry"><input name="<%$Ticket->Id%>-MemberOf"></TD>
- </TR>
- <TR>
- <TD class="label"><&|/l&>Children</&>:</TD>
- <TD class="entry"> <input name="MemberOf-<%$Ticket->Id%>"></TD>
- </TR>
- <TR>
- <TD class="label"><&|/l&>Refers to</&>:</TD>
- <TD class="entry"><input name="<%$Ticket->Id%>-RefersTo"></TD>
- </TR>
- <TR>
- <TD class="label"><&|/l&>Referred to by</&>:</TD>
- <TD class="entry"> <input name="RefersTo-<%$Ticket->Id%>"></TD>
- </TR>
-</TABLE>
-</TD>
-</TR>
-</TABLE>
-
-
-
-<%ARGS>
-$Ticket => undef
-</%ARGS>
diff --git a/rt/html/Ticket/Elements/ShowCustomers b/rt/html/Ticket/Elements/ShowCustomers
new file mode 100644
index 000000000..3acf92dd4
--- /dev/null
+++ b/rt/html/Ticket/Elements/ShowCustomers
@@ -0,0 +1,38 @@
+%# Copyright (c) 2004 Ivan Kohler <ivan-rt@420.am>
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+<table>
+% my $cust = 0;
+% foreach my $custResolver ( map { $_->TargetURI->Resolver }
+% @{ $Ticket->Customers->ItemsArrayRef }
+% )
+% {
+% $cust++;
+% my $cust_main = '';
+ <tr>
+ <td class="value">
+ <A HREF="<% $custResolver->HREF %>"><% $custResolver->AsStringLong |n %></A>
+ </td>
+ </tr>
+% }
+% unless ( $cust ) {
+ <tr>
+ <td class="labeltop">
+ <i>(none)<i>
+ </td>
+ </tr>
+
+% }
+</table>
+<%ARGS>
+$Ticket => undef
+</%ARGS>
+
diff --git a/rt/html/Ticket/Elements/ShowLink b/rt/html/Ticket/Elements/ShowLink
deleted file mode 100644
index 493fd95a5..000000000
--- a/rt/html/Ticket/Elements/ShowLink
+++ /dev/null
@@ -1,40 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<A href="<%$URI->Resolver->HREF%>">
-% if ($URI->IsLocal) {
-% my $member = $URI->Object;
-% if (UNIVERSAL::isa($member, "RT::Ticket")) {
-<%$member->Id%>: (<%$member->OwnerObj->Name%>) <%$member->Subject%> [<% loc($member->Status) %>]
-% } elsif ( UNIVERSAL::can($member, 'Name')) {
-<%$URI->Resolver->AsString%>: <%$member->Name%>
-% } else {
-<%$URI->Resolver->AsString%>
-% }
-% } else {
-<%$URI->Resolver->AsString%>
-% }
-</a>
-<%ARGS>
-$URI => undef
-</%ARGS>
diff --git a/rt/html/Ticket/Elements/ShowLinks b/rt/html/Ticket/Elements/ShowLinks
deleted file mode 100644
index f88a6008d..000000000
--- a/rt/html/Ticket/Elements/ShowLinks
+++ /dev/null
@@ -1,87 +0,0 @@
-%# BEGIN LICENSE BLOCK
-%#
-%# Copyright (c) 1996-2003 Jesse Vincent <jesse@bestpractical.com>
-%#
-%# (Except where explictly superceded by other copyright notices)
-%#
-%# This work is made available to you under the terms of Version 2 of
-%# the GNU General Public License. A copy of that license should have
-%# been provided with this software, but in any event can be snarfed
-%# from www.gnu.org.
-%#
-%# This work is distributed in the hope that it will be useful, but
-%# WITHOUT ANY WARRANTY; without even the implied warranty of
-%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-%# General Public License for more details.
-%#
-%# Unless otherwise specified, all modifications, corrections or
-%# extensions to this work which alter its source code become the
-%# property of Best Practical Solutions, LLC when submitted for
-%# inclusion in the work.
-%#
-%#
-%# END LICENSE BLOCK
-<table>
- <tr>
- <td class="labeltop"><&|/l&>Depends on</&>:</td>
- <td class="value">
-<ul>
-% while (my $Link = $Ticket->DependsOn->Next) {
-<li><& ShowLink, URI => $Link->TargetURI &>
-% }
-</ul>
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Depended on by</&>:</td>
- <td class="value">
-<ul>
-% while (my $Link = $Ticket->DependedOnBy->Next) {
-<li><& ShowLink, URI => $Link->BaseURI &>
-% }
-</ul>
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Parents</&>:</td>
- <td class="value">
-<ul>
-% while (my $Link = $Ticket->MemberOf->Next) {
-<li><& ShowLink, URI => $Link->TargetURI &>
-% }
-</ul>
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Children</&>:</td>
- <td class="value"><& /Ticket/Elements/ShowMembers, Ticket => $Ticket &></td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Refers to</&>:</td>
- <td class="value">
-<ul>
-% while (my $Link = $Ticket->RefersTo->Next) {
-<li><& ShowLink, URI => $Link->TargetURI &>
-% }
-</ul>
- </td>
- </tr>
- <tr>
- <td class="labeltop"><&|/l&>Referred to by</&>:</td>
- <td class="value">
- <ul>
-% while (my $Link = $Ticket->ReferredToBy->Next) {
-<li><& ShowLink, URI => $Link->BaseURI &>
-% }
-</ul>
- </td>
- </tr>
-
-% # Allow people to add more rows to the table
-% $m->comp('/Elements/Callback', %ARGS );
-
-</table>
-
-<%ARGS>
-$Ticket => undef
-</%ARGS>
diff --git a/rt/html/Ticket/Elements/ShowSummary b/rt/html/Ticket/Elements/ShowSummary
index aeec0fdfb..2f153f3bc 100644
--- a/rt/html/Ticket/Elements/ShowSummary
+++ b/rt/html/Ticket/Elements/ShowSummary
@@ -67,6 +67,12 @@
<& /Ticket/Elements/ShowPeople, Ticket => $Ticket &>
</&>
+ <&| /Widgets/TitleBox, title => loc('Customers'),
+ title_href =>"$RT::WebPath/Ticket/ModifyCustomers.html?id=".$Ticket->Id,
+ class=> 'ticket-info-customers' &>
+ <& /Ticket/Elements/ShowCustomers, Ticket => $Ticket &>
+ </&>
+
<& /Ticket/Elements/ShowAttachments, Ticket => $Ticket, Attachments => $Attachments &>
<br />
<& /Ticket/Elements/ShowRequestor, Ticket => $Ticket &>
diff --git a/rt/html/Ticket/Elements/ShowTransactionAttachments b/rt/html/Ticket/Elements/ShowTransactionAttachments
index 662b744ae..66823d743 100644
--- a/rt/html/Ticket/Elements/ShowTransactionAttachments
+++ b/rt/html/Ticket/Elements/ShowTransactionAttachments
@@ -139,8 +139,14 @@ unless ( ($message->GetHeader('Content-Disposition')||"") =~ /attachment/i ) {
# if it's a text/plain show the body
elsif ( $message->ContentType =~ m{^(text|message|text)}i ) {
- eval { require Text::Quoted; $content = Text::Quoted::extract($content); };
- if ($@) { 1; }
+ #don't want to use this even if it is installed, its
+ #segfaulting on weird characters and silently truncating the
+ #ticket history output
+ #see:
+ # r44838@pinglin: jesse | 2006-11-14 15:53:18 -0500
+ # * Move Text::Quoted back to being a run-time require. So that it's possible to turn off the feature if it causes your perl to segfault. (Text::Tabs is...not robust in the face of perl bugs)
+ #eval { require Text::Quoted; $content = Text::Quoted::extract($content); };
+ #if ($@) { 1; }
$m->comp(
'ShowMessageStanza',
diff --git a/rt/html/Ticket/Elements/Tabs b/rt/html/Ticket/Elements/Tabs
index 98ed143e9..3149e6b7c 100644
--- a/rt/html/Ticket/Elements/Tabs
+++ b/rt/html/Ticket/Elements/Tabs
@@ -121,6 +121,8 @@ my $ticket_page_tabs = {
{ title => loc('People'), path => "Ticket/ModifyPeople.html?id=" . $id, },
_E => { title => loc('Links'),
path => "Ticket/ModifyLinks.html?id=" . $id, },
+ _Eb=> { title => loc('Customers'),
+ path => "Ticket/ModifyCustomers.html?id=" . $id, },
_F => { title => loc('Reminders'),
path => "Ticket/Reminders.html?id=" . $id,
separator => 1, },
diff --git a/rt/html/Ticket/ModifyCustomers.html b/rt/html/Ticket/ModifyCustomers.html
new file mode 100644
index 000000000..72d103b23
--- /dev/null
+++ b/rt/html/Ticket/ModifyCustomers.html
@@ -0,0 +1,49 @@
+%# Copyright (c) 2004 Ivan Kohler <ivan-rt@420.am>
+%#
+%# This work is made available to you under the terms of Version 2 of
+%# the GNU General Public License. A copy of that license should have
+%# been provided with this software, but in any event can be snarfed
+%# from www.gnu.org.
+%#
+%# This work is distributed in the hope that it will be useful, but
+%# WITHOUT ANY WARRANTY; without even the implied warranty of
+%# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%# General Public License for more details.
+<& /Elements/Header, Title => loc("Customers for ticket #[_1]", $Ticket->Id) &>
+<& /Ticket/Elements/Tabs,
+ Ticket => $Ticket,
+ current_tab => "Ticket/ModifyCustomers.html?id=".$Ticket->Id,
+ Title => loc("Customers for ticket #[_1]", $Ticket->Id) &>
+
+<& /Elements/ListActions, actions => \@results &>
+
+<form action="ModifyCustomers.html" method="post">
+<input type="hidden" name="id" value="<%$Ticket->id%>">
+
+<& /Elements/TitleBoxStart, title => loc('Edit Customer Links'), color => "#7f007b"&>
+<& Elements/EditCustomers, Ticket => $Ticket, CustomerString => $CustomerString, ServiceString => $ServiceString &>
+<& /Elements/TitleBoxEnd &>
+<& /Elements/Submit, color => "#7f007b", Label => loc('Save Changes') &>
+</form>
+
+
+<%INIT>
+
+my @results = ();
+my $Ticket = LoadTicket($id);
+
+# if we're trying to search for customers/services and nothing else
+unless ( $OnlySearchForCustomers || $OnlySearchForServices) {
+ @results = ProcessTicketCustomers( TicketObj => $Ticket, ARGSRef => \%ARGS);
+}
+
+</%INIT>
+
+
+<%ARGS>
+$OnlySearchForCustomers => undef
+$OnlySearchForServices => undef
+$CustomerString => undef
+$ServiceString => undef
+$id => undef
+</%ARGS>
diff --git a/rt/html/User/Prefs.html b/rt/html/User/Prefs.html
index 54a950d7c..56d2ee05b 100644
--- a/rt/html/User/Prefs.html
+++ b/rt/html/User/Prefs.html
@@ -45,7 +45,7 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<& /Elements/Header, Title=>loc("Preferences") &>
+<& /Elements/Header, Title=>loc("Ticketing Preferences") &>
<& /User/Elements/Tabs,
current_tab => 'User/Prefs.html',
Title=>loc("Preferences") &>