summaryrefslogtreecommitdiff
path: root/rt/share
diff options
context:
space:
mode:
Diffstat (limited to 'rt/share')
-rw-r--r--rt/share/fonts/Droid.README5
-rwxr-xr-xrt/share/fonts/DroidSans.ttfbin0 -> 149076 bytes
-rwxr-xr-xrt/share/fonts/DroidSansFallback.ttfbin0 -> 3022632 bytes
-rw-r--r--rt/share/html/Admin/CustomFields/Modify.html13
-rw-r--r--rt/share/html/Admin/CustomFields/Objects.html152
-rw-r--r--rt/share/html/Admin/CustomFields/index.html58
-rwxr-xr-xrt/share/html/Admin/Elements/EditCustomFields213
-rwxr-xr-xrt/share/html/Admin/Elements/EditScrip1
-rwxr-xr-xrt/share/html/Admin/Elements/EditScrips5
-rwxr-xr-xrt/share/html/Admin/Elements/EditTemplates5
-rwxr-xr-xrt/share/html/Admin/Groups/index.html5
-rwxr-xr-xrt/share/html/Admin/Queues/Modify.html7
-rwxr-xr-xrt/share/html/Admin/Queues/index.html6
-rw-r--r--rt/share/html/Admin/Tools/Configuration.html180
-rw-r--r--rt/share/html/Admin/Users/Memberships.html4
-rwxr-xr-xrt/share/html/Admin/Users/Modify.html64
-rwxr-xr-xrt/share/html/Admin/Users/index.html6
-rw-r--r--rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Elements/Tabs/Default12
-rw-r--r--rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Modify.html/BeforeActionList15
-rw-r--r--rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Update.html/BeforeDisplay24
-rw-r--r--rt/share/html/Callbacks/RTx-Calendar/Elements/Header/Head2
-rw-r--r--rt/share/html/Callbacks/RTx-Calendar/Ticket/Elements/Tabs/Default19
-rw-r--r--rt/share/html/Callbacks/RTx-Calendar/User/Elements/Tabs/Default9
-rw-r--r--rt/share/html/Dashboards/Elements/HiddenSearches3
-rw-r--r--rt/share/html/Dashboards/Render.html7
-rw-r--r--rt/share/html/Download/CustomFieldValue/dhandler5
-rw-r--r--rt/share/html/Elements/AddCustomers59
-rw-r--r--rt/share/html/Elements/CalendarEvent129
-rw-r--r--rt/share/html/Elements/CollectionAsTable/Row3
-rw-r--r--rt/share/html/Elements/CollectionList30
-rw-r--r--rt/share/html/Elements/ColumnMap24
-rwxr-xr-xrt/share/html/Elements/CreateTicket7
-rw-r--r--rt/share/html/Elements/EditCustomFieldDate62
-rw-r--r--rt/share/html/Elements/EditCustomFieldSelect3
-rw-r--r--rt/share/html/Elements/EditCustomers63
-rwxr-xr-xrt/share/html/Elements/EditLinks24
-rw-r--r--rt/share/html/Elements/EditPassword34
-rwxr-xr-xrt/share/html/Elements/Footer19
-rwxr-xr-xrt/share/html/Elements/Header92
-rw-r--r--rt/share/html/Elements/HeaderJavascript2
-rwxr-xr-xrt/share/html/Elements/Login15
-rw-r--r--rt/share/html/Elements/Logo7
-rwxr-xr-xrt/share/html/Elements/MessageBox2
-rw-r--r--rt/share/html/Elements/MyCalendar78
-rwxr-xr-xrt/share/html/Elements/MyReminders1
-rwxr-xr-xrt/share/html/Elements/PageLayout12
-rw-r--r--rt/share/html/Elements/RT__CustomField/ColumnMap178
-rw-r--r--rt/share/html/Elements/RT__Queue/ColumnMap54
-rw-r--r--rt/share/html/Elements/RT__Scrip/ColumnMap4
-rw-r--r--rt/share/html/Elements/RT__Template/ColumnMap11
-rw-r--r--rt/share/html/Elements/RT__Ticket/ColumnMap41
-rwxr-xr-xrt/share/html/Elements/SelectDate17
-rwxr-xr-xrt/share/html/Elements/SelectQueue3
-rw-r--r--rt/share/html/Elements/ShowCustomFieldDate57
-rw-r--r--rt/share/html/Elements/ShowCustomFields11
-rw-r--r--rt/share/html/Elements/ShowLink_Checklist36
-rwxr-xr-xrt/share/html/Elements/ShowLinks22
-rw-r--r--rt/share/html/Elements/ShowRelationLabel62
-rw-r--r--rt/share/html/Elements/ShowUser24
-rw-r--r--rt/share/html/Elements/ShowUserConcise16
-rw-r--r--rt/share/html/Elements/ShowUserVerbose6
-rw-r--r--rt/share/html/Helpers/CalPopup.html12
-rw-r--r--rt/share/html/NoAuth/Calendar/dhandler159
-rwxr-xr-xrt/share/html/NoAuth/Logout.html12
-rw-r--r--rt/share/html/NoAuth/css/3.4-compat/misc.css3
-rw-r--r--rt/share/html/NoAuth/css/3.4-compat/titlebox.css4
-rwxr-xr-xrt/share/html/NoAuth/css/3.5-default/misc.css31
-rw-r--r--rt/share/html/NoAuth/css/3.5-default/titlebox.css4
-rw-r--r--rt/share/html/NoAuth/css/autohandler3
-rw-r--r--rt/share/html/NoAuth/css/base/misc.css49
-rw-r--r--rt/share/html/NoAuth/css/calendar.css75
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/InHeader54
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/admin.css60
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/base.css63
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/boxes.css192
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/collection.css52
-rwxr-xr-xrt/share/html/NoAuth/css/freeside2.1/forms.css242
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/freeside.css9
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/images/dhandler8
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/images/source/background-gradient.pngbin0 -> 394 bytes
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/layout.css237
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/login.css82
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/main.css71
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/misc.css87
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/msie.css246
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/msie6.css88
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/nav.css206
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/portlets.css71
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/ticket-lists.css172
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/ticket-search.css199
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/ticket.css230
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/tools.css56
-rw-r--r--rt/share/html/NoAuth/css/freeside2.1/yui-fonts.css7
-rw-r--r--rt/share/html/NoAuth/css/print.css11
-rw-r--r--rt/share/html/NoAuth/css/web2/base.css7
-rw-r--r--rt/share/html/NoAuth/css/web2/boxes.css8
-rw-r--r--rt/share/html/NoAuth/css/web2/collection.css52
-rw-r--r--rt/share/html/NoAuth/css/web2/main.css1
-rw-r--r--rt/share/html/NoAuth/css/web2/misc.css27
-rw-r--r--rt/share/html/NoAuth/css/web2/msie.css7
-rw-r--r--rt/share/html/NoAuth/css/web2/portlets.css6
-rw-r--r--rt/share/html/NoAuth/images/autohandler3
-rw-r--r--rt/share/html/NoAuth/images/created.pngbin0 -> 994 bytes
-rw-r--r--rt/share/html/NoAuth/images/created_due.pngbin0 -> 997 bytes
-rw-r--r--rt/share/html/NoAuth/images/due.pngbin0 -> 936 bytes
-rw-r--r--rt/share/html/NoAuth/images/reminder.pngbin0 -> 921 bytes
-rw-r--r--rt/share/html/NoAuth/images/resolved.pngbin0 -> 229 bytes
-rw-r--r--rt/share/html/NoAuth/images/started.pngbin0 -> 934 bytes
-rw-r--r--rt/share/html/NoAuth/images/starts.pngbin0 -> 935 bytes
-rw-r--r--rt/share/html/NoAuth/images/starts_due.pngbin0 -> 173 bytes
-rw-r--r--rt/share/html/NoAuth/images/updated.pngbin0 -> 191 bytes
-rw-r--r--rt/share/html/NoAuth/js/autohandler3
-rw-r--r--rt/share/html/NoAuth/rss/dhandler48
-rw-r--r--rt/share/html/Prefs/Calendar.html123
-rw-r--r--rt/share/html/Prefs/Elements/CalendarFeed68
-rw-r--r--rt/share/html/Prefs/SearchOptions.html2
-rw-r--r--rt/share/html/Search/Build.html2
-rwxr-xr-xrt/share/html/Search/Bulk.html4
-rw-r--r--rt/share/html/Search/Calendar.html238
-rw-r--r--rt/share/html/Search/Chart136
-rw-r--r--rt/share/html/Search/Elements/BuildFormatString4
-rw-r--r--rt/share/html/Search/Elements/Chart34
-rw-r--r--rt/share/html/Search/Elements/DisplayOptions2
-rw-r--r--rt/share/html/Search/Elements/PickCFs49
-rw-r--r--rt/share/html/Search/Elements/ResultsRSSView143
-rwxr-xr-xrt/share/html/Search/Results.html11
-rw-r--r--rt/share/html/Search/Results.rdf57
-rw-r--r--rt/share/html/Search/Results.tsv2
-rwxr-xr-xrt/share/html/SelfService/Error.html2
-rwxr-xr-xrt/share/html/SelfService/Prefs.html34
-rwxr-xr-xrt/share/html/Ticket/Attachment/dhandler7
-rw-r--r--rt/share/html/Ticket/Checklist.html30
-rwxr-xr-xrt/share/html/Ticket/Create.html18
-rwxr-xr-xrt/share/html/Ticket/Display.html4
-rw-r--r--rt/share/html/Ticket/Elements/AddCustomers52
-rwxr-xr-xrt/share/html/Ticket/Elements/BulkLinks2
-rw-r--r--rt/share/html/Ticket/Elements/CheckMandatoryFields9
-rwxr-xr-xrt/share/html/Ticket/Elements/EditCustomFields2
-rw-r--r--rt/share/html/Ticket/Elements/EditCustomers63
-rwxr-xr-xrt/share/html/Ticket/Elements/EditDates1
-rw-r--r--rt/share/html/Ticket/Elements/EditTransactionCustomFields2
-rwxr-xr-xrt/share/html/Ticket/Elements/PreviewScrips6
-rwxr-xr-xrt/share/html/Ticket/Elements/ShowAttachments17
-rw-r--r--rt/share/html/Ticket/Elements/ShowCustomers38
-rwxr-xr-xrt/share/html/Ticket/Elements/ShowDates1
-rw-r--r--rt/share/html/Ticket/Elements/ShowGroupMembers4
-rw-r--r--rt/share/html/Ticket/Elements/ShowMembers_Checklist29
-rwxr-xr-xrt/share/html/Ticket/Elements/ShowMessageStanza3
-rwxr-xr-xrt/share/html/Ticket/Elements/ShowPeople4
-rwxr-xr-xrt/share/html/Ticket/Elements/ShowSummary118
-rwxr-xr-xrt/share/html/Ticket/Elements/ShowTransaction2
-rw-r--r--rt/share/html/Ticket/Elements/ShowTransactionAttachments17
-rwxr-xr-xrt/share/html/Ticket/Elements/Tabs32
-rw-r--r--rt/share/html/Ticket/Elements/UpdateCc26
-rwxr-xr-xrt/share/html/Ticket/ModifyAll.html10
-rw-r--r--rt/share/html/Ticket/ModifyCustomers.html49
-rwxr-xr-xrt/share/html/Ticket/ModifyDates.html1
-rwxr-xr-xrt/share/html/Ticket/Update.html28
-rw-r--r--rt/share/html/Tools/Reports/CreatedByDates.html8
-rw-r--r--rt/share/html/Tools/Reports/ResolvedByDates.html8
-rwxr-xr-xrt/share/html/User/Elements/Tabs66
-rwxr-xr-xrt/share/html/User/Prefs.html45
-rw-r--r--rt/share/html/Widgets/Form/Select5
-rwxr-xr-xrt/share/html/Widgets/TitleBoxEnd2
-rwxr-xr-xrt/share/html/autohandler4
165 files changed, 5686 insertions, 923 deletions
diff --git a/rt/share/fonts/Droid.README b/rt/share/fonts/Droid.README
new file mode 100644
index 000000000..3a9cfcaf8
--- /dev/null
+++ b/rt/share/fonts/Droid.README
@@ -0,0 +1,5 @@
+Droid is a font family created by Ascender Corporation for use by the Open Handset Alliance platform Android and licensed under the Apache license. The fonts are intended for use on the small screens of mobile handsets and were designed by Steve Matteson of Ascender Corporation. The name was derived from the Open Handset Alliance platform name Android.
+
+Droid Sans Fallback is a font with CJK support.
+
+See Also: http://en.wikipedia.org/wiki/Droid_(font)
diff --git a/rt/share/fonts/DroidSans.ttf b/rt/share/fonts/DroidSans.ttf
new file mode 100755
index 000000000..458ba59d8
--- /dev/null
+++ b/rt/share/fonts/DroidSans.ttf
Binary files differ
diff --git a/rt/share/fonts/DroidSansFallback.ttf b/rt/share/fonts/DroidSansFallback.ttf
new file mode 100755
index 000000000..38b5b1a53
--- /dev/null
+++ b/rt/share/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/rt/share/html/Admin/CustomFields/Modify.html b/rt/share/html/Admin/CustomFields/Modify.html
index f75607a8d..d2932d2d9 100644
--- a/rt/share/html/Admin/CustomFields/Modify.html
+++ b/rt/share/html/Admin/CustomFields/Modify.html
@@ -119,6 +119,11 @@
% }
<tr><td class="label">&nbsp;</td><td>
+<input type="checkbox" class="checkbox" name="Required" value="1" <% $RequiredChecked |n%> />
+<&|/l&>Required for ticket resolution</&>
+</td></tr>
+
+<tr><td class="label">&nbsp;</td><td>
<input type="hidden" class="hidden" name="SetEnabled" value="1" />
<input type="checkbox" class="checkbox" name="Enabled" value="1" <% $EnabledChecked |n%> />
<&|/l&>Enabled (Unchecking this box disables this custom field)</&>
@@ -171,11 +176,12 @@ else {
}
if ( $ARGS{'Update'} && $id ne 'new' ) {
-
#we're asking about enabled on the web page but really care about disabled.
$ARGS{'Disabled'} = $Disabled = $Enabled? 0 : 1;
+
+ $ARGS{'Required'} ||= 0;
- my @attribs = qw(Disabled Pattern Name TypeComposite LookupType Description LinkValueTo IncludeContentForValue);
+ my @attribs = qw(Disabled Required Pattern Name TypeComposite LookupType Description LinkValueTo IncludeContentForValue);
push @results, UpdateRecordObject(
AttributesRef => \@attribs,
Object => $CustomFieldObj,
@@ -222,6 +228,9 @@ $id = $CustomFieldObj->id if $CustomFieldObj->id;
my $EnabledChecked = qq[checked="checked"];
$EnabledChecked = '' if $CustomFieldObj->Disabled;
+my $RequiredChecked = '';
+$RequiredChecked = qq[checked="checked"] if $CustomFieldObj->Required;
+
my @CFvalidations = (
'(?#Mandatory).',
'(?#Digits)^[\d.]+$',
diff --git a/rt/share/html/Admin/CustomFields/Objects.html b/rt/share/html/Admin/CustomFields/Objects.html
index 20d79b294..06e3739b2 100644
--- a/rt/share/html/Admin/CustomFields/Objects.html
+++ b/rt/share/html/Admin/CustomFields/Objects.html
@@ -56,94 +56,104 @@
<form action="Objects.html" method="post">
<input type="hidden" class="hidden" name="id" value="<% $id %>" />
-<input type="hidden" class="hidden" name="UpdateObjs" value="1" />
+
+% if ( $is_global ) {
+<h2><&|/l&>Applies to all objects</&></h2>
+<input type="checkbox" name="RemoveCustomField-<% $CF->id %>" value="0" />
+<&|/l&>check this box to remove this Custom Field from all objects and be able to choose specific objects.</&>
+% } else {
+<h2><&|/l&>Apply globally</&></h2>
+
+<input type="checkbox" name="AddCustomField-<% $CF->id %>" value="0" />
+<&|/l&>check this box to apply this Custom Field to all objects.</&>
<h2><&|/l&>Selected objects</&></h2>
-<& /Admin/Elements/PickObjects, Objects => \@AssignedObjs, id => $id, Checked => 1 &>
-<h2><&|/l&>Unselected objects</&></h2>
-<& /Admin/Elements/PickObjects, Objects => \@UnassignedObjs, id => $id &>
+<& /Elements/CollectionList,
+ OrderBy => 'id',
+ Order => 'ASC',
+ %ARGS,
+ Collection => $applied,
+ Rows => 0,
+ Page => 1,
+ Format => $format,
+ DisplayFormat => "'__CheckBox.{RemoveCustomField-". $CF->id ."}__',". $format,
+ AllowSorting => 0,
+ ShowEmpty => 0,
+ PassArguments => [
+ qw(id Format Rows Page Order OrderBy),
+ ],
+&>
-<& /Elements/Submit, CheckAll => 1, ClearAll => 1 &>
+<h2><&|/l&>Unselected objects</&></h2>
+<& /Elements/CollectionList,
+ OrderBy => 'id',
+ Order => 'ASC',
+ %ARGS,
+ Collection => $not_applied,
+ Rows => 50,
+ Format => $format,
+ DisplayFormat => "'__CheckBox.{AddCustomField-". $CF->id ."}__',". $format,
+ AllowSorting => 1,
+ ShowEmpty => 0,
+ PassArguments => [
+ qw(id Format Rows Page Order OrderBy),
+ ],
+&>
+
+% }
+
+<& /Elements/Submit, Name => 'UpdateObjs' &>
</form>
<%INIT>
my $CF = RT::CustomField->new($session{'CurrentUser'});
$CF->Load($id) or Abort(loc("Could not load CustomField [_1]"), $id);
-my $LookupType = $CF->LookupType || '';
-$LookupType =~ /^([^-]+)/ ||
- Abort(loc("Object of type [_1] cannot take custom fields", $LookupType));
-
-my $Class = $1;
-my $CollectionClass;
-if (UNIVERSAL::can($Class.'Collection', 'new') ) {
-$CollectionClass = $Class.'Collection';
-
-} elsif (UNIVERSAL::can($Class.'es', 'new') ) {
- $CollectionClass = $Class.'es';
-} elsif (UNIVERSAL::can($Class.'s', 'new') ) {
- $CollectionClass = $Class.'s';
-
-} else {
- Abort(loc("Can't find a collection class for '[_1]'", $Class));
-}
-
-
-my $title = loc('Modify associated objects for [_1]', $CF->Name);
+my $class = $CF->RecordClassFromLookupType;
+Abort(loc("Something wrong. Contact system administrator"))
+ unless $class;
-my $Objects = $CollectionClass->new($session{'CurrentUser'});
+my (@results);
-# If CF is a Group CF, only display user-defined groups
-if ($Class eq 'RT::Group') {
- $Objects->LimitToUserDefinedGroups;
+if ( $UpdateObjs ) {
+ if ( defined (my $del = $ARGS{'RemoveCustomField-'.$CF->id}) ) {
+ foreach my $id ( ref $del? (@$del) : ($del) ) {
+ my $object = $class->new( $session{'CurrentUser'} );
+ if ( $id ) {
+ $object->Load( $id );
+ next unless $object->id;
+ }
+
+ my ($status, $msg) = $CF->RemoveFromObject( $object );
+ push @results, $msg;
+ }
+ }
+ if ( defined (my $add = $ARGS{'AddCustomField-'.$CF->id}) ) {
+ foreach my $id ( ref $add? (@$add) : ($add) ) {
+ my $object = $class->new( $session{'CurrentUser'} );
+ if ( $id ) {
+ $object->Load( $id );
+ next unless $object->id;
+ }
+
+ my ($status, $msg) = $CF->AddToObject( $object );
+ push @results, $msg;
+ }
+ }
}
-my (@results);
-my (@AssignedObjs, @UnassignedObjs);
-
-$Objects->UnLimit;
-$Objects->OrderBy( FIELD => 'Name' );
+my $is_global = $CF->IsApplied(0);
+my $applied = $CF->AppliedTo;
+my $not_applied = $CF->NotAppliedTo;
-my $ObjectCFs;
-$ObjectCFs = RT::ObjectCustomFields->new($session{'CurrentUser'});
-$ObjectCFs->UnLimit;
-$ObjectCFs->LimitToCustomField($id);
+my $collection_class = ref($applied);
+$collection_class =~ s/^RT:://;
-my %seen;
-while (my $OCF = $ObjectCFs->Next) {
- $seen{$OCF->ObjectId}++;
-}
+my $format = RT->Config->Get('AdminSearchResultFormat')->{$collection_class}
+ || '__id__,__Name__';
-while (my $obj = $Objects->Next) {
- my $obj_id = $obj->Id;
-
- if ($UpdateObjs) {
- # Go through and delete all the custom field relationships that this object
- # no longer has
- my $key = "Object-$obj_id-CF-$id";
- if ($ARGS{$key}) {
- if (!$seen{$obj_id}) {
- my ($val, $msg) = $CF->AddToObject($obj);
- push (@results, $msg);
- push @UnassignedObjs, $obj if !$val;
- }
- }
- else {
- push @UnassignedObjs, $obj;
- if ($seen{$obj_id}) {
- my ($val, $msg) = $CF->RemoveFromObject($obj);
- push (@results, $msg);
- pop @UnassignedObjs if !$val;
- }
- }
- }
- elsif (!$seen{$obj_id}) {
- push @UnassignedObjs, $obj;
- }
- next if @UnassignedObjs and $UnassignedObjs[-1] == $obj;
- push @AssignedObjs, $obj;
-}
+my $title = loc('Modify associated objects for [_1]', $CF->Name);
</%INIT>
<%ARGS>
diff --git a/rt/share/html/Admin/CustomFields/index.html b/rt/share/html/Admin/CustomFields/index.html
index 139b8ebd6..16fb593f6 100644
--- a/rt/share/html/Admin/CustomFields/index.html
+++ b/rt/share/html/Admin/CustomFields/index.html
@@ -45,40 +45,38 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<& /Admin/Elements/Header, Title => loc('Select a Custom Field') &>
+<& /Admin/Elements/Header, Title => $title &>
<& /Admin/Elements/CustomFieldTabs,
current_tab => 'Admin/CustomFields/',
- Title => loc('Select a Custom Field') &>
+ Title => $title,
+&>
-% my @types;
-% my $prev_lookup = '';
-% while (my $CustomFieldObj = $CustomFields->Next) {
-% next unless $CustomFieldObj->CurrentUserHasRight('AdminCustomField');
-% my $lookup = $CustomFieldObj->FriendlyLookupType;
-% if ($lookup ne $prev_lookup) {
-% if ($prev_lookup) {
-</ul>
-% }
-<h2><% loc("Custom Fields for [_1]", $lookup) %></h2>
-<ul>
-% $prev_lookup = $lookup;
-% push @types, [$lookup, $CustomFieldObj->LookupType];
-% }
-%
-<li>
-<a href="Modify.html?id=<% $CustomFieldObj->id %>"><% $CustomFieldObj->Name %>: <% $CustomFieldObj->Description %></a>
-</li>
-% }
-% if ($prev_lookup) {
-</ul>
+% my $tmp = RT::CustomField->new( $session{'CurrentUser'} );
+% if ( $Type ) {
+<h2><% loc("Custom Fields for [_1]", $tmp->FriendlyLookupType( $Type )) %></h2>
% }
+<& /Elements/CollectionList,
+ OrderBy => 'LookupType|Name',
+ Order => 'ASC|ASC',
+ Rows => 50,
+ %ARGS,
+ Collection => $CustomFields,
+ Format => $Format,
+ DisplayFormat => ($Type? '' : '__FriendlyLookupType__,'). $Format,
+ AllowSorting => 1,
+ PassArguments => [
+ qw(Format Rows Page Order OrderBy),
+ qw(Type ShowDisabled)
+ ],
+&>
+
<form action="<%RT->Config->Get('WebPath')%>/Admin/CustomFields/index.html" method="get">
<&|/l&>Only show custom fields for:</&>
<select name="Type">
<option value="" <% !$Type && 'selected="selected"'%> ><% loc('(any)') %></option>
-% for (@types) {
-<option value="<% $_->[1] %>" <% $_->[1] eq $Type && 'selected="selected"'%> ><% $_->[0] %></option>
+% for my $type ( $tmp->LookupTypes ) {
+<option value="<% $type %>" <% $type eq $Type && 'selected="selected"'%> ><% $tmp->FriendlyLookupType( $type ) %></option>
% }
</select>
<br />
@@ -92,8 +90,12 @@
<%args>
$Type => ''
$ShowDisabled => 0
+
+$Format => undef
</%args>
<%INIT>
+my $title = loc('Select a Custom Field');
+
$Type ||= $ARGS{'type'} || '';
if ( !$Type && $ARGS{'type'} ) {
$Type ||= $ARGS{'type'};
@@ -102,7 +104,9 @@ if ( !$Type && $ARGS{'type'} ) {
my $CustomFields = RT::CustomFields->new($session{'CurrentUser'});
$CustomFields->UnLimit;
-$CustomFields->{'find_disabled_rows'} = 1 if $ShowDisabled;
+$CustomFields->FindAllRows if $ShowDisabled;
$CustomFields->LimitToLookupType( $Type ) if $Type;
-$CustomFields->OrderByCols( { FIELD => 'LookupType' }, { FIELD => 'Name' } );
+
+$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'CustomFields'};
+
</%INIT>
diff --git a/rt/share/html/Admin/Elements/EditCustomFields b/rt/share/html/Admin/Elements/EditCustomFields
index 89c6d0f65..0767e4ae4 100755
--- a/rt/share/html/Admin/Elements/EditCustomFields
+++ b/rt/share/html/Admin/Elements/EditCustomFields
@@ -51,155 +51,126 @@
<input type="hidden" class="hidden" name="id" value="<% $Object->Id || ''%>" />
<input type="hidden" class="hidden" name="ObjectType" value="<% $ObjectType %>" />
<input type="hidden" class="hidden" name="SubType" value="<% $SubType %>" />
-<input type="hidden" class="hidden" name="UpdateCFs" value="1" />
-% if ($Object->Id) {
-<h2><&|/l&>Global Custom Fields</&></h2>
-<& PickCustomFields, CustomFields => \@GlobalCFs, ReadOnly => 1, id => $id, SubType => $SubType &>
-% }
<h2><&|/l&>Selected Custom Fields</&></h2>
-<& PickCustomFields, CustomFields => [$ObjectCFs->CustomFields], id => $id, Checked => 1, SubType => $SubType &>
-<h2><&|/l&>Unselected Custom Fields</&></h2>
-<& PickCustomFields, CustomFields => \@UnassignedCFs, id => $id, SubType => $SubType &>
+<& /Elements/CollectionList,
+ %ARGS,
+ Collection => $applied_cfs,
+ Rows => 0,
+ Page => 1,
+ Format => $format,
+ DisplayFormat =>
+ $id
+ ? ("'__RemoveCheckBox.{$id}__',". $format .", '__MoveCF.{$id}__'")
+ : ("'__CheckBox.{RemoveCustomField}__',". $format .", '__MoveCF.{$id}__'"),
+ AllowSorting => 0,
+ ShowEmpty => 0,
+ PassArguments => [
+ qw(Page Order OrderBy),
+ qw(id ObjectType SubType),
+ ],
+&>
-<& /Elements/Submit, CheckAll => 1, ClearAll => 1 &>
+<h2><&|/l&>Unselected Custom Fields</&></h2>
+<& /Elements/CollectionList,
+ OrderBy => 'Name',
+ Order => 'ASC',
+ %ARGS,
+ Collection => $not_applied_cfs,
+ Rows => 50,
+ Format => $format,
+ DisplayFormat => "'__CheckBox.{AddCustomField}__',". $format,
+ AllowSorting => 1,
+ ShowEmpty => 0,
+ PassArguments => [
+ qw(Page Order OrderBy),
+ qw(id ObjectType SubType),
+ ],
+&>
+
+<& /Elements/Submit, Name => 'UpdateCFs' &>
</form>
<%INIT>
-my $CustomFields = RT::CustomFields->new($session{'CurrentUser'});
-my @results;
-my (@GlobalCFs, @UnassignedCFs);
-
-my $id = $Object->Id;
+my $id = $Object->Id || 0;
if ($id and !$Object->CurrentUserHasRight('AssignCustomFields')) {
$m->out('<p><i>', loc('(No custom fields)'), '</i></p>');
return;
}
+my @results;
+
my $lookup = $ObjectType;
$lookup .= "-$SubType" if $SubType;
-$CustomFields->LimitToLookupType($lookup);
-$CustomFields->OrderBy( FIELD => 'Name' );
-
-
-my ($GlobalCFs, $ObjectCFs);
-$ObjectCFs = RT::ObjectCustomFields->new($session{'CurrentUser'});
-$ObjectCFs->UnLimit;
-$ObjectCFs->LimitToObjectId($id);
-$ObjectCFs->LimitToLookupType($lookup);
-
-# Check sanity of SortOrders
-my %SortOrders;
-$SortOrders{ $_->SortOrder }++
- while ($_ = $ObjectCFs->Next);
-
-# If there are duplicates, run though and squash them
-if (grep $_ > 1, values %SortOrders) {
- my $i = 1;
- while ( my $ObjectCF = $ObjectCFs->Next ) {
- $ObjectCF->SetSortOrder( $i++ );
+## deal with moving sortorder of custom fields
+if ( $MoveCustomFieldUp ) { {
+ my $record = RT::ObjectCustomField->new( $session{'CurrentUser'} );
+ $record->LoadByCols( ObjectId => $id, CustomField => $MoveCustomFieldUp );
+ unless ( $record->id ) {
+ push @results, loc("Custom field #[_1] is not applied to this object", $MoveCustomFieldUp);
+ last;
}
- $ObjectCFs->GotoFirstItem;
-}
-
-# {{{ deal with moving sortorder of custom fields
-if ($CustomField and $Move) {
- my $SourceObj = RT::ObjectCustomField->new($session{'CurrentUser'});
- $SourceObj->LoadByCols( ObjectId => $id, CustomField => $CustomField );
-
- my $TargetObj;
- my $target_order = $SourceObj->SortOrder + $Move;
- while (my $ObjectCF = $ObjectCFs->Next) {
- my $this_order = $ObjectCF->SortOrder;
-
- # if we have an exact match, finish the loop now
- ($TargetObj = $ObjectCF, last) if $this_order == $target_order;
-
- # otherwise, we need to apropos toward the general direction
- # ... first, check the sign is correct
- next unless ($this_order - $SourceObj->SortOrder) * $Move > 0;
- # ... next, see if we already have a candidate
- if ($TargetObj) {
- # ... if yes, compare the delta and choose the smaller one
- my $orig_delta = abs($TargetObj->SortOrder - $target_order);
- my $this_delta = abs($this_order - $target_order);
- next if $orig_delta < $this_delta;
- }
-
- $TargetObj = $ObjectCF;
+ my ($status, $msg) = $record->MoveUp;
+ push @results, $msg;
+} }
+if ( $MoveCustomFieldDown ) { {
+ my $record = RT::ObjectCustomField->new( $session{'CurrentUser'} );
+ $record->LoadByCols( ObjectId => $id, CustomField => $MoveCustomFieldDown );
+ unless ( $record->id ) {
+ push @results, loc("Custom field #[_1] is not applied to this object", $MoveCustomFieldDown);
+ last;
}
- if ($TargetObj) {
- # swap their sort order
- my ($s, $t) = ($SourceObj->SortOrder, $TargetObj->SortOrder);
- $TargetObj->SetSortOrder($s);
- $SourceObj->SetSortOrder($t);
- # because order changed, we must redo search for subsequent uses
+ my ($status, $msg) = $record->MoveDown;
+ push @results, $msg;
+} }
+
+if ( $UpdateCFs ) {
+ foreach my $cf_id ( @AddCustomField ) {
+ my $CF = RT::CustomField->new( $session{'CurrentUser'} );
+ $CF->Load( $cf_id );
+ unless ( $CF->id ) {
+ push @results, loc("Couldn't load CustomField #[_1]", $cf_id);
+ next;
+ }
+ my ($status, $msg) = $CF->AddToObject( $Object );
+ push @results, $msg;
+ }
+ foreach my $cf_id ( @RemoveCustomField ) {
+ my $CF = RT::CustomField->new( $session{'CurrentUser'} );
+ $CF->Load( $cf_id );
+ unless ( $CF->id ) {
+ push @results, loc("Couldn't load CustomField #[_1]", $cf_id);
+ next;
+ }
+ my ($status, $msg) = $CF->RemoveFromObject( $Object );
+ push @results, $msg;
}
-
- $ObjectCFs->GotoFirstItem;
-}
-# }}}
-
-if ($id) {
- $GlobalCFs = RT::ObjectCustomFields->new($session{'CurrentUser'});
- $GlobalCFs->LimitToObjectId(0);
- $GlobalCFs->LimitToLookupType($lookup);
}
-while (my $cf = $CustomFields->Next) {
- my $cf_id = $cf->Id;
+my $applied_cfs = RT::CustomFields->new( $session{'CurrentUser'} );
+$applied_cfs->LimitToLookupType($lookup);
+$applied_cfs->LimitToGlobalOrObjectId($id);
+$applied_cfs->ApplySortOrder;
- if ($GlobalCFs and $GlobalCFs->HasEntryForCustomField($cf_id)) {
- push @GlobalCFs, $cf;
- next;
- }
+my $not_applied_cfs = RT::CustomFields->new( $session{'CurrentUser'} );
+$not_applied_cfs->LimitToLookupType($lookup);
+$not_applied_cfs->LimitToNotApplied( $id ? ($id, 0) : (0) );
- if ($UpdateCFs) {
- # Go through and delete all the custom field relationships that this object
- # no longer has
- my $key = "Object-$id-CF-$cf_id";
- if ($ARGS{$key}) {
- if (!$ObjectCFs->HasEntryForCustomField($cf_id)) {
- my ($val, $msg) = $cf->AddToObject($Object);
- push (@results, $msg);
- push @UnassignedCFs, $cf if !$val;
- }
- }
- else {
- push @UnassignedCFs, $cf;
- if ($ObjectCFs->HasEntryForCustomField($cf_id)) {
- my ($val, $msg) = $cf->RemoveFromObject($Object);
- push (@results, $msg);
- pop @UnassignedCFs if !$val;
- }
- }
- }
- elsif (!$ObjectCFs->HasEntryForCustomField($cf_id)) {
- push @UnassignedCFs, $cf;
- }
- else {
- }
-}
-
-# redo search...
-$ObjectCFs = RT::ObjectCustomFields->new($session{'CurrentUser'});
-$ObjectCFs->UnLimit;
-$ObjectCFs->LimitToObjectId($id);
-$ObjectCFs->LimitToLookupType($lookup);
+my $format = RT->Config->Get('AdminSearchResultFormat')->{'CustomFields'};
</%INIT>
<%ARGS>
-$title => undef
-$Move => undef
-$Source => undef
-$CustomField => undef
-$FindDisabledCustomFields => undef
-$UpdateCFs => 0
$Object
$ObjectType
$SubType => ''
+
+$UpdateCFs => undef
+@RemoveCustomField => ()
+@AddCustomField => ()
+$MoveCustomFieldUp => undef
+$MoveCustomFieldDown => undef
</%ARGS>
diff --git a/rt/share/html/Admin/Elements/EditScrip b/rt/share/html/Admin/Elements/EditScrip
index 29ec71cd7..2bcf64d49 100755
--- a/rt/share/html/Admin/Elements/EditScrip
+++ b/rt/share/html/Admin/Elements/EditScrip
@@ -56,6 +56,7 @@
<tr><td align="right"><&|/l&>Description</&>:</td><td>
<input name="Scrip-<% $id %>-Description"
+ size="60"
value="<% $ARGS{"Scrip-$id-Description"} || $scrip->Description || '' %>" />
</td></tr>
diff --git a/rt/share/html/Admin/Elements/EditScrips b/rt/share/html/Admin/Elements/EditScrips
index df349e1b9..dce0390fd 100755
--- a/rt/share/html/Admin/Elements/EditScrips
+++ b/rt/share/html/Admin/Elements/EditScrips
@@ -109,10 +109,7 @@ foreach my $id ( grep $_, @DeleteScrip, map /^DeleteScrip-(\d+)/, keys %ARGS ) {
}
# }}}
-my $dir_path = $m->request_comp->dir_path;
-$Format ||= qq{'<a href="__WebPath__$dir_path/Scrip.html?id=__id__&Queue=$id">__id__</a>/TITLE:#'}
- .qq{,'<a href="__WebPath__$dir_path/Scrip.html?id=__id__&Queue=$id">__Description__</a>/TITLE:Description'}
- .q{,__Stage__, __Condition__, __Action__, __Template__};
+$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Scrips'};
</%init>
diff --git a/rt/share/html/Admin/Elements/EditTemplates b/rt/share/html/Admin/Elements/EditTemplates
index 0bd68c2c0..7d7d930ce 100755
--- a/rt/share/html/Admin/Elements/EditTemplates
+++ b/rt/share/html/Admin/Elements/EditTemplates
@@ -73,10 +73,7 @@
</form>
<%INIT>
-my $dir_path = $m->request_comp->dir_path;
-$Format ||= qq{'<a href="__WebPath__$dir_path/Template.html?Queue=$id&Template=__id__">__id__</a>/TITLE:#'}
- .qq{,'<a href="__WebPath__$dir_path/Template.html?Queue=$id&Template=__id__">__Name__</a>/TITLE:Name'}
- .qq{,'__Description__'};
+$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Templates'};
my $QueueObj = RT::Queue->new( $session{'CurrentUser'} );
$QueueObj->Load( $id ) if $id;
diff --git a/rt/share/html/Admin/Groups/index.html b/rt/share/html/Admin/Groups/index.html
index 078f51bd9..17b760c26 100755
--- a/rt/share/html/Admin/Groups/index.html
+++ b/rt/share/html/Admin/Groups/index.html
@@ -113,10 +113,7 @@ else {
$caption = loc("User-defined groups");
}
-
-$Format ||= q{'<a href="__WebPath__/Admin/Groups/Modify.html?id=__id__">__id__</a>/TITLE:#'}
- .q{,'<a href="__WebPath__/Admin/Groups/Modify.html?id=__id__">__Name__</a>/TITLE:Name'}
- .q{,'__Description__'};
+$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Groups'};
</%INIT>
<%ARGS>
diff --git a/rt/share/html/Admin/Queues/Modify.html b/rt/share/html/Admin/Queues/Modify.html
index df97a68c7..c6ffe179f 100755
--- a/rt/share/html/Admin/Queues/Modify.html
+++ b/rt/share/html/Admin/Queues/Modify.html
@@ -194,6 +194,13 @@ if ( $QueueObj->Id ) {
);
push @results, @linkresults;
push @results, ProcessObjectCustomFieldUpdates( ARGSRef => \%ARGS, Object => $QueueObj );
+ if ( RT->Config->Get('RTAddressRegexp') ) {
+ foreach my $address ( $QueueObj->CorrespondAddress, $QueueObj->CommentAddress ) {
+ next unless defined $address && length $address;
+ next if RT::EmailParser->IsRTAddress( $address );
+ push @results, loc("RTAddressRegexp option in the config doesn't match [_1]", $address );
+ }
+ }
}
</%INIT>
diff --git a/rt/share/html/Admin/Queues/index.html b/rt/share/html/Admin/Queues/index.html
index 52e7b3bfd..c0131b14f 100755
--- a/rt/share/html/Admin/Queues/index.html
+++ b/rt/share/html/Admin/Queues/index.html
@@ -92,7 +92,7 @@
<%INIT>
my $queues = new RT::Queues($session{'CurrentUser'});
-$queues->{'find_disabled_rows'} = 1 if $FindDisabledQueues;
+$queues->FindAllRows if $FindDisabledQueues;
my ($caption);
if ( defined $QueueString && length $QueueString ) {
@@ -111,9 +111,7 @@ if ( defined $QueueString && length $QueueString ) {
: loc("Enabled Queues");
}
-$Format ||= q{'<a href="__WebPath__/Admin/Queues/Modify.html?id=__id__">__id__</a>/TITLE:#'}
- .q{,'<a href="__WebPath__/Admin/Queues/Modify.html?id=__id__">__Name__</a>/TITLE:Name'}
- .q{,__Description__,__Address__,__Priority__,__DefaultDueIn__,__Disabled__};
+$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Queues'};
</%INIT>
<%ARGS>
diff --git a/rt/share/html/Admin/Tools/Configuration.html b/rt/share/html/Admin/Tools/Configuration.html
index eb48af19c..22c846aca 100644
--- a/rt/share/html/Admin/Tools/Configuration.html
+++ b/rt/share/html/Admin/Tools/Configuration.html
@@ -50,9 +50,7 @@ require Module::Versions::Report;
my $title = loc('System Configuration');
unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'SuperUser')) {
Abort(loc('This feature is only available to system administrators'));
-}
-
-
+}
</%init>
<& /Admin/Elements/Header, Title => $title &>
<& /Admin/Elements/ToolTabs,
@@ -60,18 +58,15 @@ unless ($session{'CurrentUser'}->HasRight( Object=> $RT::System, Right => 'Super
current_subtab => 'Admin/Tools/Configuration.html',
Title => $title &>
-
-
-<h2><&|/l&>Loaded perl modules</&></h2>
-% my $report = Module::Versions::Report::report();
-% my @report = grep /v\d/, split("\n",$report);
-<pre>
-<% join('<br />', @report) |n %>
-</pre>
-
-<h2><&|/l&>RT Config</&></h2>
-<table>
+<&|/Widgets/TitleBox, title => loc("RT Configuration") &>
+<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection">
+<tr class="collection-as-table">
+<th class="collection-as-table"><&|/l&>Option</&></th>
+<th class="collection-as-table"><&|/l&>Value</&></th>
+<th class="collection-as-table"><&|/l&>Source</&></th>
+</tr>
<%PERL>
+my $index_conf;
foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
my $val = RT->Config->Get( $key );
next unless defined $val;
@@ -90,9 +85,11 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
else {
$description = loc("core config");
}
+ $index_conf++;
</%PERL>
-<tr><th><% $key %></th>
-<td rowspan="2">\
+<tr class="<% $index_conf%2 ? 'oddline' : 'evenline'%>">
+<td class="collection-as-table"><% $key %></td>
+<td class="collection-as-table">
% if ( $key =~ /Password(?!Length)/i ) {
<em>Password not printed</em>\
% } elsif ( !ref $val ) {
@@ -104,19 +101,38 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
% } else {
<% ref $val %>\
% }
-</td></tr>
-<tr><td><% $description %></td></tr>
+</td>
+<td class="collection-as-table" style="white-space: nowrap">
+% if ( $description =~ /^.*site config$/ ) {
+<span style="font-weight: bold"><% $description %></span>
+% } else {
+<% $description %>
+% }
+</td>
+</tr>
% }
</table>
-
-<h2><&|/l&>RT Variables</&></h2>
-<table>
-% { no strict qw/refs/;
-% my %config_opt = map { $_ => 1 } RT->Config->Options( Overridable => undef );
-% foreach my $key ( sort keys %{*RT::} ) {
-% next if !${'RT::'.$key} || ref ${'RT::'.$key} || $config_opt{ $key };
-<tr><th>RT::<% $key %></th>
-<td>
+</&>
+<table width="100%">
+ <tr>
+ <td valign="top" width="60%" class="boxcontainer">
+<&|/Widgets/TitleBox, title=> loc("RT core variables") &>
+<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection">
+<tr class="collection-as-table">
+<th class="collection-as-table"><&|/l&>Variable</&></th>
+<th class="collection-as-table"><&|/l&>Value</&></th>
+</tr>
+<%PERL>
+{ no strict qw/refs/;
+my %config_opt = map { $_ => 1 } RT->Config->Options( Overridable => undef );
+my $index_var;
+foreach my $key ( sort keys %{*RT::} ) {
+ next if !${'RT::'.$key} || ref ${'RT::'.$key} || $config_opt{ $key };
+ $index_var++;
+</%PERL>
+<tr class="collection-as-table <% $index_var%2 ? 'oddline' : 'evenline'%>">
+<td class="collection-as-table">RT::<% $key %></td>
+<td class="collection-as-table">
% if ( $key =~ /Password(?!Length)/i ) {
<em>Password not printed</em>
% } else {
@@ -127,44 +143,100 @@ foreach my $key ( RT->Config->Options( Overridable => undef, Sorted => 0 ) ) {
% }
% }
</table>
+</&>
-<h2><&|/l&>RT Size</&></h2>
-<table>
+<&|/Widgets/TitleBox, title => loc("RT Size") &>
+<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection">
+<tr class="collection-as-table">
+<th class="collection-as-table"><&|/l&>Object</&></th>
+<th class="collection-as-table"><&|/l&>Size</&></th>
+</tr>
<%PERL>
-for my $type (qw/Ticket Queue Transaction Group/) {
- my $class = 'RT::' . $type . 's';
+my ($index_size, $user_count, $privileged_count);
+for my $type (qw/Tickets Queues Transactions Groups PrivilegedUsers UnprivilegedUsers/) {
+ my $count;
+ my $class = 'RT::' . $type;
+ $class =~ s/Privileged|Unprivileged//;
my $collection = $class->new($RT::SystemUser);
$collection->UnLimit;
- my $count = $collection->CountAll;
+ if ($type =~ /PrivilegedUsers/) {
+ $user_count = $collection->CountAll;
+ $collection->LimitToPrivileged;
+ $count = $privileged_count = $collection->CountAll;
+ } elsif ($type =~ /UnprivilegedUsers/) {
+ $count = $user_count - $privileged_count;
+ } else {
+ $count = $collection->CountAll;
+ }
+ $index_size++;
</%PERL>
-<tr><th><% $type %>s</th>
-<td><% $count %></td></tr>
+<tr class="<% $index_size%2 ? 'oddline' : 'evenline'%>">
+<td class="collection-as-table"><% $type %></td>
+<td class="collection-as-table"><% $count %></td>
+</tr>
% }
+</table>
+</&>
+</td>
+<td valign="top" class="boxcontainer">
-<%PERL>
-my $users = RT::Users->new($RT::SystemUser);
-$users->UnLimit;
-my $user_count = $users->CountAll;
+<&|/Widgets/TitleBox, title => loc("Mason template search order") &>
+<ol>
+% foreach my $path ( map { $_->[1] } $m->interp->comp_root_array ) {
+<li><% $path %></li>
+% }
+</ol>
+</&>
-$users->LimitToPrivileged;
-my $privileged_count = $users->CountAll;
-my $unprivileged_count = $user_count - $privileged_count;
-</%PERL>
-<tr><th>Privileged Users</th>
-<td><% $privileged_count %></td></tr>
-<tr><th>Unprivileged Users</th>
-<td><% $unprivileged_count %></td></tr>
+<&|/Widgets/TitleBox, title => loc("Perl library search order") &>
+<ol>
+% foreach my $inc (@INC) {
+<li><% $inc %></li>
+% }
+</ol>
+</&>
+
+</td>
+</table>
+
+<&|/Widgets/TitleBox, title => loc("Loaded perl modules")&>
+<table border="0" cellspacing="0" cellpadding="5" width="100%" class="collection">
+<tr class="collection-as-table">
+<th class="collection-as-table"><&|/l&>Module</&></th>
+<th class="collection-as-table"><&|/l&>Version</&></th>
+<th class="collection-as-table"><&|/l&>Source</&></th>
+
+
+<%perl>
+my $i = 0;
+my $report = Module::Versions::Report::report();
+my @report = grep /v\d/, split("\n",$report);
+shift @report; # throw away the perl version
+my ($ver, $source, $distfile);
+foreach my $item (@report) {
+if ($item =~ /^\s*(.*?)\s*v(\S+);/) {
+ $item = $1;
+ $ver = $2;
+ $distfile = $item.".pm";
+ $distfile =~ s|::|/|g;
+}
+</%perl>
+<tr class="<% $i++ %2 ? 'oddline' : 'evenline'%>">
+<td class="collection-as-table"><% $item %></td>
+ <td class="collection-as-table">
+ <%$ver%>
+ </td>
+ <td class="collection-as-table">
+ <% $INC{$distfile} %>
+ </td>
+</tr>
+% }
</table>
+</&>
-<h2><&|/l&>Perl configuration</&></h2>
+<&|/Widgets/TitleBox, title => loc("Perl configuration") &>
% require Config;
<pre>
<% Config::myconfig() %>
</pre>
-
-<h2><&|/l&>Perl Include Paths (@INC)</&></h2>
-<pre>
-% foreach my $inc (@INC) {
-<% $inc %>
-% }
-</pre>
+</&>
diff --git a/rt/share/html/Admin/Users/Memberships.html b/rt/share/html/Admin/Users/Memberships.html
index ea5dd258b..cd8574d58 100644
--- a/rt/share/html/Admin/Users/Memberships.html
+++ b/rt/share/html/Admin/Users/Memberships.html
@@ -128,9 +128,7 @@ my $is_not_member = RT::Groups->new( $session{'CurrentUser'} );
$is_not_member->LimitToUserDefinedGroups;
$is_not_member->WithoutMember( PrincipalId => $UserObj->Id );
-$Format ||= q{'<a href="__WebPath__/Admin/Groups/Modify.html?id=__id__">__id__</a>/TITLE:#'}
- .q{,'<a href="__WebPath__/Admin/Groups/Modify.html?id=__id__">__Name__</a>/TITLE:Name'}
- .q{,'__Description__'};
+$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Groups'};
</%INIT>
<%ARGS>
$id => undef
diff --git a/rt/share/html/Admin/Users/Modify.html b/rt/share/html/Admin/Users/Modify.html
index aae38b173..70650a47d 100755
--- a/rt/share/html/Admin/Users/Modify.html
+++ b/rt/share/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%> />
@@ -113,26 +119,11 @@
<input type="hidden" class="hidden" name="SetPrivileged" value="1" />
<input type="checkbox" class="checkbox" name="Privileged" value="1" <%$PrivilegedChecked||''%> /> <&|/l&>Let this user be granted rights</&><br />
-
-% unless (RT->Config->Get('WebExternalAuth') and !RT->Config->Get('WebFallbackToInternalAuth')) {
-<table>
-<tr>
-<td align="right">
-<&|/l&>New Password</&>:
-</td>
-<td align="left">
-<input type="password" name="Pass1" autocomplete="off" />
-</td>
-</tr>
-<tr><td align="right">
-<&|/l&>Retype Password</&>:
-</td>
-<td>
-<input type="password" name="Pass2" autocomplete="off" />
-</td>
-</tr>
-</table>
-% }
+
+<& /Elements/EditPassword,
+ User => $UserObj,
+ Name => [qw(CurrentPass Pass1 Pass2)],
+&>
</&>
% $m->callback( %ARGS, CallbackName => 'LeftColumnBottom', UserObj => $UserObj );
</td>
@@ -345,6 +336,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 ) {
@@ -364,22 +357,20 @@ if ($UserObj->Id && $id ne 'new') {
# }}}
}
+
+my %password_cond = $UserObj->CurrentUserRequireToSetPassword;
if ( $UserObj->Id ) {
- my $password_not_set;
# Deal with Password field
- if ( !$Pass1 and !$Pass2 ) {
- $password_not_set = 1;
- } elsif ( $Pass1 ne $Pass2 ) {
- $password_not_set = 1;
- push @results, loc("Passwords do not match.");
- } elsif ( $Pass1 eq $Pass2 and !$UserObj->IsPassword($Pass1) ) {
- my ($code, $msg) = $UserObj->SetPassword($Pass1);
- push @results, loc_fuzzy($msg);
- $password_not_set = 1 unless $code;
+ my ($status, $msg) = $UserObj->SafeSetPassword(
+ Current => $CurrentPass,
+ New => $Pass1,
+ Confirmation => $Pass2,
+ );
+ push @results, $msg;
+
+ if ( $id eq 'new' && !$status ) {
+ push @results, loc("A password was not set, so user won't be able to login.");
}
- if ($id eq 'new' and $password_not_set) {
- push @results, loc("A password was not set, so user won't be able to login.");
- }
}
@@ -431,7 +422,12 @@ $City => undef
$State => undef
$Zip => undef
$Country => undef
+$CurrentPass => undef
$Pass1 => undef
-$Pass2=> undef
+$Pass2 => undef
$Create=> undef
+$OnlySearchForCustomers => undef
+$OnlySearchForServices => undef
+$CustomerString => undef
+$ServiceString => undef
</%ARGS>
diff --git a/rt/share/html/Admin/Users/index.html b/rt/share/html/Admin/Users/index.html
index e9a58183d..88a775fc3 100755
--- a/rt/share/html/Admin/Users/index.html
+++ b/rt/share/html/Admin/Users/index.html
@@ -93,7 +93,7 @@
<%INIT>
my $caption;
my $users = RT::Users->new( $session{'CurrentUser'} );
-$users->{'find_disabled_rows'} = 1 if $FindDisabledUsers;
+$users->FindAllRows if $FindDisabledUsers;
if ( defined($UserString) && length $UserString ) {
$caption = loc("Users matching search criteria");
@@ -117,9 +117,7 @@ else {
$users->LimitToPrivileged;
}
-$Format ||= q{'<a href="__WebPath__/Admin/Users/Modify.html?id=__id__">__id__</a>/TITLE:#'}
- .q{,'<a href="__WebPath__/Admin/Users/Modify.html?id=__id__">__Name__</a>/TITLE:Name'}
- .q{,__RealName__, __EmailAddress__};
+$Format ||= RT->Config->Get('AdminSearchResultFormat')->{'Users'};
</%INIT>
<%ARGS>
diff --git a/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Elements/Tabs/Default b/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Elements/Tabs/Default
new file mode 100644
index 000000000..2c0698ec2
--- /dev/null
+++ b/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Elements/Tabs/Default
@@ -0,0 +1,12 @@
+<%doc>
+If mandatory fields aren't set yet, point the "Resolve" link back
+to "Ticket Basics".
+</%doc>
+<%init>
+my $TicketObj = delete($ARGS{'Ticket'});
+my $actions = $ARGS{'actions'};
+if( $m->comp('/Ticket/Elements/CheckMandatoryFields', Ticket => $TicketObj)
+ ) {
+ $actions->{'G'}->{'path'} = 'Ticket/Modify.html?id='.$TicketObj->Id.'&resolve=1';
+}
+</%init>
diff --git a/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Modify.html/BeforeActionList b/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Modify.html/BeforeActionList
new file mode 100644
index 000000000..4779411ce
--- /dev/null
+++ b/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Modify.html/BeforeActionList
@@ -0,0 +1,15 @@
+<%init>
+use Data::Dumper;
+my $ARGSRef = $ARGS{'ARGSRef'};
+my $TicketObj = $ARGS{'Ticket'};
+my $results = $ARGS{'Actions'};
+if(defined($ARGSRef->{'resolve'})) {
+ my @errors =
+ $m->comp('/Ticket/Elements/CheckMandatoryFields', Ticket => $TicketObj);
+ return if !@errors;
+ my $msg = 'Missing required field'.(@errors > 1 ? 's' : '').': ' .
+ join(', ', map { $_->Name } @errors);
+ $m->notes( ('InvalidField-' . $_->Id) => 'Required' ) foreach @errors;
+ push @$results, $msg;
+}
+</%init>
diff --git a/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Update.html/BeforeDisplay b/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Update.html/BeforeDisplay
new file mode 100644
index 000000000..0d69bc27b
--- /dev/null
+++ b/rt/share/html/Callbacks/CheckMandatoryFields/Ticket/Update.html/BeforeDisplay
@@ -0,0 +1,24 @@
+<%doc>
+When the user tries to change a ticket's status to "resolved" through
+the Update interface, check mandatory fields. If they aren't all set,
+redirect to Ticket Basics instead of updating. Note that this will
+lose any comments/time/other information the user has entered.
+</%doc>
+
+<%init>
+my $TicketObj = $ARGS{'Ticket'};
+my $ARGSRef = $ARGS{'ARGSRef'};
+my $oldStatus = $TicketObj->Status();
+my $newStatus = $ARGSRef->{'Status'} || $ARGSRef->{'DefaultStatus'};
+if( $oldStatus ne 'resolved' and
+ $newStatus eq 'resolved' and
+ $m->comp('/Ticket/Elements/CheckMandatoryFields',
+ Ticket => $TicketObj
+ ) ) {
+ $m->clear_buffer;
+ RT::Interface::Web::Redirect(
+ RT->Config->Get('WebURL')."Ticket/Modify.html?id=".$TicketObj->Id."&resolve=1"
+ );
+ $m->abort;
+}
+</%init>
diff --git a/rt/share/html/Callbacks/RTx-Calendar/Elements/Header/Head b/rt/share/html/Callbacks/RTx-Calendar/Elements/Header/Head
new file mode 100644
index 000000000..c1f24c2b4
--- /dev/null
+++ b/rt/share/html/Callbacks/RTx-Calendar/Elements/Header/Head
@@ -0,0 +1,2 @@
+<link rel="stylesheet" href="<%$RT::WebPath%>/NoAuth/css/calendar.css" type="text/css" media="all" />
+
diff --git a/rt/share/html/Callbacks/RTx-Calendar/Ticket/Elements/Tabs/Default b/rt/share/html/Callbacks/RTx-Calendar/Ticket/Elements/Tabs/Default
new file mode 100644
index 000000000..cb46fdaf6
--- /dev/null
+++ b/rt/share/html/Callbacks/RTx-Calendar/Ticket/Elements/Tabs/Default
@@ -0,0 +1,19 @@
+<%init>
+my $args;
+$args= "?" . $m->comp(
+ '/Elements/QueryString',
+ Query => $ARGS{'Query'} || $session{'CurrentSearchHash'}->{'Query'},
+ Format => $ARGS{'Format'} || $session{'CurrentSearchHash'}->{'Format'},
+ OrderBy => $ARGS{'OrderBy'} || $session{'CurrentSearchHash'}->{'OrderBy'},
+ Order => $ARGS{'Order'} || $session{'CurrentSearchHash'}->{'Order'},
+ Page => $ARGS{'Page'} || $session{'CurrentSearchHash'}->{'Page'},
+ Rows => $ARGS{'Rows'},
+ ) if ($ARGS{'Query'} or $session{'CurrentSearchHash'}->{'Query'});
+$args ||= '';
+
+$tabs->{'zz'} = { title =>loc("Calendar"),
+ path => "Search/Calendar.html$args" };
+</%init>
+<%args>
+$tabs
+</%args>
diff --git a/rt/share/html/Callbacks/RTx-Calendar/User/Elements/Tabs/Default b/rt/share/html/Callbacks/RTx-Calendar/User/Elements/Tabs/Default
new file mode 100644
index 000000000..06413e278
--- /dev/null
+++ b/rt/share/html/Callbacks/RTx-Calendar/User/Elements/Tabs/Default
@@ -0,0 +1,9 @@
+<%init>
+ $tabs->{'z'} = { title =>loc("Calendar"),
+ path => "Prefs/Calendar.html" };
+</%init>
+<%args>
+$tabs
+$current_subtab => undef
+$Searches => undef
+</%args>
diff --git a/rt/share/html/Dashboards/Elements/HiddenSearches b/rt/share/html/Dashboards/Elements/HiddenSearches
index aa3a67ebb..753d2fe49 100644
--- a/rt/share/html/Dashboards/Elements/HiddenSearches
+++ b/rt/share/html/Dashboards/Elements/HiddenSearches
@@ -50,6 +50,9 @@
$Dashboard
</%args>
<%init>
+# eliminate deleted searches (id=0) because they confuse this logic
+@searches = grep { $_->Id } @searches;
+
return if @searches == 0;
my @display;
diff --git a/rt/share/html/Dashboards/Render.html b/rt/share/html/Dashboards/Render.html
index 1893b533f..ba01a9d2e 100644
--- a/rt/share/html/Dashboards/Render.html
+++ b/rt/share/html/Dashboards/Render.html
@@ -110,10 +110,11 @@ for my $sub ($session{'CurrentUser'}->UserObj->Attributes->Named('Subscription')
last;
}
-# otherwise honor their search preferences.. otherwise 20 rows
-if (!$rows) {
+# otherwise honor their search preferences.. otherwise 50 rows
+# $rows == 0 means unlimited, which we don't want to ignore from above
+unless (defined($rows)) {
my $prefs = $session{'CurrentUser'}->UserObj->Preferences("SearchDisplay") || {};
- $rows = defined($prefs->{'RowsPerPage'}) ? $prefs->{'RowsPerPage'} : 20;
+ $rows = defined($prefs->{'RowsPerPage'}) ? $prefs->{'RowsPerPage'} : 50;
}
my $title = loc 'Dashboard [_1]', $DashboardObj->Name;
diff --git a/rt/share/html/Download/CustomFieldValue/dhandler b/rt/share/html/Download/CustomFieldValue/dhandler
index 218de33c8..d8c703904 100644
--- a/rt/share/html/Download/CustomFieldValue/dhandler
+++ b/rt/share/html/Download/CustomFieldValue/dhandler
@@ -63,7 +63,10 @@ unless ($OCFV->id) {
my $content_type = $OCFV->ContentType || 'text/plain';
-unless (RT->Config->Get('TrustHTMLAttachments')) {
+if (RT->Config->Get('AlwaysDownloadAttachments')) {
+ $r->headers_out->{'Content-Disposition'} = "attachment; filename=" . $OCFV->Content;
+}
+elsif (!RT->Config->Get('TrustHTMLAttachments')) {
$content_type = 'text/plain' if ($content_type =~ /^text\/html/i);
}
diff --git a/rt/share/html/Elements/AddCustomers b/rt/share/html/Elements/AddCustomers
new file mode 100644
index 000000000..aaf8ca8ba
--- /dev/null
+++ b/rt/share/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/share/html/Elements/CalendarEvent b/rt/share/html/Elements/CalendarEvent
new file mode 100644
index 000000000..3a6b00bb8
--- /dev/null
+++ b/rt/share/html/Elements/CalendarEvent
@@ -0,0 +1,129 @@
+<%args>
+$Date => undef
+$Object => undef
+$DateTypes => undef
+</%args>
+<div class="tooltip">
+<small>
+
+% if ($IsReminder and RTx::Calendar::LocalDate($Object->DueObj->Unix) eq $today) {
+ <img src="<%$RT::WebImagesURL%>/reminder.png" />
+
+% } elsif ($DateTypes->{Resolved}
+% and RTx::Calendar::LocalDate($Object->ResolvedObj->Unix) eq $today) {
+ <img src="<%$RT::WebImagesURL%>/resolved.png" />
+
+% } elsif ($DateTypes->{Starts} and $DateTypes->{Due}
+% and RTx::Calendar::LocalDate($Object->StartsObj->Unix) eq $today and RTx::Calendar::LocalDate($Object->DueObj->Unix) eq $today ) {
+ <img src="<%$RT::WebImagesURL%>/starts_due.png" />
+
+% } elsif ($DateTypes->{Due} and $DateTypes->{Created}
+% and RTx::Calendar::LocalDate($Object->DueObj->Unix) eq $today and RTx::Calendar::LocalDate($Object->CreatedObj->Unix) eq $today ) {
+ <img src="<%$RT::WebImagesURL%>/created_due.png" />
+
+% } elsif ($DateTypes->{Starts}
+% and RTx::Calendar::LocalDate($Object->StartsObj->Unix) eq $today) {
+ <img src="<%$RT::WebImagesURL%>/starts.png" />
+
+% } elsif ($DateTypes->{Due}
+% and RTx::Calendar::LocalDate($Object->DueObj->Unix) eq $today) {
+ <img src="<%$RT::WebImagesURL%>/due.png" />
+
+% } elsif ($DateTypes->{Created}
+% and RTx::Calendar::LocalDate($Object->CreatedObj->Unix) eq $today) {
+ <img src="<%$RT::WebImagesURL%>/created.png" />
+
+% } elsif ($DateTypes->{Started}
+% and RTx::Calendar::LocalDate($Object->StartedObj->Unix) eq $today) {
+ <img src="<%$RT::WebImagesURL%>/started.png" />
+
+% } elsif ($DateTypes->{LastUpdated}
+% and RTx::Calendar::LocalDate($Object->LastUpdatedObj->Unix) eq $today) {
+ <img src="<%$RT::WebImagesURL%>/updated.png" />
+
+% }
+
+ <a href="<%$RT::WebPath%>/Ticket/Display.html?id=<%$TicketId%>">
+ <% $Object->QueueObj->Name %> #<% $TicketId %>
+ <% $display_owner ? 'by ' . $Object->OwnerObj->Name : '' %>
+ <% length($Object->Subject) > 80 ? substr($Object->Subject, 0, 77) . "..." : $Object->Subject %></a></small><br />
+ <span class="tip">
+ <a href="<%$RT::WebPath%>/Ticket/Display.html?id=<%$TicketId%>">
+ <% $Object->QueueObj->Name %> #<% $TicketId %>
+ </a>
+ :</strong> <% $subject%><br />
+ <br />
+
+%# logic taken from Ticket/Search/Results.tsv
+% foreach my $attr (@display_fields) {
+% my $value;
+%
+% if ($attr =~ /(.*)->ISO$/ and $Object->$1->Unix <= 0) {
+% $value = '-';
+% } else {
+% my $method = '$Object->'.$attr.'()';
+% $method =~ s/->ISO\(\)$/->ISO( Timezone => 'user' )/;
+% $value = eval $method;
+% if ($@) {die "<b>Check your CalendarPopupFields config in etc/RT_SiteConfig.pm</b>.<br /><br />Failed to find \"$attr\" - ". $@};
+% }
+ <strong><&|/l&><% $label_of{$attr} %></&>:</strong> <% $value %><br />
+% }
+
+<br />
+ </span>
+</div>
+
+<%init>
+use RTx::Calendar;
+
+my $today = $Date->strftime("%F");
+
+my $TicketId;
+
+my $ticket;
+my $subject;
+my $IsReminder;
+
+if ($Object->Type eq 'reminder') {
+ $IsReminder = 1;
+ if ($Object->RefersTo->First) {
+ $ticket = $Object->RefersTo->First->TargetObj;
+ $TicketId = $ticket->Id;
+ $subject = $Object->Subject . " (" . $ticket->Subject . ")";
+ }
+} else {
+ $TicketId = $Object->Id;
+ $subject = $Object->Subject;
+}
+
+my $display_owner = $RT::CalendarDisplayOwner;
+$display_owner ||= RT->Config->Get('CalendarDisplayOwner')
+ if RT->can('Config');
+
+
+# 3.6 config
+my @display_fields = @RT::CalendarPopupFields;
+
+# 3.8 config
+# the if condition is weird but it doesn't work with 3.8.0 without the last part
+@display_fields = RT->Config->Get('CalendarPopupFields')
+ if 0 == @display_fields and RT->can('Config') and RT->Config->Get('CalendarPopupFields');
+
+# default
+if (0 == @display_fields) {
+ @display_fields = qw(OwnerObj->Name CreatedObj->ISO StartsObj->ISO
+ StartedObj->ISO LastUpdatedObj->ISO DueObj->ISO
+ ResolvedObj->ISO Status Priority
+ Requestors->MemberEmailAddressesAsString);
+}
+
+
+my %label_of;
+for my $field (@display_fields) {
+ my $label = $field;
+ $label =~ s'Obj-.(?:AsString|Name|ISO)''g;
+ $label =~ s'-\>MemberEmailAddressesAsString''g;
+ $label_of{$field} = $label;
+}
+
+</%init>
diff --git a/rt/share/html/Elements/CollectionAsTable/Row b/rt/share/html/Elements/CollectionAsTable/Row
index fa7474b6c..a1af9f383 100644
--- a/rt/share/html/Elements/CollectionAsTable/Row
+++ b/rt/share/html/Elements/CollectionAsTable/Row
@@ -54,9 +54,10 @@ $Depth => undef
$Warning => undef
$ColumnMap => {}
$Class => 'RT__Ticket'
+$Classes => ''
</%ARGS>
<%init>
-$m->out( '<tr class="'
+$m->out( '<tr class="' . $Classes . ' '
. ( $Warning ? 'warnline' : $i % 2 ? 'oddline' : 'evenline' ) . '" >'
. "\n" );
use HTML::Entities;
diff --git a/rt/share/html/Elements/CollectionList b/rt/share/html/Elements/CollectionList
index 6f21420f5..4e06e3f0a 100644
--- a/rt/share/html/Elements/CollectionList
+++ b/rt/share/html/Elements/CollectionList
@@ -54,7 +54,9 @@ if (!$Collection && $Class eq 'RT::Tickets') {
my $TotalFound = $Collection->CountAll();
return '' if !$TotalFound && !$ShowEmpty;
-if ( @OrderBy ) {
+# XXX: ->{'order_by'} is hacky, but there is no way to check if
+# collection is ordered or not
+if ( @OrderBy && ($AllowSorting || !$Collection->{'order_by'}) ) {
if ( $OrderBy[0] =~ /\|/ ) {
@OrderBy = split /\|/, $OrderBy[0];
@Order = split /\|/,$Order[0];
@@ -121,14 +123,30 @@ if ( $ShowHeader ) {
my ($i, $column_map) = (0, {});
while ( my $record = $Collection->Next ) {
# Every ten rows, flush the buffer and put something on the page.
- $m->flush_buffer unless ++$i % 10;
+ #broken w/FS, causes rows to be output prematurely
+ #$m->flush_buffer unless ++$i % 10;
+ ++$i;
+
+ my $warning = 0;
+ my $Classes = '';
+
+ $m->callback(
+ CallbackName => 'EachRow',
+ Record => $record,
+ Warning => \$warning,
+ Classes => \$Classes,
+ Format => \@Format,
+ );
+
$m->comp('/Elements/CollectionAsTable/Row',
- i => $i,
- Format => \@Format,
- record => $record,
- maxitems => $maxitems,
+ i => $i,
+ Format => \@Format,
+ record => $record,
+ maxitems => $maxitems,
ColumnMap => $column_map,
Class => $Class,
+ Warning => $warning,
+ Classes => $Classes,
);
}
diff --git a/rt/share/html/Elements/ColumnMap b/rt/share/html/Elements/ColumnMap
index 71517e063..a1475a99d 100644
--- a/rt/share/html/Elements/ColumnMap
+++ b/rt/share/html/Elements/ColumnMap
@@ -92,6 +92,26 @@ my $COLUMN_MAP = {
value => sub { return $_[0]->LastUpdatedByObj->Name }
},
+ CustomField => {
+ attribute => sub { return shift @_ },
+ title => sub { return pop @_ },
+ value => sub {
+ # Display custom field contents, separated by newlines.
+ # For Image custom fields we also show a thumbnail here.
+
+ my $values = $_[0]->CustomFieldValues( $_[-1] );
+ my @values = map {
+ (
+ ($_->CustomFieldObj->Type eq 'Image')
+ ? \($m->scomp( '/Elements/ShowCustomFieldImage', Object => $_ ))
+ : $_->Content
+ ),
+ \'<br />',
+ } @{ $values->ItemsArrayRef };
+ pop @values; # Remove that last <br />
+ return @values;
+ },
+ },
CheckBox => {
title => sub {
@@ -136,8 +156,12 @@ my $COLUMN_MAP = {
$_ => { value => sub { return \$value } };
} qw(WebPath WebBaseURL WebURL)),
+ WebRequestPath => { value => sub { substr( $m->request_path, 1 ) } },
+ WebRequestPathDir => { value => sub { substr( $m->request_comp->dir_path, 1 ) } },
};
+$COLUMN_MAP->{'CF'} = $COLUMN_MAP->{'CustomField'};
+
</%ONCE>
<%INIT>
$m->callback( COLUMN_MAP => $COLUMN_MAP, CallbackName => 'Once', CallbackOnce => 1 );
diff --git a/rt/share/html/Elements/CreateTicket b/rt/share/html/Elements/CreateTicket
index 9c8f3aadf..fd2ba9e53 100755
--- a/rt/share/html/Elements/CreateTicket
+++ b/rt/share/html/Elements/CreateTicket
@@ -45,6 +45,9 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<form action="<% RT->Config->Get('WebPath') %>/Ticket/Create.html" name="CreateTicketInQueue" id="CreateTicketInQueue">
-<&|/l, $m->scomp('/Elements/SelectNewTicketQueue', OnChange => 'document.CreateTicketInQueue.submit()')&><input type="submit" class="button" value="New ticket in" />&nbsp;[_1]</&>
+<form action="<% RT->Config->Get('WebPath') %><% $SendTo %>" name="CreateTicketInQueue" id="CreateTicketInQueue">
+<&|/l, $m->scomp('/Elements/SelectNewTicketQueue', OnChange => 'document.CreateTicketInQueue.submit()', SendTo => $SendTo ) &><input type="submit" class="button" value="New ticket in" />&nbsp;[_1]</&>
</form>
+<%ARGS>
+$SendTo => '/Ticket/Create.html',
+</%ARGS>
diff --git a/rt/share/html/Elements/EditCustomFieldDate b/rt/share/html/Elements/EditCustomFieldDate
new file mode 100644
index 000000000..b6359d7e0
--- /dev/null
+++ b/rt/share/html/Elements/EditCustomFieldDate
@@ -0,0 +1,62 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2008 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/copyleft/gpl.html.
+%#
+%#
+%# 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 }}}
+% my $name = $NamePrefix.$CustomField->Id.'-Values';
+<& /Elements/SelectDate, Name => "$name", ShowTime => 0, current => 0 &> (<%$DateObj->AsString%>)
+
+<%INIT>
+my $DateObj = new RT::Date ( $session{'CurrentUser'} );
+$DateObj->Set( Format => 'ISO', Value => $Default );
+</%INIT>
+<%ARGS>
+$Object => undef
+$CustomField => undef
+$NamePrefix => undef
+$Default => undef
+$Values => undef
+$MaxValues => 1
+</%ARGS>
diff --git a/rt/share/html/Elements/EditCustomFieldSelect b/rt/share/html/Elements/EditCustomFieldSelect
index 8fe79f9f9..30b06dbd1 100644
--- a/rt/share/html/Elements/EditCustomFieldSelect
+++ b/rt/share/html/Elements/EditCustomFieldSelect
@@ -52,7 +52,7 @@
% my @category;
% my $id = $NamePrefix . $CustomField->Id;
% my $out = $m->scomp('SELF:options', %ARGS, SelectedRef => \$selected, CategoryRef => \@category);
-% if (@category and not $CustomField->BasedOnObj->id) {
+% if (!$HideCategory and @category and not $CustomField->BasedOnObj->id) {
<script type="text/javascript" src="<%RT->Config->Get('WebPath')%>/NoAuth/js/cascaded.js"></script>
%# XXX - Hide this select from w3m?
<select onchange="filter_cascade('<% $id %>-Values', this.value)" name="<% $id %>-Category" class="CF-<%$CustomField->id%>-Edit">
@@ -108,6 +108,7 @@ $Default => undef
$Values => undef
$Multiple => 0
$Rows => undef
+$HideCategory => 0
</%ARGS>
<%METHOD options>
diff --git a/rt/share/html/Elements/EditCustomers b/rt/share/html/Elements/EditCustomers
new file mode 100644
index 000000000..68efb5f40
--- /dev/null
+++ b/rt/share/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/share/html/Elements/EditLinks b/rt/share/html/Elements/EditLinks
index 637762e1b..90acb4692 100755
--- a/rt/share/html/Elements/EditLinks
+++ b/rt/share/html/Elements/EditLinks
@@ -52,7 +52,7 @@
<table>
<tr>
- <td class="labeltop"><&|/l&>Depends on</&>:</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Depends on'), Relation => 'DependsOn' &>:</td>
<td class="value">
% while (my $link = $Object->DependsOn->Next) {
<input type="checkbox" class="checkbox" name="DeleteLink--<%$link->Type%>-<%$link->Target%>" value="1" />
@@ -61,7 +61,7 @@
</td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Depended on by</&>:</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Depended on by'), Relation => 'DependedOnBy' &>:</td>
<td class="value">
% while (my $link = $Object->DependedOnBy->Next) {
<input type="checkbox" class="checkbox" name="DeleteLink-<%$link->Base%>-<%$link->Type%>-" value="1" />
@@ -70,7 +70,7 @@
</td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Parents</&>:</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Parents'), Relation => 'Parents' &>:</td>
<td class="value">
% while (my $link = $Object->MemberOf->Next) {
<input type="checkbox" class="checkbox" name="DeleteLink--<%$link->Type%>-<%$link->Target%>" value="1" />
@@ -79,7 +79,7 @@
</td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Children</&>:</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Children'), Relation => 'Children' &>:</td>
<td class="value">
% while (my $link = $Object->Members->Next) {
<input type="checkbox" class="checkbox" name="DeleteLink-<%$link->Base%>-<%$link->Type%>-" value="1" />
@@ -88,7 +88,7 @@
</td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Refers to</&>:</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Refers to'), Relation => 'RefersTo' &>:</td>
<td class="value">
% while (my $link = $Object->RefersTo->Next) {
<input type="checkbox" class="checkbox" name="DeleteLink--<%$link->Type%>-<%$link->Target%>" value="1" />
@@ -97,7 +97,7 @@
</td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Referred to by</&>:</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Referred to by'), Relation => 'ReferredToBy' &>:</td>
<td class="value">
% while (my $link = $Object->ReferredToBy->Next) {
% # Skip reminders
@@ -134,27 +134,27 @@
</tr>
% }
<tr>
- <td class="label"><&|/l&>Depends on</&>:</td>
+ <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Depends on'), Relation => 'DependsOn' &>:</td>
<td class="entry"><input name="<%$id%>-DependsOn" /></td>
</tr>
<tr>
- <td class="label"><&|/l&>Depended on by</&>:</td>
+ <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Depended on by'), Relation => 'DependedOnBy' &>:</td>
<td class="entry"><input name="DependsOn-<%$id%>" /></td>
</tr>
<tr>
- <td class="label"><&|/l&>Parents</&>:</td>
+ <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Parents'), Relation => 'Parents' &>:</td>
<td class="entry"><input name="<%$id%>-MemberOf" /></td>
</tr>
<tr>
- <td class="label"><&|/l&>Children</&>:</td>
+ <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Children'), Relation => 'Children' &>:</td>
<td class="entry"> <input name="MemberOf-<%$id%>" /></td>
</tr>
<tr>
- <td class="label"><&|/l&>Refers to</&>:</td>
+ <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Refers to'), Relation => 'RefersTo' &>:</td>
<td class="entry"><input name="<%$id%>-RefersTo" /></td>
</tr>
<tr>
- <td class="label"><&|/l&>Referred to by</&>:</td>
+ <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Referred to by'), Relation => 'ReferredToBy' &>:</td>
<td class="entry"> <input name="RefersTo-<%$id%>" /></td>
</tr>
% $m->callback( CallbackName => 'NewLink' );
diff --git a/rt/share/html/Elements/EditPassword b/rt/share/html/Elements/EditPassword
new file mode 100644
index 000000000..3b0ec0b32
--- /dev/null
+++ b/rt/share/html/Elements/EditPassword
@@ -0,0 +1,34 @@
+% unless ( $cond{'CanSet'} ) {
+<% $cond{'Reason'} %><br />
+% } else {
+<table>
+
+% if ( $cond{'RequireCurrent'} ) {
+<tr>
+<td><&|/l&>Your current password</&>:</td>
+<td><input type="password" name="<% $Name[0] %>" size="16" autocomplete="off" /></td>
+</tr>
+% }
+
+<tr>
+<td><&|/l&>New password</&>:</td>
+<td><input type="password" name="<% $Name[1] %>" size="16" autocomplete="off" /></td>
+</tr>
+
+<tr>
+<td><&|/l&>Retype Password</&>:</td>
+<td><input type="password" name="<% $Name[2] %>" size="16" autocomplete="off" /></td>
+</tr>
+
+</table>
+% }
+
+<%ARGS>
+$User
+@Name => qw(CurrentPass NewPass1 NewPass2)
+</%ARGS>
+<%INIT>
+
+my %cond = $User->CurrentUserRequireToSetPassword;
+
+</%INIT>
diff --git a/rt/share/html/Elements/Footer b/rt/share/html/Elements/Footer
index 2fcdee949..59547e238 100755
--- a/rt/share/html/Elements/Footer
+++ b/rt/share/html/Elements/Footer
@@ -48,25 +48,6 @@
%# End of div#body from /Elements/PageLayout
</div>
% $m->callback( %ARGS );
-<div id="footer">
-% if ($m->{'rt_base_time'}) {
- <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)]);
diff --git a/rt/share/html/Elements/Header b/rt/share/html/Elements/Header
index 953efcb22..72e3e7220 100755
--- a/rt/share/html/Elements/Header
+++ b/rt/share/html/Elements/Header
@@ -45,61 +45,67 @@
%# 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">
+<& /elements/header.html, {
+ 'title' => $Title,
+ 'head' => $head,
+ 'etc' => $etc,
+ 'nobr' => 1,
+ 'nocss' => 1,
+ }
+&>
+<%INIT>
+$r->headers_out->{'Pragma'} = 'no-cache';
+$r->headers_out->{'Cache-control'} = 'no-cache';
-<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head>
-<title><%$Title%></title>
+my $id = $m->request_comp->path;
+$id =~ s|^/||g;
+$id =~ s|/|-|g;
+$id =~ s|\.html$||g;
+$id =~ s|index$||g
+ if $id ne 'index';
+$id =~ s|-$||g;
+my $head = '';
-% if ($Refresh && $Refresh =~ /^(\d+)/ && $1 > 0) {
- <meta http-equiv="refresh" content="<% $Refresh %>" />
-% }
+if ($Refresh && $Refresh =~ /^(\d+)/ && $1 > 0) {
+ $head .= '<meta http-equiv="refresh" content="$Refresh" />';
+}
-<link rel="shortcut icon" href="<%RT->Config->Get('WebImagesURL')%>/favicon.png" type="image/png" />
-<link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/<% RT->Config->Get( 'WebDefaultStylesheet', $session{'CurrentUser'} ) %>/main<% RT->Config->Get('DevelMode')? '' : '-squished' %>.css" type="text/css" media="all" />
-<link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/print.css" type="text/css" media="print" />
+my $WebPath = RT->Config->Get('WebPath');
+my $WebImagesURL = RT->Config->Get('WebImagesURL');
+my $WebDefaultStylesheet =
+ RT->Config->Get('WebDefaultStylesheet', $session{'CurrentUser'});
+my $squished = RT->Config->Get('DevelMode') ? '' : '-squished';
-% for (keys %{$LinkRel || {}}) {
- <link rel="<% $_ %>" href="<% RT->Config->Get('WebPath') . $LinkRel->{$_} %>" />
-% }
+$head .= <<END;
+<link rel="shortcut icon" href="$WebImagesURL/favicon.png" type="image/png" />
+<link rel="stylesheet" href="$WebPath/NoAuth/css/$WebDefaultStylesheet/main$squished.css" type="text/css" media="all" />
+<link rel="stylesheet" href="$WebPath/NoAuth/css/print.css" type="text/css" media="print" />
+END
-% if ( $RSSAutoDiscovery ) {
- <link rel="alternate" href="<%$RSSAutoDiscovery%>" type="application/rss+xml" title="RSS RT Search" />
-% }
+for (keys %{$LinkRel || {}}) {
+ $head .= qq(<link rel="$_" href="$WebPath) . $LinkRel->{$_} . '" />';
+}
-% if ($JavaScript) {
-<& HeaderJavascript, focus => $Focus, onload => $onload &>
-% }
+if ( $RSSAutoDiscovery ) {
+ $head .= qq(<link rel="alternate" href="$RSSAutoDiscovery" type="application/rss+xml" title="RSS RT Search" />);
+}
-% my $stylesheet_plugin = "/NoAuth/css/". RT->Config->Get( 'WebDefaultStylesheet', $session{'CurrentUser'} )."/InHeader";
-% if ($m->comp_exists($stylesheet_plugin) ) {
-<& $stylesheet_plugin &>
-% }
-% $m->callback( %ARGS, CallbackName => 'Head' );
+if ($JavaScript) {
+ $head .= $m->scomp('HeaderJavascript', focus => $Focus, onload => $onload);
+}
-</head>
- <body<% $id && qq[ id="comp-$id"] |n %>>
+my $stylesheet_plugin = "/NoAuth/css/$WebDefaultStylesheet/InHeader";
+if ($m->comp_exists($stylesheet_plugin) ) {
+ $head .= $m->scomp($stylesheet_plugin);
+}
-% if ($ShowBar) {
-<& /Elements/Logo, %ARGS &>
+# $m->callback( %ARGS, CallbackName => 'Head' );
+$head .= $m->scomp( '/Elements/Callback', _CallbackName => 'Head', %ARGS );
-<div id="quickbar">
- <& /Elements/PersonalQuickbar, %ARGS &>
-% }
+my $etc = '';
+$etc .= qq[ id="comp-$id"] if $id;
-<%INIT>
-$r->headers_out->{'Pragma'} = 'no-cache';
-$r->headers_out->{'Cache-control'} = 'no-cache';
-
-my $id = $m->request_comp->path;
-$id =~ s|^/||g;
-$id =~ s|/|-|g;
-$id =~ s|\.html$||g;
-$id =~ s|index$||g
- if $id ne 'index';
-$id =~ s|-$||g;
</%INIT>
<%ARGS>
diff --git a/rt/share/html/Elements/HeaderJavascript b/rt/share/html/Elements/HeaderJavascript
index 6ee88a13b..c4eb17504 100644
--- a/rt/share/html/Elements/HeaderJavascript
+++ b/rt/share/html/Elements/HeaderJavascript
@@ -111,7 +111,7 @@ $onload => undef
typeField.setAttribute('value', 'text/html');
textArea.parentNode.appendChild(typeField);
- var oFCKeditor = new FCKeditor( textArea.name, '100%', <% RT->Config->Get('MessageBoxRichTextHeight') %> );
+ var oFCKeditor = new FCKeditor( textArea.name, '100%', <% RT->Config->Get('MessageBoxRichTextHeight', $session{CurrentUser} ) %> );
oFCKeditor.BasePath = "<%RT->Config->Get('WebPath')%>/NoAuth/RichText/";
oFCKeditor.ReplaceTextarea();
}
diff --git a/rt/share/html/Elements/Login b/rt/share/html/Elements/Login
index 8dfbe51d1..e768b0e7a 100755
--- a/rt/share/html/Elements/Login
+++ b/rt/share/html/Elements/Login
@@ -64,6 +64,21 @@ my $form_action = defined $goto ? $goto
: defined $req_uri ? $req_uri
: RT->Config->Get('WebPath')
;
+
+# sanitize $form_action
+my $uri = URI->new($form_action);
+
+# You get undef scheme with a relative uri like "/Search/Build.html"
+unless (!defined($uri->scheme) || $uri->scheme eq 'http' || $uri->scheme eq 'https') {
+ $form_action = RT->Config->Get('WebPath');
+}
+
+# Make sure we're logging in to the same domain
+# You can get an undef authority with a relative uri like "index.html"
+my $uri_base_url = URI->new(RT->Config->Get('WebBaseURL'));
+unless (!defined($uri->authority) || $uri->authority eq $uri_base_url->authority) {
+ $form_action = RT->Config->Get('WebPath');
+}
</%INIT>
% $m->callback( %ARGS, CallbackName => 'Header' );
diff --git a/rt/share/html/Elements/Logo b/rt/share/html/Elements/Logo
index 359738b5e..e6cb1ad4b 100644
--- a/rt/share/html/Elements/Logo
+++ b/rt/share/html/Elements/Logo
@@ -46,10 +46,11 @@
%#
%# END BPS TAGGED BLOCK }}}
<div id="logo">
-<a href="http://bestpractical.com"><img
+<a href="<%$ARGS{'LogoLinkURL'}||RT->Config->Get('LogoLinkURL')%>"><img
src="<%$ARGS{'LogoURL'}||RT->Config->Get('LogoURL')%>"
- alt="<% loc("Best Practical Solutions, LLC corporate logo") %>"
- width="177" height="33" /></a>
+ alt="<%loc($ARGS{'LogoAltText'}||RT->Config->Get('LogoAltText'))%>"
+ width="<%$ARGS{'LogoImageWidth'}||RT->Config->Get('LogoImageWidth')%>"
+ height="<%$ARGS{'LogoImageHeight'}||RT->Config->Get('LogoImageHeight')%>" /></a>
% if ( $ShowName ) {
<span class="rtname"><% $Name || loc("RT for [_1]", RT->Config->Get('rtname')) %></span>
% }
diff --git a/rt/share/html/Elements/MessageBox b/rt/share/html/Elements/MessageBox
index 4985b23e3..854528c23 100755
--- a/rt/share/html/Elements/MessageBox
+++ b/rt/share/html/Elements/MessageBox
@@ -46,7 +46,7 @@
%#
%# END BPS TAGGED BLOCK }}}
<textarea class="messagebox" cols="<% $Width %>" rows="<% $Height %>" <% $wrap_type |n %> name="<% $Name %>" id="<% $Name %>">\
-% $m->callback( %ARGS );
+% $m->callback( %ARGS, SignatureRef => \$signature );
<% $Default || '' %><% $message %><% $signature %></textarea>
% $m->callback( %ARGS, CallbackName => 'AfterTextArea' );
<%INIT>
diff --git a/rt/share/html/Elements/MyCalendar b/rt/share/html/Elements/MyCalendar
new file mode 100644
index 000000000..a54ab39d6
--- /dev/null
+++ b/rt/share/html/Elements/MyCalendar
@@ -0,0 +1,78 @@
+<&|/Widgets/TitleBox,
+ title => loc("Calendar"),
+ title_href => "Search/Calendar.html" &>
+
+<table class="rtxcalendar">
+<thead>
+<tr>
+% my $date = $begin->clone;
+% while ( $date <= $end ) {
+<th width="14%"><%$rtdate->GetWeekday($date->day_of_week % 7)%></th>
+% $date = $set->next($date);
+% }
+</tr>
+</thead>
+<tbody>
+<tr>
+% $date = $begin->clone;
+% while ($date <= $end) {
+<td>
+<p class="date"><%$date->day%></p>
+% for my $t (@{ $Tickets{$date->strftime("%F")} }) {
+<& /Elements/CalendarEvent, Object => $t, Date => $date, DateTypes => \%DateTypes &>
+% }
+</td>
+% $date = $set->next($date);
+% }
+</tr>
+</tbody>
+</table>
+
+ </&>
+
+<%INIT>
+
+use RTx::Calendar;
+
+my $title = loc("Calendar");
+
+my $rtdate = RT::Date->new($session{'CurrentUser'});
+
+my @DateTypes = qw/Created Starts Started Due LastUpdated Resolved/;
+
+my $today = DateTime->today;
+
+# this line is used to debug MyCalendar
+# $today = DateTime->new(year => 2007, month => 4, day => 11);
+
+my $begin = $today->clone->subtract( days => 3);
+my $end = $today->clone->add( days => 3);
+
+# use this to loop over days until $end
+my $set = DateTime::Set->from_recurrence(
+ next => sub { $_[0]->truncate( to => 'day' )->add( days => 1 ) }
+);
+
+my $Query = "( Status = 'new' OR Status = 'open' OR Status = 'stalled')
+ AND ( Owner = '" . $session{CurrentUser}->Id ."' OR Owner = 'Nobody' )
+ AND ( Type = 'reminder' OR 'Type' = 'ticket' )";
+my $Format = "__Starts__ __Due__";
+
+if ( my $Search = RTx::Calendar::SearchDefaultCalendar($session{CurrentUser}) ) {
+ $Format = $Search->SubValue('Format');
+ $Query = $Search->SubValue('Query');
+}
+
+# we search all date types in Format string
+my @Dates = grep { $Format =~ m/__${_}(Relative)?__/ } @DateTypes;
+
+# used to display or not a date in Element/CalendarEvent
+my %DateTypes = map { $_ => 1 } @Dates;
+
+$Query .= RTx::Calendar::DatesClauses(\@Dates, $begin->strftime("%F"), $end->strftime("%F"));
+
+# print STDERR $Query, "\n";
+
+my %Tickets = RTx::Calendar::FindTickets($session{'CurrentUser'}, $Query, \@Dates);
+
+</%INIT>
diff --git a/rt/share/html/Elements/MyReminders b/rt/share/html/Elements/MyReminders
index 25fdf5d48..53e3f99c7 100755
--- a/rt/share/html/Elements/MyReminders
+++ b/rt/share/html/Elements/MyReminders
@@ -47,6 +47,7 @@
%# END BPS TAGGED BLOCK }}}
%# DEPRECATED
<&|/Widgets/TitleBox,
+ class => 'reminders',
title => loc("Reminders") &>
<table width="100%">
% my $i =0;
diff --git a/rt/share/html/Elements/PageLayout b/rt/share/html/Elements/PageLayout
index 981e58a3c..f30d815a5 100755
--- a/rt/share/html/Elements/PageLayout
+++ b/rt/share/html/Elements/PageLayout
@@ -45,23 +45,27 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+
+<% include('/elements/init_calendar.html') |n %>
+
+% if (0) { ## new ticket via customer, and we already have a ticket search box
<div id="topactions">
% foreach my $action (reverse sort keys %{$topactions}) {
<span class="topaction" id="topaction-<%$action%>"><% $topactions->{"$action"}->{'html'} |n %></span>
% }
</div>
+% }
-%# End of div#quickbar from /Elements/Header
-</div>
-
+% 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>
<div id="page-navigation">
% my $sep = 0;
% my $postsep = 0;
diff --git a/rt/share/html/Elements/RT__CustomField/ColumnMap b/rt/share/html/Elements/RT__CustomField/ColumnMap
new file mode 100644
index 000000000..6d8d76a4c
--- /dev/null
+++ b/rt/share/html/Elements/RT__CustomField/ColumnMap
@@ -0,0 +1,178 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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>
+my $COLUMN_MAP = {
+ id => {
+ title => '#', # loc
+ attribute => 'id',
+ align => 'right',
+ value => sub { return $_[0]->id },
+ },
+ Disabled => {
+ title => \'&nbsp;',
+ attribute => 'Disabled',
+ value => sub { return $_[0]->Disabled? $_[0]->loc('Disabled'): $_[0]->loc('Enabled') },
+ },
+
+ map(
+ { my $c = $_; $c => {
+ title => $c, attribute => $c,
+ value => sub { return $_[0]->$c() },
+ } }
+ qw(Name Description Type LookupType Pattern)
+ ),
+ map(
+ { my $c = $_; my $short = $c; $short =~ s/^Friendly//;
+ $c => {
+ title => $short, attribute => $short,
+ value => sub { return $_[0]->$c() },
+ } }
+ qw(FriendlyLookupType FriendlyType FriendlyPattern)
+ ),
+ MaxValues => {
+ title => 'MaxValues', # loc
+ attribute => 'MaxValues',
+ value => sub {
+ my $v = $_[0]->MaxValues;
+ return !$v ? $_[0]->loc('unlimited') : $v == 0 ? $_[0]->loc('one') : $v;
+ },
+ },
+ AppliedTo => {
+ title => 'Applied', # loc
+ value => sub {
+ if ( $_[0]->IsApplied ) {
+ return $_[0]->loc('Global');
+ }
+
+ my $collection = $_[0]->AppliedTo;
+ return '' unless $collection;
+
+ $collection->RowsPerPage(10);
+
+ my $found = 0;
+ my $res = '';
+ while ( my $record = $collection->Next ) {
+ $res .= ', ' if $res;
+
+ my $id = '';
+ $id = $record->Name if $record->can('Name');
+ $id ||= "#". $record->id;
+ $res .= $id;
+
+ $found++;
+ }
+ $res .= ', ...' if $found >= 10;
+ return $res;
+ },
+
+ },
+ RemoveCheckBox => {
+ title => sub {
+ my $name = 'RemoveCustomField';
+ my $checked = $m->request_args->{ $name .'All' }? 'checked="checked"': '';
+
+ return \qq{<input type="checkbox" name="${name}All" value="1" $checked
+ onclick="setCheckbox(this.form, '$name', this.checked)" />};
+ },
+ value => sub {
+ my $id = $_[0]->id;
+ return '' if $_[0]->IsApplied;
+
+ my $name = 'RemoveCustomField';
+ my $arg = $m->request_args->{ $name };
+
+ my $checked = '';
+ if ( $arg && ref $arg ) {
+ $checked = 'checked="checked"' if grep $_ == $id, @$arg;
+ }
+ elsif ( $arg ) {
+ $checked = 'checked="checked"' if $arg == $id;
+ }
+ return \qq{<input type="checkbox" name="$name" value="$id" $checked />}
+ },
+ },
+ MoveCF => {
+ title => 'Move',
+ value => sub {
+ my $id = $_[0]->id;
+
+ my $context = $_[2] || 0;
+ return '' unless $_[0]->IsApplied( $context );
+
+ my $name = 'MoveCustomField';
+ my $args = $m->caller_args( 1 );
+ my @pass = ref $args->{'PassArguments'}
+ ? @{$args->{'PassArguments'}}
+ : ($args->{'PassArguments'});
+ my %pass = map { $_ => $args->{$_} } grep exists $args->{$_}, @pass;
+
+ my $uri = RT->Config->Get('WebPath') . $m->request_path;
+
+ my @res = (
+ \'<a href="',
+ $uri .'?'. $m->comp("/Elements/QueryString", %pass, MoveCustomFieldUp => $id ),
+ \'">', loc('[Up]'), \'</a>',
+ \' <a href="',
+ $uri .'?'. $m->comp("/Elements/QueryString", %pass, MoveCustomFieldDown => $id ),
+ \'">', loc('[Down]'), \'</a>'
+ );
+
+ return @res;
+ },
+ },
+};
+
+</%ONCE>
+<%INIT>
+$m->callback( COLUMN_MAP => $COLUMN_MAP, CallbackName => 'ColumnMap', CallbackOnce => 1 );
+return GetColumnMapEntry( Map => $COLUMN_MAP, Name => $Name, Attribute => $Attr );
+</%INIT>
diff --git a/rt/share/html/Elements/RT__Queue/ColumnMap b/rt/share/html/Elements/RT__Queue/ColumnMap
index 5c56004d1..f44ab32c3 100644
--- a/rt/share/html/Elements/RT__Queue/ColumnMap
+++ b/rt/share/html/Elements/RT__Queue/ColumnMap
@@ -70,43 +70,33 @@ my $COLUMN_MAP = {
title => 'Address', # loc
value => sub { return ($_[0]->CorrespondAddress||'-') .'/'. ($_[0]->CommentAddress||'-') },
},
- Name => {
- title => 'Name', # loc
- attribute => 'Name',
- value => sub { return $_[0]->Name() },
- },
- Description => {
- title => 'Description', # loc
- attribute => 'Description',
- value => sub { return $_[0]->Description() },
- },
- CorrespondAddress => {
- title => 'CorrespondAddress', # loc
- attribute => 'CorrespondAddress',
- value => sub { return $_[0]->CorrespondAddress() },
- },
- CommentAddress => {
- title => 'CommentAddress', # loc
- attribute => 'CommentAddress',
- value => sub { return $_[0]->CommentAddress() },
- },
- InitialPriority => {
- title => 'InitialPriority', # loc
- attribute => 'InitialPriority',
- value => sub { return $_[0]->InitialPriority() },
+
+ # SubjectTag is special as we can not sort
+ SubjectTag => {
+ title => 'SubjectTag', # loc
+ value => sub { return $_[0]->SubjectTag },
},
- FinalPriority => {
- title => 'FinalPriority', # loc
- attribute => 'FinalPriority',
- value => sub { return $_[0]->FinalPriority() },
+ Sign => {
+ title => 'Sign', # loc
+ value => sub { return $_[0]->Sign? $_[0]->loc('yes') : $_[0]->loc('no') },
},
- DefaultDueIn => {
- title => 'DefaultDueIn', # loc
- attribute => 'DefaultDueIn',
- value => sub { return $_[0]->DefaultDueIn() },
+ Encrypt => {
+ title => 'Encrypt', # loc
+ value => sub { return $_[0]->Encrypt? $_[0]->loc('yes') : $_[0]->loc('no') },
},
};
+foreach my $field (qw(
+ Name Description CorrespondAddress CommentAddress
+ InitialPriority FinalPriority DefaultDueIn
+)) {
+ $COLUMN_MAP->{$field} = {
+ title => $field,
+ attribute => $field,
+ value => sub { return $_[0]->$field() },
+ },
+}
+
</%ONCE>
<%INIT>
$m->callback( COLUMN_MAP => $COLUMN_MAP, CallbackName => 'ColumnMap', CallbackOnce => 1 );
diff --git a/rt/share/html/Elements/RT__Scrip/ColumnMap b/rt/share/html/Elements/RT__Scrip/ColumnMap
index 88b4c4bea..3e1d4074f 100644
--- a/rt/share/html/Elements/RT__Scrip/ColumnMap
+++ b/rt/share/html/Elements/RT__Scrip/ColumnMap
@@ -64,6 +64,10 @@ my $COLUMN_MAP = {
return $_[0]->loc('Global');
},
},
+ QueueId => {
+ title => 'Queue', # loc
+ value => sub { $_[0]->Queue },
+ },
Condition => {
title => 'Condition', # loc
value => sub { return $_[0]->loc( $_[0]->ScripConditionObj->Name ) },
diff --git a/rt/share/html/Elements/RT__Template/ColumnMap b/rt/share/html/Elements/RT__Template/ColumnMap
index 851cc9dec..e7c149575 100644
--- a/rt/share/html/Elements/RT__Template/ColumnMap
+++ b/rt/share/html/Elements/RT__Template/ColumnMap
@@ -67,6 +67,17 @@ my $COLUMN_MAP = {
attribute => 'Description',
value => sub { return $_[0]->Description() },
},
+ Queue => {
+ title => 'Queue', # loc
+ value => sub {
+ return $_[0]->QueueObj->Name if $_[0]->Queue;
+ return $_[0]->loc('Global');
+ },
+ },
+ QueueId => {
+ title => 'Queue', # loc
+ value => sub { $_[0]->Queue },
+ },
};
</%ONCE>
diff --git a/rt/share/html/Elements/RT__Ticket/ColumnMap b/rt/share/html/Elements/RT__Ticket/ColumnMap
index 7df471009..e848939e1 100644
--- a/rt/share/html/Elements/RT__Ticket/ColumnMap
+++ b/rt/share/html/Elements/RT__Ticket/ColumnMap
@@ -303,26 +303,6 @@ $COLUMN_MAP = {
value => sub { return \('<input type="checkbox" class="checkbox" name="UpdateTicket'.$_[0]->id.'" value="1" checked="checked" />') }
},
- CustomField => {
- attribute => sub { return shift @_ },
- title => sub { return pop @_ },
- value => sub {
- # Display custom field contents, separated by newlines.
- # For Image custom fields we also show a thumbnail here.
-
- my $values = $_[0]->CustomFieldValues( $_[-1] );
- my @values = map {
- (
- ($_->CustomFieldObj->Type eq 'Image')
- ? \($m->scomp( '/Elements/ShowCustomFieldImage', Object => $_ ))
- : $_->Content
- ),
- \'<br />',
- } @{ $values->ItemsArrayRef };
- pop @values; # Remove that last <br />
- return @values;
- },
- },
Bookmark => {
title => ' ',
value => sub {
@@ -333,9 +313,26 @@ $COLUMN_MAP = {
return \$bookmark;
},
},
-};
-$COLUMN_MAP->{'CF'} = $COLUMN_MAP->{'CustomField'};
+ Customer => {
+ title => 'Customer', #loc
+ attribute => 'Customer', #title/attribute/name... what does it all mean?
+ value => sub {
+ my $Ticket = shift;
+ my @Customers = @{ $Ticket->Customers->ItemsArrayRef };
+ my @CustResolvers = map $_->TargetURI->Resolver, @Customers;
+ my @return = ();
+ for ( 0 .. $#CustResolvers ) {
+ my $c = @CustResolvers[$_];
+ push @return, \'<A HREF="', $c->HREF, \'">', $c->AsString, \'</A>';
+ push @return, \'<BR>' if scalar(@CustResolvers) > 1
+ && $_ != $#CustResolvers;
+ }
+ @return;
+ },
+ },
+
+};
# if no GPG support, then KeyOwnerName and KeyRequestors fall back to the regular
# versions
diff --git a/rt/share/html/Elements/SelectDate b/rt/share/html/Elements/SelectDate
index 32a173db4..46092ce23 100755
--- a/rt/share/html/Elements/SelectDate
+++ b/rt/share/html/Elements/SelectDate
@@ -45,10 +45,21 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<script type="text/javascript"><!--
- onLoadHook('createCalendarLink("<% $Name %>");');
---></script>
+%# in PageLayout instead, once <% include('/elements/init_calendar.html') |n %>
<input type="text" id="<% $Name %>" name="<% $Name %>" value="<% $Value %>" size="<% $Size %>" />
+<IMG SRC="<%$fsurl%>images/calendar.png" ID="<% $Name %>_date_button" STYLE="cursor: pointer" TITLE="Select date">
+<script type="text/javascript">
+Calendar.setup({
+ inputField: <% $Name |n,js_string %>,
+% if ( defined($ShowTime) && $ShowTime ) {
+ ifFormat: "%Y-%m-%d %H:%M",
+ showsTime: true,
+% } else {
+ ifFormat: "%Y-%m-%d",
+% }
+ button: <% $Name.'_date_button' |n,js_string %>,
+});
+</script>
<%init>
unless ((defined $Default) or
($current <= 0)) {
diff --git a/rt/share/html/Elements/SelectQueue b/rt/share/html/Elements/SelectQueue
index 20a5b7d9d..c78afe9ce 100755
--- a/rt/share/html/Elements/SelectQueue
+++ b/rt/share/html/Elements/SelectQueue
@@ -51,7 +51,7 @@
<input name="<%$Name%>" size="25" value="<%$d->Name%>" class="<%$Class%>" />
% }
% else {
-<select name="<%$Name%>" <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>">
+<select name="<%$Name%>" <% ($Multiple) ? 'multiple="multiple"' : '' %> <% ($OnChange) ? 'onchange="'.$OnChange.'"' : '' |n %> class="<%$Class%>">
% if ($ShowNullOption) {
<option value="">-</option>
% }
@@ -82,6 +82,7 @@ $NamedValues => 0
$Default => 0
$Lite => 0
$OnChange => undef
+$Multiple => 0
$Class => 'select-queue'
</%args>
<%init>
diff --git a/rt/share/html/Elements/ShowCustomFieldDate b/rt/share/html/Elements/ShowCustomFieldDate
new file mode 100644
index 000000000..4e8ad676c
--- /dev/null
+++ b/rt/share/html/Elements/ShowCustomFieldDate
@@ -0,0 +1,57 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2008 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+<%INIT>
+ my $content = $Object->Content;
+ my $DateObj = new RT::Date ( $session{'CurrentUser'} );
+ $DateObj->Set( Format => 'ISO', Value => $content );
+ $content = $DateObj->AsString;
+</%INIT>
+<%$content|n%>
+<%ARGS>
+$Object
+</%ARGS>
diff --git a/rt/share/html/Elements/ShowCustomFields b/rt/share/html/Elements/ShowCustomFields
index ddb8b72e3..b60c49ae8 100644
--- a/rt/share/html/Elements/ShowCustomFields
+++ b/rt/share/html/Elements/ShowCustomFields
@@ -45,6 +45,7 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+% $m->callback( CallbackName => 'BeforeCustomFields' );
% if ($Table) {
<table>
% }
@@ -73,6 +74,7 @@
% if ($Table) {
</table>
% }
+% $m->callback( CallbackName => 'AfterCustomFields', Object => $Object );
<%INIT>
$m->callback(
CallbackName => 'MassageCustomFields',
@@ -82,9 +84,10 @@ $m->callback(
my $print_value = sub {
my ($cf, $value) = @_;
- my $linked = $cf->LinkValueTo;
- if ( $linked ) {
- $m->out('<a href="'. $value->LinkValueTo .'" target="_new">');
+ my $linked = $value->LinkValueTo;
+ if ( defined $linked && length $linked ) {
+ my $linked = $m->interp->apply_escapes( $linked, 'h' );
+ $m->out('<a href="'. $linked .'" target="_new">');
}
my $comp = "ShowCustomField". $cf->Type;
$m->callback(
@@ -98,7 +101,7 @@ my $print_value = sub {
} else {
$m->out( $m->interp->apply_escapes( $value->Content, 'h' ) );
}
- $m->out('</a>') if $linked;
+ $m->out('</a>') if defined $linked && length $linked;
# This section automatically populates a div with the "IncludeContentForValue" for this custom
# field if it's been defined
diff --git a/rt/share/html/Elements/ShowLink_Checklist b/rt/share/html/Elements/ShowLink_Checklist
new file mode 100644
index 000000000..945305fb6
--- /dev/null
+++ b/rt/share/html/Elements/ShowLink_Checklist
@@ -0,0 +1,36 @@
+<a href="<%$URI->Resolver->HREF%>">
+% if ($URI->IsLocal) {
+% my $member = $URI->Object;
+% if (UNIVERSAL::isa($member, "RT::Ticket")) {
+% my $inactive = 0; #$member->QueueObj->IsInactiveStatus($member->Status);
+
+<span class="<% $inactive ? 'ticket-inactive' : '' %>">
+<IMG SRC="<%$fsurl%>images/<% $status2image{$member->Status} %>.png" BORDER=0>
+<%$member->Id%>: (<%$member->OwnerObj->Name%>) <%$member->Subject%>
+%# [<% loc($member->Status) %>]
+</span>
+
+% } elsif ( UNIVERSAL::can($member, 'Name')) {
+<%$URI->Resolver->AsString%>: <%$member->Name%>
+% } else {
+<%$URI->Resolver->AsString%>
+% }
+% } else {
+<%$URI->Resolver->AsString%>
+% }
+</a>
+<%ARGS>
+$URI => undef
+</%ARGS>
+<%once>
+
+my %status2image = (
+ 'new' => 'square_add', #'bullet_add',
+ 'open' => 'square', #'bullet_black',
+ 'stalled' => 'error',
+ 'resolved' => 'tick',
+ 'rejected' => 'cross',
+ #'deleted' => 'delete',
+);
+
+</%once>
diff --git a/rt/share/html/Elements/ShowLinks b/rt/share/html/Elements/ShowLinks
index 569bad39c..e3b3ef509 100755
--- a/rt/share/html/Elements/ShowLinks
+++ b/rt/share/html/Elements/ShowLinks
@@ -47,7 +47,7 @@
%# END BPS TAGGED BLOCK }}}
<table>
<tr>
- <td class="labeltop"><&|/l&>Depends on</&>: (<a href="<%$clone->{'DependsOn-new'}%>"><% loc('Create') %></a>)</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Depends on'), Relation => 'DependsOn' &>: <span class="create">(<a href="<%$clone->{'DependsOn-new'}%>"><% loc('Create') %></a>)</span></td>
<td class="value">
<%PERL>
@@ -77,7 +77,7 @@ for my $link ( @{ $Ticket->DependsOn->ItemsArrayRef } ) {
</td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Depended on by</&>: (<a href="<%$clone->{'new-DependsOn'}%>"><% loc('Create') %></a>)</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Depended on by'), Relation => 'DependedOnBy' &>: <span class="create">(<a href="<%$clone->{'new-DependsOn'}%>"><% loc('Create') %></a>)</span></td>
<td class="value">
<ul>
% while (my $Link = $Ticket->DependedOnBy->Next) {
@@ -87,15 +87,15 @@ for my $link ( @{ $Ticket->DependsOn->ItemsArrayRef } ) {
</td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Parents</&>: (<a href="<%$clone->{'MemberOf-new'}%>"><% loc('Create') %></a>)</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Parents'), Relation => 'Parents' &>: <span class="create">(<a href="<%$clone->{'MemberOf-new'}%>"><% loc('Create') %></a>)</span></td>
<td class="value"><& /Ticket/Elements/ShowParents, Ticket => $Ticket &></td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Children</&>: (<a href="<%$clone->{'new-MemberOf'}%>"><% loc('Create') %></a>)</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Children'), Relation => 'Children' &>: <span class="create">(<a href="<%$clone->{'new-MemberOf'}%>"><% loc('Create') %></a>)</span></td>
<td class="value"><& /Ticket/Elements/ShowMembers, Ticket => $Ticket &></td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Refers to</&>: (<a href="<%$clone->{'RefersTo-new'}%>"><% loc('Create') %></a>)</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Refers to'), Relation => 'RefersTo' &>: <span class="create">(<a href="<%$clone->{'RefersTo-new'}%>"><% loc('Create') %></a>)</span></td>
<td class="value">
<ul>
% while (my $Link = $Ticket->RefersTo->Next) {
@@ -105,7 +105,7 @@ for my $link ( @{ $Ticket->DependsOn->ItemsArrayRef } ) {
</td>
</tr>
<tr>
- <td class="labeltop"><&|/l&>Referred to by</&>: (<a href="<%$clone->{'new-RefersTo'}%>"><% loc('Create') %></a>)</td>
+ <td class="labeltop"><& ShowRelationLabel, id => $id, Label => loc('Referred to by'), Relation => 'ReferredToBy' &>: <span class="create">(<a href="<%$clone->{'new-RefersTo'}%>"><% loc('Create') %></a>)</span></td>
<td class="value">
<ul>
% while (my $Link = $Ticket->ReferredToBy->Next) {
@@ -124,14 +124,15 @@ for my $link ( @{ $Ticket->DependsOn->ItemsArrayRef } ) {
<%INIT>
+my $id = $Ticket->id;
+
my $clone = {};
my $path
= RT->Config->Get('WebPath')
. '/Ticket/Create.html?Queue='
. $Ticket->Queue
. '&CloneTicket='
- . $Ticket->id;
-
+ . $id;
for my $relation (
qw(RefersTo ReferredToBy)) {
@@ -142,15 +143,14 @@ for my $relation (
$clone->{$field}
= $path . "&$field="
. join( '%20',
- ( map { $_->$other() } @{ $Ticket->$relation->ItemsArrayRef } ),
- $Ticket->id );
+ ( map { $_->$other() } @{ $Ticket->$relation->ItemsArrayRef } ), $id );
}
for my $relation ( qw(MemberOf Members DependsOn DependedOnBy)) {
my $mode = $RT::Ticket::LINKTYPEMAP{$relation}->{Mode};
my $type = $RT::Ticket::LINKTYPEMAP{$relation}->{Type};
my $field = $mode eq 'Base' ? 'new-' . $type : $type . '-new';
- $clone->{$field} = $path . "&$field=". $Ticket->id ;
+ $clone->{$field} = $path . "&$field=$id";
}
</%INIT>
diff --git a/rt/share/html/Elements/ShowRelationLabel b/rt/share/html/Elements/ShowRelationLabel
new file mode 100644
index 000000000..3c1ed1514
--- /dev/null
+++ b/rt/share/html/Elements/ShowRelationLabel
@@ -0,0 +1,62 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+<a href="<%$SearchURL |n %>"><%$Label%></a>
+<%INIT>
+my $typemap = RT::Ticket->LINKTYPEMAP->{$Relation};
+my $search_mode = $typemap->{Mode};
+my $search_type = $typemap->{Type};
+my $search_relation = RT::Ticket->LINKDIRMAP->{$search_type}{$search_mode};
+
+my $Query = $search_relation . ' = ' . $id;
+my $SearchURL = RT->Config->Get('WebPath') . '/Search/Results.html?' . $m->comp('/Elements/QueryString', Query => $Query);
+</%INIT>
+<%ARGS>
+$id
+$Label
+$Relation
+</%ARGS>
diff --git a/rt/share/html/Elements/ShowUser b/rt/share/html/Elements/ShowUser
index 2fbdcbc3e..01de7256a 100644
--- a/rt/share/html/Elements/ShowUser
+++ b/rt/share/html/Elements/ShowUser
@@ -49,18 +49,20 @@
<%INIT>
# $User is an RT::User object
# $Address is Email::Address object
-if ( !$User && $Address ) {
- $User = RT::User->new( $session{'CurrentUser'} );
- $User->LoadByEmail( $Address->address );
- unless ( $User->Id ) {
- $m->comp( '/Elements/ShowUserVerbose', Address => $Address );
- return;
- }
+
+my $comp = '/Elements/ShowUser'. ucfirst lc $style;
+unless ( $m->comp_exists( $comp ) ) {
+ $RT::Logger->error(
+ 'Either system config or user #'
+ . $session{'CurrentUser'}->id
+ . ' picked UsernameFormat '. $style
+ . ', but '. $comp . "doesn't exist"
+ );
+ return $m->comp('/Elements/ShowUserConcise',
+ User => $User, Address => $Address,
+ );
}
-if ( $style eq 'concise' ) {
- $m->comp( '/Elements/ShowUserConcise', User => $User );
-}
-else { $m->comp( '/Elements/ShowUserVerbose', User => $User ); }
+return $m->comp( $comp, User => $User, Address => $Address );
</%INIT>
<%ARGS>
$User => undef
diff --git a/rt/share/html/Elements/ShowUserConcise b/rt/share/html/Elements/ShowUserConcise
index 3cdba10dd..c4cccca75 100644
--- a/rt/share/html/Elements/ShowUserConcise
+++ b/rt/share/html/Elements/ShowUserConcise
@@ -46,7 +46,19 @@
%#
%# END BPS TAGGED BLOCK }}}
%# Released under the terms of version 2 of the GNU Public License
-<% $User->RealName || $User->Name %>\
+<% $Address || $User->RealName || $User->Name %>\
<%ARGS>
-$User
+$User => undef
+$Address => undef
</%ARGS>
+<%INIT>
+if ( !$User && $Address ) {
+ $User = RT::User->new( $session{'CurrentUser'} );
+ $User->LoadByEmail( $Address->address );
+ if ( $User->Id ) {
+ $Address = '';
+ } else {
+ $Address = $Address->address;
+ }
+}
+</%INIT>
diff --git a/rt/share/html/Elements/ShowUserVerbose b/rt/share/html/Elements/ShowUserVerbose
index 82d65b0b3..9b61ea74a 100644
--- a/rt/share/html/Elements/ShowUserVerbose
+++ b/rt/share/html/Elements/ShowUserVerbose
@@ -46,7 +46,11 @@
%#
%# END BPS TAGGED BLOCK }}}
%# Released under the terms of version 2 of the GNU Public License
-<%$Address->format%>\
+% if ( $Address->phrase || $Address->comment ) {
+<% sprintf q{%s <%s> %s}, map $Address->$_, qw( phrase address comment ) %>
+% } else {
+<% $Address->address %>
+% }
<%INIT>
my ($phrase, $address, $comment);
diff --git a/rt/share/html/Helpers/CalPopup.html b/rt/share/html/Helpers/CalPopup.html
index 96e8d77d0..70b43c192 100644
--- a/rt/share/html/Helpers/CalPopup.html
+++ b/rt/share/html/Helpers/CalPopup.html
@@ -123,7 +123,17 @@ elsif ($DisplayedMonth == 1) {
$prev_year--;
}
-my @cal = calendar($DisplayedMonth, $DisplayedYear);
+my @cal;
+{
+ my $error;
+ # RT defines a __DIE__ and Calendar::Simple uses Carp::Croak to report errors
+ # work around this so we get a better error message if something is out of range
+ eval { local $SIG{__DIE__} = sub { $error = $_[0] }; @cal = calendar($DisplayedMonth, $DisplayedYear) };
+ if ($error) {
+ $RT::Logger->error("error $error");
+ $m->comp('/Elements/Error', Why => $error );
+ }
+}
</%init>
<%args>
diff --git a/rt/share/html/NoAuth/Calendar/dhandler b/rt/share/html/NoAuth/Calendar/dhandler
new file mode 100644
index 000000000..4b4aa631e
--- /dev/null
+++ b/rt/share/html/NoAuth/Calendar/dhandler
@@ -0,0 +1,159 @@
+<%init>
+
+use Data::ICal;
+use Data::ICal::Entry::Todo;
+use Data::ICal::Entry::Event;
+use Date::ICal;
+
+$RT::ICalTicketType ||= "Data::ICal::Entry::Todo";
+$RT::ICalReminderType ||= "Data::ICal::Entry::Event";
+
+my ($UserId, $SearchId, $MagicNumber);
+my $arg = $m->dhandler_arg;
+
+if ($arg =~ m{^(\d+)@(\d+)/(.*)$}) {
+ $UserId = $1;
+ $SearchId = $2;
+ $MagicNumber = $3;
+} elsif ($arg =~ m{^(\d+)/(.*)}) {
+ $UserId = $1;
+ $MagicNumber = $2;
+} else {
+ Abort("Corrupted URL.");
+}
+
+my $CurrentUser = new RT::CurrentUser();
+$CurrentUser->LoadById($UserId);
+my $user = $CurrentUser->Name;
+
+# if no user, abort
+unless ($CurrentUser->Id) {
+ $RT::Logger->error("No such user id $UserId from $ENV{'REMOTE_ADDR'}");
+ $m->out("RT/".$RT::VERSION ." ".404 ."\n\nno such file\n");
+ $m->abort;
+}
+
+# verify user has LoadSavedSearch right
+if ($SearchId and not $CurrentUser->HasRight( Right => 'LoadSavedSearch',
+ Object=> $RT::System )) {
+ $RT::Logger->error("not enough rights for user $user from $ENV{'REMOTE_ADDR'}");
+ $m->out("RT/".$RT::VERSION ." ".404 ."\n\nno such file\n");
+ $m->abort;
+}
+
+
+# if MagicNumber doesn't match the one stored in database, abort
+my $Search;
+my $ICalAttribute;
+if ($SearchId) {
+ $Search = $CurrentUser->Attributes->WithId($SearchId);
+ $ICalAttribute = $Search->FirstAttribute('ICalURL');
+} else {
+ $ICalAttribute = $CurrentUser->UserObj->FirstAttribute('ICalURL');
+}
+
+unless ($ICalAttribute) {
+ $RT::Logger->error("No such ICal feed for $user from $ENV{'REMOTE_ADDR'}");
+ $m->out("RT/".$RT::VERSION ." ".404 ."\n\nno such file\n");
+ $m->abort;
+}
+
+
+if ($MagicNumber ne $ICalAttribute->Content) {
+ $RT::Logger->error("FAILED LOGIN for $user from $ENV{'REMOTE_ADDR'}");
+ $m->out("RT/".$RT::VERSION ." ".404 ."\n\nno such file\n");
+ $m->abort;
+}
+
+my $Tickets = RT::Tickets->new($CurrentUser);
+
+my $Query = "( Status = 'new' OR Status = 'open' OR Status = 'stalled')
+ AND ( Owner = '" . $CurrentUser->Id ."' OR Owner = 'Nobody' )
+ AND ( Type = 'reminder' OR 'Type' = 'ticket' )";
+
+$Query = $Search->SubValue('Query')
+ if $Search;
+
+$Query .= " AND ( Due > '1970-01-01' OR Starts > '1970-01-01' )";
+
+$Tickets->FromSQL($Query);
+
+$Tickets->OrderBy(FIELD => 'Due', ORDER => 'ASC');
+
+my $calendar = Data::ICal->new();
+
+my ($uid) = $RT::WebURL =~ m{https?://([^:]+)};
+
+while (my $Ticket = $Tickets->Next ) {
+
+ my $event;
+ if ($Ticket->Type eq 'ticket') {
+ $event = add_todo($Ticket, $uid);
+ } else {
+ $event = add_event($Ticket, $uid);
+ }
+ next unless $event;
+ $calendar->add_entry($event);
+}
+
+my $cal = $calendar->as_string;
+
+$r->content_type('text/calendar;charset=utf-8');
+$m->clear_buffer();
+$m->out($cal);
+$m->abort;
+
+sub add_event {
+ my ($Reminder, $uid) = @_;
+
+ return unless defined $Reminder->RefersTo->First;
+ my $Ticket = $Reminder->RefersTo->First->TargetObj;
+
+ my %event = (
+ summary => $Reminder->Subject ? $Reminder->Subject : '',
+ url => "${RT::WebURL}/Ticket/Display.html?id=" . $Ticket->id,
+ uid => Date::ICal->new( epoch => time() )->ical() . "-" . $Reminder->Id . "@" . $uid,
+ categories => $Ticket->QueueObj->Name,
+ dtstart => Date::ICal->new( epoch => $Reminder->DueObj->Unix )->ical,
+ );
+
+ my $event = $RT::ICalReminderType->new();
+ $event->add_properties(%event);
+
+ return $event;
+}
+
+sub add_todo {
+ my ($Ticket, $uid) = @_;
+
+ my %vtodo = (
+ summary => $Ticket->Subject ? $Ticket->Subject : '',
+ dtstart => Date::ICal->new( epoch => $Ticket->CreatedObj->Unix )->ical,
+ url => "${RT::WebURL}/Ticket/Display.html?id=" . $Ticket->id,
+ uid => Date::ICal->new( epoch => time() )->ical() . "-" . $Ticket->Id . "@" . $uid,
+ categories => $Ticket->QueueObj->Name,
+ );
+
+ $vtodo{due} = Date::ICal->new( epoch => $Ticket->DueObj->Unix )->ical,
+ if $Ticket->DueObj;
+
+ if ($Ticket->OwnerObj->Id != $RT::Nobody->Id and $Ticket->OwnerObj->EmailAddress) {
+ $vtodo{organizer} = "MAILTO:" . $Ticket->OwnerObj->EmailAddress;
+ $vtodo{attendee} = "MAILTO:" . $Ticket->OwnerObj->EmailAddress;
+ } elsif ($Ticket->QueueObj->CommentAddress) {
+ $vtodo{organizer} = "MAILTO:" . $Ticket->QueueObj->CommentAddress;
+ $vtodo{attendee} = "MAILTO:" . $Ticket->QueueObj->CommentAddress;
+ }
+
+ $vtodo{priority} = $Ticket->Priority
+ if $Ticket->Priority;
+
+ my $vtodo = $RT::ICalTicketType->new();
+ $vtodo->add_properties(%vtodo);
+
+ return $vtodo;
+}
+
+
+
+</%init>
diff --git a/rt/share/html/NoAuth/Logout.html b/rt/share/html/NoAuth/Logout.html
index 5a4926b97..7b80823b3 100755
--- a/rt/share/html/NoAuth/Logout.html
+++ b/rt/share/html/NoAuth/Logout.html
@@ -45,7 +45,7 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<& /Elements/Header, Title => loc('Logout'), Refresh => "1;URL=$URL" &>
+<& /Elements/Header, Title => loc('Logout'), Refresh => RT->Config->Get('LogoutRefresh').";URL=$URL" &>
</div>
<div id="body" class="login-body">
@@ -58,22 +58,22 @@
<br />
<a href="<%$URL%>"><&|/l&>You're welcome to login again</&></a>.
</&>
+
+% $m->callback( %ARGS );
+
</div></div>
<& /Elements/Footer, Menu => 0 &>
% $m->abort();
<%INIT>
+my $URL = RT->Config->Get('WebPath')."/";
$m->callback( %ARGS, CallbackName => 'BeforeSessionDelete' );
-if (defined %session) {
+if (keys %session) {
tied(%session)->delete;
$session{'CurrentUser'} = RT::CurrentUser->new;
}
$m->callback( %ARGS, CallbackName => 'AfterSessionDelete' );
</%INIT>
-
-<%ARGS>
-$URL => RT->Config->Get('WebPath')."/"
-</%ARGS>
diff --git a/rt/share/html/NoAuth/css/3.4-compat/misc.css b/rt/share/html/NoAuth/css/3.4-compat/misc.css
index 2a58b13aa..a7a445f84 100644
--- a/rt/share/html/NoAuth/css/3.4-compat/misc.css
+++ b/rt/share/html/NoAuth/css/3.4-compat/misc.css
@@ -45,6 +45,9 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+
+@import "../base/misc.css";
+
.oddline { background: white; }
.evenline { background: #cecfef; }
diff --git a/rt/share/html/NoAuth/css/3.4-compat/titlebox.css b/rt/share/html/NoAuth/css/3.4-compat/titlebox.css
index 9b31b294b..72b1a27cb 100644
--- a/rt/share/html/NoAuth/css/3.4-compat/titlebox.css
+++ b/rt/share/html/NoAuth/css/3.4-compat/titlebox.css
@@ -77,10 +77,6 @@
color: black;
}
-.titlebox .titlebox-content hr.clear {
- visibility: hidden;
-}
-
%# TRS: I wish there was a more elegant way to do this... I essentially need to
%# select all elements X that do NOT have element Y as a descendant... which I can
%# fake with the child selector of CSS2, but IE is stupid and does not support that.
diff --git a/rt/share/html/NoAuth/css/3.5-default/misc.css b/rt/share/html/NoAuth/css/3.5-default/misc.css
index 67b5e1951..ca5020338 100755
--- a/rt/share/html/NoAuth/css/3.5-default/misc.css
+++ b/rt/share/html/NoAuth/css/3.5-default/misc.css
@@ -45,6 +45,9 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+
+@import "../base/misc.css";
+
body {
font-family: Verdana, sans-serif;
font-size: 76%;
@@ -52,8 +55,6 @@ body {
background-color: white;
}
-.hide, .hidden { display: none !important; }
-
#body.calpopup {
margin-left: 2em;
}
@@ -77,36 +78,11 @@ td {
padding: 0.1em 0.5em 0.1em 0.5em;
}
-.clear { clear: both; }
-
ul.action-results {
margin-top: 0;
margin-bottom: 0;
}
-div.autocomplete {
- position: absolute;
- background-color: white;
- border: 1px solid #888;
- margin: 0px;
- padding: 0px;
-}
-div.autocomplete ul {
- list-style-type: none;
- margin: 0px;
- padding: 0px;
-}
-div.autocomplete ul li.selected {
- background-color: #0088cc;
- color: #eee;
-}
-div.autocomplete ul li {
- list-style-type: none;
- display: block;
- margin: 0;
- padding: 2px;
-}
-
.shredder-form { line-height: 3em }
.shredder-form span { margin-left: 1em; margin-right: 1em }
.shredder-help {
@@ -122,4 +98,3 @@ div.autocomplete ul li {
#shredder-plugin-results input { margin-left: 1em; }
.pod-sequence-C { background-color: #eee }
-
diff --git a/rt/share/html/NoAuth/css/3.5-default/titlebox.css b/rt/share/html/NoAuth/css/3.5-default/titlebox.css
index 329cf8f76..f47b15803 100644
--- a/rt/share/html/NoAuth/css/3.5-default/titlebox.css
+++ b/rt/share/html/NoAuth/css/3.5-default/titlebox.css
@@ -152,10 +152,6 @@
text-decoration: underline;
}
-.titlebox .titlebox-content hr.clear {
- visibility: hidden;
-}
-
.titlebox .titlebox-title .left {
position: relative;
}
diff --git a/rt/share/html/NoAuth/css/autohandler b/rt/share/html/NoAuth/css/autohandler
index a92cfd17b..f11f78adb 100644
--- a/rt/share/html/NoAuth/css/autohandler
+++ b/rt/share/html/NoAuth/css/autohandler
@@ -49,7 +49,8 @@
my $file = $m->base_comp->source_file;
if ($file =~ /\.(gif|png|jpe?g)$/i) {
- RT::Interface::Web->SendStaticFile( File => $file );
+ my $relfile = $m->base_comp->path;
+ RT::Interface::Web->SendStaticFile( File => $file, RelativeFile => $relfile );
} else {
RT::Interface::Web::StaticFileHeaders();
$r->content_type('text/css') ;
diff --git a/rt/share/html/NoAuth/css/base/misc.css b/rt/share/html/NoAuth/css/base/misc.css
new file mode 100644
index 000000000..84023eca9
--- /dev/null
+++ b/rt/share/html/NoAuth/css/base/misc.css
@@ -0,0 +1,49 @@
+.hide, .hidden { display: none !important; }
+
+div.autocomplete {
+ position: absolute;
+ background-color: white;
+ border: 1px solid #888;
+ margin: 0px;
+ padding: 0px;
+}
+div.autocomplete ul {
+ list-style-type: none;
+ margin: 0px;
+ padding: 0px;
+}
+div.autocomplete ul li.selected {
+ background-color: #0088cc;
+ color: #eee;
+}
+div.autocomplete ul li {
+ list-style-type: none;
+ display: block;
+ margin: 0;
+ padding: 2px;
+}
+
+
+.clear { clear: both; }
+
+* html .clearfix {
+ height: 1%; /* IE5-6 */
+}
+.clearfix {
+ display: inline-block; /* IE7xhtml*/
+}
+html[xmlns] .clearfix { /* O */
+ display: block;
+}
+.clearfix:after { /* FF, O, etc. */
+ content: ".";
+ display: block;
+ height: 0;
+ clear: both;
+ visibility: hidden;
+}
+
+.titlebox .titlebox-content hr.clear {
+ visibility: hidden;
+}
+
diff --git a/rt/share/html/NoAuth/css/calendar.css b/rt/share/html/NoAuth/css/calendar.css
new file mode 100644
index 000000000..c6b584e96
--- /dev/null
+++ b/rt/share/html/NoAuth/css/calendar.css
@@ -0,0 +1,75 @@
+.tooltip{position:relative;z-index:1;}
+.tooltip:hover{z-index:5;color:#000;}
+.tooltip span.tip{display: none; text-align:left;}
+
+div.tooltip:hover span.tip{
+display:block;
+position:absolute;
+top:12px; left:24px; width:350px;
+border:1px solid #555;
+background-color:#fff;
+padding: 4px;
+font-size: 0.8em;
+color:#505050;
+}
+
+.calendardate {
+ text-align: right;
+ background-color: #f8f8ff;
+ width:100%;
+}
+
+.offmonthcalendardate {
+ text-align: right;
+ background-color: #f8f8f8;
+ width:100%;
+}
+
+.todayscalendardate {
+ text-align: right;
+ background-color: #fc6; /*#fad163*/
+ width:100%;
+}
+
+table.rtxcalendar {
+ width:100%;
+ border-collapse: collapse;
+ border: 1px solid #d0d0d0;
+ margin-bottom: 6px;
+}
+
+table.rtxcalendar td {
+ border: 1px solid #d7d7d7;
+ background: #fff;
+ vertical-align: top;
+ width: 14%;
+}
+
+table.rtxcalendar th {
+ border: 1px solid #d7d7d7;
+ background: #eef;
+}
+table.rtxcalendar tbody th {
+ border: 1px solid #d7d7d7;
+ background: #eee;
+ font-weight: normal;
+}
+
+table.rtxcalendar td.offmonth {
+ background: #f8f8f8;
+ color: #aaa;
+}
+
+table.rtxcalendar td.today {
+ background: #ffe; /*#fed;*/
+ border: 1px solid #fc6;
+}
+
+table.rtxcalendar td.yesterday {
+ border-right: none;
+}
+
+table.rtxcalendar td.aweekago {
+ border-bottom: none;
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/InHeader b/rt/share/html/NoAuth/css/freeside2.1/InHeader
new file mode 100644
index 000000000..904535fbd
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/InHeader
@@ -0,0 +1,54 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+<!--[if lt IE 8]>
+<link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/freeside2.1/msie.css" type="text/css" media="all" />
+
+<![endif]-->
+<!--[if lt IE 7]>
+<link rel="stylesheet" href="<%RT->Config->Get('WebPath')%>/NoAuth/css/freeside2.1/msie6.css" type="text/css" media="all" />
+<![endif]-->
diff --git a/rt/share/html/NoAuth/css/freeside2.1/admin.css b/rt/share/html/NoAuth/css/freeside2.1/admin.css
new file mode 100644
index 000000000..63385bffa
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/admin.css
@@ -0,0 +1,60 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+ul.list-menu .menu-item {
+ font-size: 1.25em;
+}
+ul.list-menu {
+ list-style: none;
+
+}
+ul.list-menu .description {
+ display: block;
+ padding: 0.5em;
+ font-style: italic;
+ padding-left: 1em;
+}
diff --git a/rt/share/html/NoAuth/css/freeside2.1/base.css b/rt/share/html/NoAuth/css/freeside2.1/base.css
new file mode 100644
index 000000000..a38854fb5
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/base.css
@@ -0,0 +1,63 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+a {
+ color: #000;
+ text-decoration: none;
+}
+
+
+div#body a:visited {
+ color: #666;
+
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+textarea:focus, input:focus { background-color: #ffd; }
diff --git a/rt/share/html/NoAuth/css/freeside2.1/boxes.css b/rt/share/html/NoAuth/css/freeside2.1/boxes.css
new file mode 100644
index 000000000..fbd9af108
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/boxes.css
@@ -0,0 +1,192 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+.titlebox {
+ border-left: 1px solid #ccc;
+ border-top: 1px solid #ccc;
+ background-color: #efefef;
+ padding-top: 1em;
+ margin-top: 1em;
+ margin-left: 1em;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ margin-bottom: 2em;
+ border-bottom: 2px solid #aaa;
+ border-right: 2px solid #aaa;
+ padding-right: 1em;
+}
+
+* html .titlebox {
+ border-top: none;
+ border-left: none;
+}
+
+.titlebox .titlebox {
+
+ background-color: #ffffff;
+ margin-top: 1em;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ margin-right: 0.25em;
+
+}
+
+
+.titlebox {
+ margin-left: 0em;
+ margin-right: 0em;
+ min-height: 1.25em;
+
+}
+
+
+
+.titlebox .titlebox-title {
+ position: relative;
+ margin-top: -1.5em;
+ padding-bottom: 0.25em;
+ padding-left: 1em;
+ margin-right: -1em;
+
+}
+
+.titlebox .titlebox-title a {
+ text-decoration: none;
+ color: black;
+
+}
+
+.titlebox .titlebox-title a:hover {
+ text-decoration: underline;
+
+}
+
+.titlebox .titlebox-title a:visited {
+ color: #fff;
+}
+
+.titlebox .titlebox-title .left {
+ font-weight: bold;
+ background: #ccc;
+ margin-left: 0.75em;
+ padding:0.5em;
+ padding-left: 0.75em;
+ padding-right: 0.75em;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ border-bottom: 2px solid #aaa;
+ border-right: 2px solid #aaa;
+
+
+}
+
+.titlebox .titlebox-title .right-empty {
+ display:none;
+}
+
+.titlebox .titlebox-title .right {
+ position: absolute;
+ right: 0;
+ top: 0.5em;
+ font-size: 0.9em;
+ background: #dedede;
+ border-left: 1px solid #ccc;
+ border-bottom: 1px solid #ccc;
+ padding-right: 0.4em;
+ padding-left: 0.4em;
+ padding-bottom: 0.2em;
+ padding-top: 0.5em;
+ -moz-border-radius-bottomleft: 0.25em;
+ -webkit-border-bottom-left-radius: 0.25em;
+
+
+ -moz-border-radius-topright: 0.25em;
+ -webkit-border-top-right-radius: 0.25em;
+
+}
+
+.titlebox .titlebox-title .right a {
+ color: #000;
+}
+
+.titlebox .titlebox-content {
+ padding-top: 0.5em;
+ padding-left: 1em;
+ padding-bottom: 1em;
+
+}
+
+.titlebox .titlebox-title .widget a {
+ display: block;
+ margin: 0;
+ margin-top: 0.5em;
+ width: 20px;
+
+ background: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rollup-arrow.gif) no-repeat center center;
+
+ position: absolute;
+ top: -1em;
+ left: 0.15em;
+ float: left;
+
+ padding: 11px 0 0 0;
+ overflow: hidden;
+}
+
+* html .titlebox .titlebox-title .widget a {
+ background-position: center 0.3em;
+ top: 0em;
+ left: -1.5em;
+}
+
+.titlebox.rolled-up .titlebox-title .widget a {
+ background-image: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rolldown-arrow.gif);
+}
+
+.titlebox hr.clear {
+ display: none;
+}
diff --git a/rt/share/html/NoAuth/css/freeside2.1/collection.css b/rt/share/html/NoAuth/css/freeside2.1/collection.css
new file mode 100644
index 000000000..cbc8cefd7
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/collection.css
@@ -0,0 +1,52 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+
+table.collection td:first-child, table.collection th:first-child {
+ padding-left: 1em;
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/forms.css b/rt/share/html/NoAuth/css/freeside2.1/forms.css
new file mode 100755
index 000000000..8afedcb03
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/forms.css
@@ -0,0 +1,242 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+form {
+
+ background: none;
+ border: none;
+ margin: 0;
+}
+
+
+.input-row .label {
+ position: relative;
+ text-align: right;
+ width: 4em;
+}
+
+.input-row .input {
+ position: relative;
+ left: 1em;
+ width: 10em;
+ text-align: right;
+}
+
+.value {
+ font-size: 0.85em;
+
+}
+
+
+
+div.button-row {
+ text-align: right;
+ padding-right: 0.5em;
+}
+
+
+input[type=reset], input[type=submit], input[class=button] {
+ color: #fff;
+ background: #3858a3;
+ padding: 0.25em;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+}
+
+input.button:hover, button:hover, input[type=reset]:hover, input[type=submit]:hover, input[class=button]:hover {
+ background: #1D3B7D;
+}
+
+input.button:focus, button:focus, input[type=reset]:focus, input[type=submit]:focus, input[class=button]:focus {
+ background: #1D3B7D;
+}
+
+div.error div.error {
+ border: 2px solid #aa0000;
+ border-top: 1px solid #bb0000;
+ border-left: 1px solid #bb0000;
+ background-color: #fcc;
+}
+
+div.error .titlebox-title span.left {
+ background-color: #f00;
+ color: #fff;
+ border: 1px solid #cc0000;
+ border-right: 2px solid #bb0000;
+ border-bottom: 2px solid #bb0000;
+
+}
+
+
+div.results .titlebox-title .left, div.results .titlebox {
+ border: 1px solid #aa9;
+ border-bottom: 2px solid #990;
+ border-right: 2px solid #990;
+}
+
+div.results .titlebox-title .left {
+ background: #ff9;
+
+}
+
+div.results .titlebox {
+ background: #ffc;
+
+}
+
+div.results .titlebox-content {
+ padding: 0;
+}
+
+
+.label, .labeltop {
+ text-align: right;
+ font-size: 0.8em;
+ padding-right: .5em;
+
+}
+
+.cflabel {
+ text-align: right;
+ font-size: 0.8em;
+ padding-right: .5em;
+ width: 25%;
+}
+
+.labeltop, .label, .value {
+ padding-top: 0.25em;
+}
+
+div.ticket-info-basics div.titlebox-content .labeltop{
+ width: 10em;
+}
+
+div.submit {
+ text-align: right;
+}
+
+div.submit .extra-buttons {
+ text-align: left;
+}
+
+
+div.widget {
+ padding-bottom: 0.5em;
+}
+
+div.widget .label {
+ text-align: right;
+ display: block;
+ width: 15em;
+ float: left;
+ clear: both;
+ font-size: 0.9em;
+ padding-right: 0.5em;
+}
+
+div.widget .hints {
+
+ display: block;
+ padding-left: 14em;
+ font-style: italic;
+}
+
+
+%# ComboBox styles... some properties like height and width must be dynamically
+%# set in the JS (at least for now).
+.combobox {
+ position: relative;
+ width: 11.5em;
+}
+
+.combobox .combo-button {
+ right: 0;
+ padding: 0;
+ margin-top: 0;
+ cursor: default;
+ color: ButtonFace;
+ background: ButtonFace;
+ border: 2px outset ButtonHighlight;
+}
+
+/* this style replaces the default down-triangle with one that looks more like
+ * native widget sets. It does not work in IE as it's an :after pseudo element
+ * with a "content" value. but that's ok because IE can't display unicode 25be
+ * anyway */
+
+.combobox .combo-button:after {
+ color: ButtonText;
+ margin: 0;
+ padding: 0;
+ margin-top: -0.5em;
+ margin-left: -0.8em;
+ content: "\25be";
+}
+
+.combobox .combo-text {
+ border: 1px inset ButtonHighlight;
+ margin: 0;
+ padding: 0;
+}
+
+.combobox .combo-list {
+ border: 1px outset;
+ z-index: 150;
+}
+
+.value .TimeUnits{
+ margin-left: .5em;
+ width: 7em;
+}
+
+.cfinvalidfield {
+ font-style: italic;
+ color: red;
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/freeside.css b/rt/share/html/NoAuth/css/freeside2.1/freeside.css
new file mode 100644
index 000000000..6e5f3b576
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/freeside.css
@@ -0,0 +1,9 @@
+
+%# div.titlebox {
+%# background: #d4d4d4;
+%# }
+%#
+%# div.titlebox-title {
+%# background: #e8e8e8;
+%# }
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/images/dhandler b/rt/share/html/NoAuth/css/freeside2.1/images/dhandler
new file mode 100644
index 000000000..6ec9dea05
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/images/dhandler
@@ -0,0 +1,8 @@
+<%INIT>
+use File::Basename;
+my $arg = $m->dhandler_arg;
+my $file = dirname($m->current_comp->source_file) . '/source/'. $arg;
+RT::Interface::Web->SendStaticFile( File => $file );
+
+$m->abort;
+</%INIT>
diff --git a/rt/share/html/NoAuth/css/freeside2.1/images/source/background-gradient.png b/rt/share/html/NoAuth/css/freeside2.1/images/source/background-gradient.png
new file mode 100644
index 000000000..9c126c7e3
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/images/source/background-gradient.png
Binary files differ
diff --git a/rt/share/html/NoAuth/css/freeside2.1/layout.css b/rt/share/html/NoAuth/css/freeside2.1/layout.css
new file mode 100644
index 000000000..0e7912d98
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/layout.css
@@ -0,0 +1,237 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+/* body */
+
+body {
+
+
+ padding:0;
+ margin:0;
+
+ /*background: #547CCC url(<%RT->Config->Get('WebPath')%>/NoAuth/css/freeside2.1/images/background-gradient.png) top left repeat-x ; */
+ background: #f8f8f8;
+ font-family: arial, helvetica, sans-serif;
+
+ color: #000000;
+}
+
+div#body {
+ position: relative;
+ padding: 1em;
+ padding-top: 1.8em;
+ -moz-border-radius: 0.5em;
+ -webkit-border-radius: 0.5em;
+ /* margin-left: 10.5em; */
+ /* margin-top: 5.2em; */
+ margin-left: .5em;
+ margin-top: 3.0em;
+ margin-right: 1em;
+ margin-bottom: 0em;
+ min-height: 10%;
+ background: #fff;
+ border-top: 2px solid #ccc;
+ border-left: 2px solid #ccc;
+ z-index:1;
+
+
+}
+
+#topactions {
+ position: absolute;
+ background: transparent;
+ top: 3.8em;
+ right: 1em;
+ width: auto;
+ min-width: 42em;
+ font-size: 0.9em;
+ z-index: 99;
+}
+
+#topactions form * {
+ vertical-align: top;
+}
+
+#topactions button, #topactions select, #topactions input{
+ padding-top: 0em;
+ padding-bottom: 0em;
+ width: 8em;
+
+}
+
+#topactions form {
+ display: block;
+
+}
+
+#topactions #CreateTicketInQueue {
+ text-align: right;
+
+}
+#topactions #simple-search {
+ float: right;
+}
+
+#topactions #simple-search .field{
+ margin-left: 1em;
+ color: #787;
+ }
+
+#topactions #simple-search .field:focus {
+ color: #000;
+ }
+
+#topactions #GotoTicket {
+ text-align: right;
+
+}
+
+div#footer {
+ position: absolute;
+ right: 0;
+ text-align: right;
+ font-size: 0.9em;
+ margin-top: 2em;
+ background: #fff;
+ margin-bottom: 0;
+ padding-left: 3em;
+ padding-right: 1em;
+
+
+
+
+
+ border-top: 2px solid #aaa;
+ border-left: 2px solid #aaa;
+
+
+
+ -moz-border-radius-topleft: 0.5em;
+ -webkit-border-top-left-radius: 0.5em;
+ -moz-border-radius-bottomleft: 0.5em;
+ -webkit-border-bottom-left-radius: 0.5em;
+}
+
+div#footer #time {
+display: none ;
+}
+
+div#footer #bpscredits {
+ text-align: right;
+ background: url(<%RT->Config->Get('WebPath')%>/NoAuth/images//bplogo.gif) no-repeat top right;
+ padding-top: 4em;
+}
+
+
+/* logo stuff */
+
+div#logo {
+}
+
+
+div#logo a {
+ display: none;
+ position: absolute;
+ left: 0;
+ bottom: 0;
+}
+div#logo a img {
+ border: 0;
+}
+div#logo .rtname {
+ position: absolute;
+ font-weight: bold;
+ top: 1em;
+ left: 1em;
+}
+
+
+div#quickbar, div#logo {
+ font-size: 0.9em;
+}
+div#quickbar a, div#logo a {
+ color: #000;
+}
+
+
+div#quickbar {
+ background: #eaeaea;
+ padding-top: 1em;
+ padding-left: 1em;
+ padding-bottom: 0.5em;
+ height: 1em;
+ border-bottom: 1px solid #ccc;
+
+}
+div#quick-personal {
+ float: right;
+ margin-right: 1em;
+}
+
+
+div#header h1 {
+ position: absolute;
+ left: 7.25em;
+ right: 20em;
+ overflow: hidden;
+ height: 1em;
+ font-size: 1.4em;
+ margin-top: 0.4em;
+ padding: 0.25em;
+ color: #fff;
+}
+
+/* in multi-column layouts, make sure we have an internal gutter */
+
+tr .boxcontainer {
+ padding-right: 1em;
+}
+
+tr .boxcontainer:last-child {
+ padding-right: 0;
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/login.css b/rt/share/html/NoAuth/css/freeside2.1/login.css
new file mode 100644
index 000000000..2eb423876
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/login.css
@@ -0,0 +1,82 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+#login-box hr {
+ display: none;
+}
+
+#login-box {
+
+ width: 30em;
+
+margin-right:auto;margin-left:auto;
+ padding-top: 2em;
+ padding-bottom: 2em;
+
+
+}
+
+
+#login-box .input-row {
+ position: relative;
+ height: 1.5em;
+ padding-top: 1em;
+}
+
+#login-box .input-row .label {
+
+ float: left;
+ width: 8em;
+ text-align: right;
+ font-weight: bold;
+
+
+}
+
+#login-box .button-row {
+ margin-top: 0.5em;
+}
diff --git a/rt/share/html/NoAuth/css/freeside2.1/main.css b/rt/share/html/NoAuth/css/freeside2.1/main.css
new file mode 100644
index 000000000..69e7f44e2
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/main.css
@@ -0,0 +1,71 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+% $m->callback(CallbackName => 'Begin');
+
+@import "yui-fonts.css";
+@import "base.css";
+
+@import "layout.css";
+@import "nav.css";
+@import "forms.css";
+@import "boxes.css";
+
+@import "login.css";
+@import "ticket-lists.css";
+@import "ticket-search.css";
+@import "portlets.css";
+@import "ticket.css";
+@import "tools.css";
+@import "admin.css";
+@import "collection.css";
+@import "misc.css";
+
+@import "freeside.css";
+
+% $m->callback(CallbackName => 'End');
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/misc.css b/rt/share/html/NoAuth/css/freeside2.1/misc.css
new file mode 100644
index 000000000..80d7ce0b4
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/misc.css
@@ -0,0 +1,87 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+
+@import "../base/misc.css";
+
+#body.calpopup {
+ margin-left: 1em;
+ margin-top: 1em;
+}
+
+#body.calpopup a.today {
+ font-size: 1em;
+ font-weight: bold;
+}
+
+#body.calpopup a {
+ font-size: 0.8em;
+}
+
+.calendar {
+ text-align: center;
+ margin: 0 0 0 0;
+}
+
+.calendar td, .calendar th { padding: 0.1em 0.1em 0.1em 0.1em; }
+
+.calendar caption .month {
+ padding: 0 0.25em 0 0.25em;
+ font-size: 1.5em;
+}
+
+.comment {
+ padding-left: 0.5em;
+ color: #999;
+
+}
+
+#comp-Ticket-ShowEmailRecord #body {
+ margin-left: 1em;
+ margin-top: 1em;
+ overflow: auto;
+}
diff --git a/rt/share/html/NoAuth/css/freeside2.1/msie.css b/rt/share/html/NoAuth/css/freeside2.1/msie.css
new file mode 100644
index 000000000..2297c304a
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/msie.css
@@ -0,0 +1,246 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+div#body {
+ left: 0.25em;
+ height: 100%;
+ top: 1em;
+
+}
+
+
+#footer {
+ padding: 1em;
+}
+
+
+div#header h1 {
+ position: absolute;
+ left: 7.25em;
+ overflow: hidden;
+ height: 1em;
+ font-size: 1.4em;
+ margin-top: 0.4em;
+ right: 23.5em;
+ padding: 0.25em;
+}
+
+
+#topactions {
+ top: 4.1em;
+ width: auto;
+}
+.topaction form * {
+ vertical-align: top;
+}
+
+.topaction form button, .topaction form input {
+ height: 2em;
+}
+
+.topaction form input.field {
+ height: 1.6em;
+}
+
+.topaction .select-queue {
+ margin-top: 0.2em;
+}
+
+div#page-navigation ul#actions-menu {
+ margin-top: -2.9em;
+ margin-right: -0.2em;
+ border-top: 1px solid #ccc;
+ border-right: none;
+}
+
+
+div#page-navigation {
+ position: absolute;
+ top: 6.2em;
+ height: 1.8em;
+ background: #fff;
+ border-top: 2px solid #ccc;
+}
+
+
+
+div#page-navigation ul#page-menu {
+ margin-top: -2.5em;
+ margin-left: 4em;
+ background: none;
+ border: none;
+}
+
+
+div#quickbar { height: 1.2em;
+
+
+}
+
+#pick-criteria td.label select {
+ width: 10em;
+}
+
+
+#editquery {
+ margin-top: 0.2em;
+ width: 39%;
+ left: 60%;
+}
+
+div#nav li.first {
+ margin-top: 0.75em;
+ border-top: none;
+}
+div#nav ul ul li.first {
+ border-top: 1px solid #cccccc;
+ margin-top: 0.25em;
+}
+
+div#nav li.last {
+ border-bottom: none;
+ padding-bottom: 0;
+ margin-bottom: 0;
+}
+
+
+.ticket-transaction .type a { font-weight: normal; text-decoration: none; color: #fff; }
+
+
+.titlebox {
+ border-top: none;
+ border-left: none;
+}
+
+.titlebox .titlebox-title .left {
+ padding: 0.25em;
+ padding-left: 0.5em;
+}
+
+.titlebox {
+}
+
+.titlebox .titlebox-title .right {
+ border-right: 2px solid #aaa;
+
+}
+
+
+.titlebox .titlebox-content {
+ padding-top: 2.2em;
+}
+
+.titlebox table.ticket-list, .titlebox table.queue-summary {
+ width: 95%;
+ padding: 0.5em;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+th.collection-as-table {
+ padding: 0.25em;
+}
+
+table.queue-summary td, td.collection-as-table {
+ padding: 0.25em;
+}
+
+ .titlebox-title {
+ position: relative;
+}
+
+.titlebox-title .widget {
+ position: absolute;
+ top: -0.25em;
+ left: -0.25em;
+
+}
+.titlebox-title .left {
+ position: absolute;
+ top: -0.75em;
+ left: 0.5em;
+}
+
+
+.titlebox .titlebox-title .right{
+ top: 0.2em;
+ right: -0.2em;
+}
+
+/* nested things. like the ticket dates tab */
+.titlebox .titlebox .titlebox-title .right{
+ top: 0.25em;
+}
+
+.combobox {
+ float: left;
+}
+
+.combobox .combo-button {
+ color: ButtonText;
+ padding: 0;
+}
+
+.combobox .combo-list {
+ margin-top:0.5em;
+ margin-left: -0.2em;
+}
+
+#pick-criteria td.label {
+ width: auto;
+}
+
+#pick-criteria td.operator {
+ width: 7.5em;
+}
+
+.plain-text-white-space {
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+ white-space: pre; /* IE only hack to re-specify in addition to
+ word-wrap */
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/msie6.css b/rt/share/html/NoAuth/css/freeside2.1/msie6.css
new file mode 100644
index 000000000..bf6b1ed6d
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/msie6.css
@@ -0,0 +1,88 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+.topaction .select-queue {
+ margin-top: 0;
+}
+
+div#page-navigation ul#page-menu {
+ margin-top: -3.2em;
+}
+
+.titlebox-title .widget {
+ top: -1em;
+ left: 0.5em;
+
+}
+.titlebox .titlebox-title .right{
+ position: absolute;
+ top: 0.25em;
+ right: 1em;
+}
+
+/* nested things. like the ticket dates tab */
+.titlebox .titlebox .titlebox-title .right{
+ right: 1.3em;
+}
+
+#login-box .titlebox .titlebox-title .right {
+ margin-top: -0.1em;
+ right: 0em;
+}
+
+.titlebox
+{
+ height: auto !important;
+ height: 1.25em;
+}
+
+
+.ticket-transaction .messagebody img {
+ /* ie6 does not support max-width */
+ width: expression(this.width > 401 ? 400 : true);
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/nav.css b/rt/share/html/NoAuth/css/freeside2.1/nav.css
new file mode 100644
index 000000000..8a52e62c4
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/nav.css
@@ -0,0 +1,206 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+div#nav {
+ position: absolute;
+ left: 0;
+ font-size: 0.9em;
+ top: 3.2em;
+ width: 10.5em;
+ background: #fff;
+ -moz-border-radius-bottomright: 0.5em;
+ -webkit-border-bottom-right-radius: 0.5em;
+ border-left: 1px solid #999;
+border-top: 1px solid #999;
+
+ -moz-border-radius-topright: 0.5em;
+ -webkit-border-top-right-radius: 0.5em;
+ z-index: 99;
+
+
+}
+
+div#nav ul {
+ padding-left: 0.75em;
+ margin-left: 0;
+ padding-right: 0.75em;
+ list-style-type: none;
+}
+
+div#nav li:first-child {
+ border-top: 1px solid #ccc;
+ padding-top: 0.25em;
+
+}
+
+div#nav li {
+ padding: 0.125em;
+ padding-bottom: 0.25em;
+ margin-bottom: 0.25em;
+ border-bottom: 1px solid #ccc;
+ padding-left: 0.5em;
+ margin-right: 0.25em;
+ margin-left: 0em;
+}
+
+div#nav li li:first-child {
+ margin-top: 0.25em;
+}
+div#nav li li {
+ margin-left: -0.5em;
+ padding-left: 0.25em;
+ margin-right: -0.5em;
+}
+
+div#nav li li:last-child {
+ margin-bottom: 0;
+ padding-bottom: 0;
+ border: none;
+}
+
+div#nav .bullet {
+ display: none;
+}
+
+div#nav .separator {
+display: none;
+}
+
+
+div#nav a, div#page-navigation a{
+ text-decoration: none;
+ font-weight: normal;
+ color: #000;
+}
+
+div#nav a:hover, div#page-navigation a:hover {
+ text-decoration: underline;
+}
+
+
+
+div#nav a.selected, div#page-navigation a.selected {
+ font-weight: bold;
+}
+
+
+div#nav a.selected:after {
+/* content: " > " */
+}
+
+div#page-navigation {
+ background: white;
+ position: relative;
+ /* width:100%; */
+ z-index: 10;
+
+}
+
+
+div#page-navigation ul {
+
+}
+
+div#page-navigation ul#page-menu {
+ display: block;
+ /* position: absolute; */
+ float: left;
+ left: 8em;
+ font-size: 0.9em;
+ top: 2.3em;
+ min-height: 1em;
+ background-color: white;
+ right: 0em;
+ padding-top:0.3em;
+ padding-bottom:0.5em;
+ padding-right: 4em;
+ border-top: 1px solid #aaa;
+
+}
+
+/* ie hack */
+* html div#page-navigation ul#page-menu {
+ left: 6.5em;
+ top: 3.2em;
+ padding-left: 2em;
+}
+
+
+div#page-navigation ul#actions-menu {
+ /* position: absolute; */
+ float: right;
+ right: 1em;
+ top: 5.2em;
+ margin-top: 0em;
+ padding: 0.25em;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+
+ background: #dedede;
+ border-left: 1px solid #aaa;
+ border-bottom: 2px solid #aaa;
+ -moz-border-radius-bottomleft: 0.5em;
+ -webkit-border-bottom-left-radius: 0.5em;
+ -moz-border-radius-topright: 0.25em;
+ -webkit-border-top-right-radius: 0.25em;
+
+
+
+}
+
+
+
+div#page-navigation ul li{
+ display: inline;
+
+}
+
+
+ul.page-navigation ul.page-menu {
+ float: right;
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/portlets.css b/rt/share/html/NoAuth/css/freeside2.1/portlets.css
new file mode 100644
index 000000000..d96d5a9f0
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/portlets.css
@@ -0,0 +1,71 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+table.myrt {
+ width: 100%;
+}
+
+table.dashboard {
+ width: 100%;
+ border: 0;
+}
+
+.quick-create .select-queue {
+ width: 12em;
+}
+
+.quick-create input[type="text"], .quick-create textarea {
+ width: 100%;
+
+}
+
+.reminders blockquote {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ margin-left: 1em;
+ margin-right: 1em;
+}
diff --git a/rt/share/html/NoAuth/css/freeside2.1/ticket-lists.css b/rt/share/html/NoAuth/css/freeside2.1/ticket-lists.css
new file mode 100644
index 000000000..799a391e5
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/ticket-lists.css
@@ -0,0 +1,172 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+table.ticket-list, table.queue-summary, table.collection {
+ margin-top: 0.75em;
+ font-size: 0.9em;
+ border: 1px solid #aaa;
+ border-bottom: 2px solid #999;
+ border-right: 2px solid #999;
+
+
+}
+
+table.queue-summary tr>*:first-child {
+ padding-left: 1em;
+
+}
+
+
+table.queue-summary tr>*:last-child {
+ padding-right: 1em;
+
+}
+
+table.ticket-list a, table.queue-summary a, table.collection a {
+ font-weight: bold;
+}
+
+
+table.ticket-list th.collection-as-table, table.collection th.collection-as-table {
+ background: #ddd;
+ font-size: 0.9em;
+ margin-bottom: 0.5em;
+ text-align: left;
+
+}
+
+
+table.queue-summary th.collection-as-table {
+ font-size: 0.9em;
+ margin-bottom: 0.5em;
+ text-align: right;
+
+}
+
+table.queue-summary th.collection-as-table:first-child {
+ text-align: left;
+
+}
+
+
+tr.collection-as-table+tr.collection-as-table th {
+ border-bottom: 2px solid grey;
+
+}
+
+
+
+
+table.queue-summary td {
+ background: #efefef;
+ border-bottom: 1px solid #ccc;
+}
+
+
+
+tr.evenline td {
+ background: #eee;
+}
+
+tr.oddline td {
+ background: #fff;
+
+}
+
+tr.evenline td, tr.oddline td {
+ padding-top: 0.5em;
+}
+
+
+
+tr.evenline+tr.evenline td, tr.oddline+tr.oddline td{
+ padding-top: 0;
+ border: none;
+}
+
+
+
+table.ticket-list td:first-child, table.ticket-list th:first-child {
+ padding-left: 1em;
+}
+
+table.ticket-list td:last-child, table.ticket-list th:last-child {
+ padding-right: 1em;
+}
+
+th.collection-as-table , td.collection-as-table {
+ padding-right: 0.5em;
+}
+
+.pagenum.a:hover, .paging a.nav:hover{
+text-decoration: underline;
+}
+
+
+.pagenum *, .paging a.nav{
+padding: .5em;
+}
+
+.currentpage{
+text-decoration: none;
+font-weight: bold;
+background: #eee;
+}
+
+div.paging{
+text-align: center;
+padding-bottom: 1em;
+}
+
+
+/* full-page ticket lists */
+#body>table.ticket-list {
+ margin-bottom: 2em;
+
+}
+
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/ticket-search.css b/rt/share/html/NoAuth/css/freeside2.1/ticket-search.css
new file mode 100644
index 000000000..7a31d3e82
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/ticket-search.css
@@ -0,0 +1,199 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+#comp-Search-Build #body {
+ position: relative;
+}
+
+#pick-criteria select {
+ width: 8em;
+}
+
+#pick-criteria tr {
+ height: 1.5em;
+}
+
+#pick-criteria td.label {
+ font: message-box;
+ padding-right: 0.5em;
+ width: 11em;
+}
+
+#pick-criteria td.label * {
+ width: 8.5em;
+}
+
+#pick-criteria td.label select {
+ text-align: right;
+}
+
+#pick-criteria td.operator {
+ padding-right: 0.5em;
+ text-align: left;
+ vertical-align: bottom;
+ width: 7em;
+}
+
+#pick-criteria td.operator select {
+ text-align: right;
+}
+
+#pick-criteria td.value input,
+#pick-criteria td.value select {
+ width: 10em;
+}
+
+#pick-criteria td.value #ValueOfDate {
+ width: 6em;
+}
+
+
+#pick-criteria td.value #ValueOfTime {
+ width: 4em;
+
+}
+
+#pick-criteria td.value #ValueOfTime-TimeUnits{
+ width: 5.5em;
+}
+
+#pick-criteria td.value {
+ padding-right: 0.5em;
+ text-align: left;
+ font: message-box;
+}
+
+#editquery, #editsearches{
+ position: absolute;
+ margin-top: 0.2em;
+ right: 1em;
+ left: 60%;
+ top: 1em;
+/* margin-top: -1em; */
+}
+
+#editquery {
+ top: 1.3em;
+}
+
+
+#editsearches {
+ top: 24em;
+}
+
+
+#pick-criteria {
+ width: 58%;
+ padding-top: 0em;
+ margin-top: 0em;
+}
+
+#pick-criteria .titlebox-content {
+ overflow-x: auto;
+}
+
+#comp-Search-Build .submit {
+ width: 58%;
+}
+
+
+#sorting.titlebox {
+ width: 55%;
+ padding-right: 1em;
+}
+
+#comp-Search-Build #columns {
+}
+
+#display-options .submit {
+ width: 100%;
+}
+
+
+
+.search-result-views {
+ position: absolute;
+ top: 0;
+ right: 0;
+ margin-top: -2px;
+ margin-right: 0em;
+ padding: 0.25em;
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+ background-color: #ccc;
+ border-left: 1px solid #999;
+ border-bottom: 1px solid #999;
+ -moz-border-radius-bottomleft: 0.5em;
+ -webkit-border-bottom-left-radius: 0.5em;
+}
+
+
+
+.search-result-views li {
+
+ display: inline;
+}
+
+.search-result-views li:after {
+ content: " \00b7 ";
+}
+
+.search-result-views li:last-child:after {
+ content: "";
+
+}
+
+
+.refresh {
+ float: left;
+}
+
+/* Force some widget to fit at max parent box */
+#HomeRefreshInterval, #SavedSearchLoad, #SavedSearchOwner {
+ max-width: 100%;
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/ticket.css b/rt/share/html/NoAuth/css/freeside2.1/ticket.css
new file mode 100644
index 000000000..78477e0d4
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/ticket.css
@@ -0,0 +1,230 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+div#ticket-history div.ticket-transaction {
+ border-top: 1px solid #ccc;
+ padding-bottom: 0.25em;
+
+}
+
+div#ticket-history div.odd {
+ background-color: #fff;
+}
+
+div#ticket-history {
+
+ margin-top: 0.75em;
+ border-left: 1px solid #ccc;
+
+ border-right: 2px solid #999;
+ border-bottom: 2px solid #999;
+
+}
+
+.ticket-transaction div.metadata span.actions {
+ position: absolute;
+ right: 2.3em;
+ padding: 0em;
+ background: #ccc;
+ text-align: right;
+ border-left: 1px solid #999;
+ border-bottom: 1px solid #999;
+ color: #ccc;
+ -moz-border-radius-bottomleft: 0.5em;
+ -webkit-border-bottom-left-radius: 0.5em;
+ white-space: nowrap;
+}
+
+.ticket-transaction div.metadata span.type {
+ text-align: center;
+ float: left;
+ margin: 0.25em 0.70em 0.25em 0.25em;
+ width: 1em;
+ height: 1.25em;
+ padding: 0.75em 0 0 0;
+ border-right: 1px solid #999;
+ border-bottom: 1px solid #999;
+ -moz-border-radius: 0.25em;
+ -webkit-border-bottom-right-radius: 0.25em;
+}
+
+div#ticket-history span.type a {
+ color: #fff;
+}
+
+
+div#ticket-history span.date {
+ width: 10em;
+}
+
+
+div#ticket-history span.description {
+ margin-left: 1em;
+ font-weight: bold;
+}
+
+div#ticket-history span.time-taken {
+ margin-left: 1em;
+}
+
+div#ticket-history div.content {
+ padding-right: 1em;
+ padding-bottom: 0.7em;
+ font-size: 1.1em;
+ margin-left: 1.5em;
+}
+
+.plain-text-white-space {
+ white-space: pre-wrap;
+ font-family: monospace;
+}
+
+.ticket-transaction .messagebody {
+ font-size: 1em;
+ padding-left: 1em;
+ margin-top: 0.5em;
+ padding-top: 0.5em;
+ border-top: 1px solid #ccc;
+ /*overflow: auto; */
+ min-height: 2.5em;
+ /* To avoid overlapping of "downloadattachment" by messagebody */
+ clear: left;
+}
+
+.ticket-transaction .messagebody img {
+ max-width: 100%;
+}
+
+div#ticket-history div.downloadattachment {
+float: right;
+clear: both;
+font-size: 0.9em;
+text-align: right;
+background: #ddd;
+padding: 0.5em;
+margin-left: 1em;
+
+border: 1px solid #ccc;
+border-right: 2px solid #aaa;
+border-bottom: 2px solid #aaa;
+margin-top: 0.5em;
+-moz-border-radius: 0.5em;
+-webkit-border-radius: 0.5em;
+
+}
+
+div#ticket-history div.downloadattachment .downloadcontenttype{
+color: #666;
+padding-right:0.25em;
+}
+
+
+div#ticket-history .message-header-key {
+ width: 7em;
+ font-weight: bold;
+ color: #666;
+}
+
+
+div#ticket-history .messagebody .messagebody{
+ font-size: 1em;
+ padding: 0;
+ border: 0;
+ margin: 0;
+}
+
+
+
+.ticket-transaction.basics .type { background: #b32; }
+.ticket-transaction.cfs .type { background: #b32; }
+.ticket-transaction.people .type { background: #48c; }
+.ticket-transaction.links .type { background: #316531; }
+.ticket-transaction.dates .type { background: #633063; }
+.ticket-transaction.message .type { background: #069; }
+.ticket-transaction.reminders .type { background: #369; }
+.ticket-transaction.other .type { background: #abc; }
+
+
+
+
+.ticket-info-cfs .titlebox-title .left { background-color: #b32; color: #fff;}
+.ticket-info-basics .titlebox-title .left { background-color: #b32; color: #fff;}
+.ticket-info-people .titlebox-title .left { background-color: #48c; color: #fff;}
+.ticket-info-requestor .titlebox-title .left { white-space: nowrap; background-color: #48c; color: #fff;}
+.ticket-info-links .titlebox-title .left { background-color: #316531; color: #fff;}
+.ticket-info-reminders .titlebox-title .left { background-color: #369; color: #fff;}
+.ticket-info-dates .titlebox-title .left { background-color: #633063; color: #fff;}
+.ticket-info-attachments .titlebox-title .left { background-color: #993366; color: #fff;}
+
+
+.ticket-summary .titlebox-title a, div#body .ticket-summary .titlebox-title a:visited { color: #fff;}
+
+.unread-messages .titlebox , .unread-messages .titlebox-title .left {
+ border: 1px solid #99a;
+ border-right: 2px solid #aab;
+ border-bottom: 2px solid #aab;
+
+}
+
+
+.unread-messages .titlebox {
+ background-color: #dde;
+}
+
+.unread-messages .titlebox-title .left {
+ background-color: #cce;
+}
+
+.ticket-inactive {
+ text-decoration: line-through;
+ color: #666
+}
+
+table.ticket-summary td.boxcontainer:first-child {
+ width: 50%;
+}
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/tools.css b/rt/share/html/NoAuth/css/freeside2.1/tools.css
new file mode 100644
index 000000000..843feb27f
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/tools.css
@@ -0,0 +1,56 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+table.myday td {
+ padding: 1em;
+}
+
+ol.dashboard-queries {
+ padding-left: 1.5em;
+}
+
+
diff --git a/rt/share/html/NoAuth/css/freeside2.1/yui-fonts.css b/rt/share/html/NoAuth/css/freeside2.1/yui-fonts.css
new file mode 100644
index 000000000..fdae8d98f
--- /dev/null
+++ b/rt/share/html/NoAuth/css/freeside2.1/yui-fonts.css
@@ -0,0 +1,7 @@
+/*
+Copyright (c) 2008, Yahoo! Inc. All rights reserved.
+Code licensed under the BSD License:
+http://developer.yahoo.net/yui/license.txt
+version: 2.5.1
+*/
+body {font:13px/1.231 arial,helvetica,clean,sans-serif;*font-size:small;*font:x-small;}table {font-size:inherit;font:100%;}pre,code,kbd,samp,tt{font-family:monospace;*font-size:108%;line-height:100%;}
diff --git a/rt/share/html/NoAuth/css/print.css b/rt/share/html/NoAuth/css/print.css
index aaa1e8a2a..ae50342d8 100644
--- a/rt/share/html/NoAuth/css/print.css
+++ b/rt/share/html/NoAuth/css/print.css
@@ -80,7 +80,16 @@ div#header h1 {
#header #page-menu,
#header #actions-menu,
#header #page-navigation,
-.titlebox .title .widget,
+.titlebox .titlebox-title .widget,
+.ticket-info-links .titlebox-title .right,
+.ticket-info-links .titlebox-content .labeltop .create,
+.history .titlebox .titlebox-title .right,
+.ticket-transaction .metadata .actions,
+.ticket-transaction .content .downloadattachment,
+#comp-Search-Results #body .refresh,
+.search-result-actions,
+#comp-Search-Chart #body div,
+#comp-Search-Chart #body form,
#footer
{
display: none;
diff --git a/rt/share/html/NoAuth/css/web2/base.css b/rt/share/html/NoAuth/css/web2/base.css
index b98253af9..a38854fb5 100644
--- a/rt/share/html/NoAuth/css/web2/base.css
+++ b/rt/share/html/NoAuth/css/web2/base.css
@@ -45,13 +45,6 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-.hide { display: none; }
-.clear { display: none;}
-
-
-
-
-
a {
color: #000;
text-decoration: none;
diff --git a/rt/share/html/NoAuth/css/web2/boxes.css b/rt/share/html/NoAuth/css/web2/boxes.css
index 0f2f20c2b..fbd9af108 100644
--- a/rt/share/html/NoAuth/css/web2/boxes.css
+++ b/rt/share/html/NoAuth/css/web2/boxes.css
@@ -160,10 +160,6 @@
}
-.hidden {
- display: none;
-}
-
.titlebox .titlebox-title .widget a {
display: block;
margin: 0;
@@ -190,3 +186,7 @@
.titlebox.rolled-up .titlebox-title .widget a {
background-image: url(<%RT->Config->Get('WebPath')%>/NoAuth/images/css/rolldown-arrow.gif);
}
+
+.titlebox hr.clear {
+ display: none;
+}
diff --git a/rt/share/html/NoAuth/css/web2/collection.css b/rt/share/html/NoAuth/css/web2/collection.css
new file mode 100644
index 000000000..cbc8cefd7
--- /dev/null
+++ b/rt/share/html/NoAuth/css/web2/collection.css
@@ -0,0 +1,52 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+
+table.collection td:first-child, table.collection th:first-child {
+ padding-left: 1em;
+}
+
diff --git a/rt/share/html/NoAuth/css/web2/main.css b/rt/share/html/NoAuth/css/web2/main.css
index 5ca561456..a47700354 100644
--- a/rt/share/html/NoAuth/css/web2/main.css
+++ b/rt/share/html/NoAuth/css/web2/main.css
@@ -62,6 +62,7 @@
@import "ticket.css";
@import "tools.css";
@import "admin.css";
+@import "collection.css";
@import "misc.css";
% $m->callback(CallbackName => 'End');
diff --git a/rt/share/html/NoAuth/css/web2/misc.css b/rt/share/html/NoAuth/css/web2/misc.css
index eef5f4876..80d7ce0b4 100644
--- a/rt/share/html/NoAuth/css/web2/misc.css
+++ b/rt/share/html/NoAuth/css/web2/misc.css
@@ -45,6 +45,9 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+
+@import "../base/misc.css";
+
#body.calpopup {
margin-left: 1em;
margin-top: 1em;
@@ -71,29 +74,6 @@
font-size: 1.5em;
}
-div.autocomplete {
- position: absolute;
- background-color: white;
- border: 1px solid #888;
- margin: 0px;
- padding: 0px;
-}
-div.autocomplete ul {
- list-style-type: none;
- margin: 0px;
- padding: 0px;
-}
-div.autocomplete ul li.selected {
- background-color: #0088cc;
- color: #eee;
-}
-div.autocomplete ul li {
- list-style-type: none;
- display: block;
- margin: 0;
- padding: 2px;
-}
-
.comment {
padding-left: 0.5em;
color: #999;
@@ -105,4 +85,3 @@ div.autocomplete ul li {
margin-top: 1em;
overflow: auto;
}
-
diff --git a/rt/share/html/NoAuth/css/web2/msie.css b/rt/share/html/NoAuth/css/web2/msie.css
index 184ac1df5..2297c304a 100644
--- a/rt/share/html/NoAuth/css/web2/msie.css
+++ b/rt/share/html/NoAuth/css/web2/msie.css
@@ -237,3 +237,10 @@ table.queue-summary td, td.collection-as-table {
#pick-criteria td.operator {
width: 7.5em;
}
+
+.plain-text-white-space {
+ word-wrap: break-word; /* Internet Explorer 5.5+ */
+ white-space: pre; /* IE only hack to re-specify in addition to
+ word-wrap */
+}
+
diff --git a/rt/share/html/NoAuth/css/web2/portlets.css b/rt/share/html/NoAuth/css/web2/portlets.css
index 947f49db2..d96d5a9f0 100644
--- a/rt/share/html/NoAuth/css/web2/portlets.css
+++ b/rt/share/html/NoAuth/css/web2/portlets.css
@@ -63,3 +63,9 @@ table.dashboard {
}
+.reminders blockquote {
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
+ margin-left: 1em;
+ margin-right: 1em;
+}
diff --git a/rt/share/html/NoAuth/images/autohandler b/rt/share/html/NoAuth/images/autohandler
index 431a44f1d..7abf8b89e 100644
--- a/rt/share/html/NoAuth/images/autohandler
+++ b/rt/share/html/NoAuth/images/autohandler
@@ -3,5 +3,6 @@
# properly configured their webserver to stop RT from passing
# images through the mason handler.
my $file = $m->base_comp->source_file;
-RT::Interface::Web->SendStaticFile( File => $file );
+my $relfile = $m->base_comp->path;
+RT::Interface::Web->SendStaticFile( File => $file, RelativeFile => $relfile );
</%INIT>
diff --git a/rt/share/html/NoAuth/images/created.png b/rt/share/html/NoAuth/images/created.png
new file mode 100644
index 000000000..4d5eeb9ea
--- /dev/null
+++ b/rt/share/html/NoAuth/images/created.png
Binary files differ
diff --git a/rt/share/html/NoAuth/images/created_due.png b/rt/share/html/NoAuth/images/created_due.png
new file mode 100644
index 000000000..52dfc96f0
--- /dev/null
+++ b/rt/share/html/NoAuth/images/created_due.png
Binary files differ
diff --git a/rt/share/html/NoAuth/images/due.png b/rt/share/html/NoAuth/images/due.png
new file mode 100644
index 000000000..30a3aff8a
--- /dev/null
+++ b/rt/share/html/NoAuth/images/due.png
Binary files differ
diff --git a/rt/share/html/NoAuth/images/reminder.png b/rt/share/html/NoAuth/images/reminder.png
new file mode 100644
index 000000000..4370b6902
--- /dev/null
+++ b/rt/share/html/NoAuth/images/reminder.png
Binary files differ
diff --git a/rt/share/html/NoAuth/images/resolved.png b/rt/share/html/NoAuth/images/resolved.png
new file mode 100644
index 000000000..09db36d5a
--- /dev/null
+++ b/rt/share/html/NoAuth/images/resolved.png
Binary files differ
diff --git a/rt/share/html/NoAuth/images/started.png b/rt/share/html/NoAuth/images/started.png
new file mode 100644
index 000000000..e177addea
--- /dev/null
+++ b/rt/share/html/NoAuth/images/started.png
Binary files differ
diff --git a/rt/share/html/NoAuth/images/starts.png b/rt/share/html/NoAuth/images/starts.png
new file mode 100644
index 000000000..88064ba50
--- /dev/null
+++ b/rt/share/html/NoAuth/images/starts.png
Binary files differ
diff --git a/rt/share/html/NoAuth/images/starts_due.png b/rt/share/html/NoAuth/images/starts_due.png
new file mode 100644
index 000000000..16a4de46f
--- /dev/null
+++ b/rt/share/html/NoAuth/images/starts_due.png
Binary files differ
diff --git a/rt/share/html/NoAuth/images/updated.png b/rt/share/html/NoAuth/images/updated.png
new file mode 100644
index 000000000..680e79a54
--- /dev/null
+++ b/rt/share/html/NoAuth/images/updated.png
Binary files differ
diff --git a/rt/share/html/NoAuth/js/autohandler b/rt/share/html/NoAuth/js/autohandler
index 74028f8c6..e81415433 100644
--- a/rt/share/html/NoAuth/js/autohandler
+++ b/rt/share/html/NoAuth/js/autohandler
@@ -51,7 +51,8 @@ my $type;
my $file = $m->base_comp->source_file;
if ($file =~ /\.(gif|png|jpe?g)$/i) {
- RT::Interface::Web->SendStaticFile( File => $file );
+ my $relfile = $m->base_comp->path;
+ RT::Interface::Web->SendStaticFile( File => $file, RelativeFile => $relfile );
} else {
&RT::Interface::Web::StaticFileHeaders();
$r->content_type('application/x-javascript');
diff --git a/rt/share/html/NoAuth/rss/dhandler b/rt/share/html/NoAuth/rss/dhandler
new file mode 100644
index 000000000..c402b6f8e
--- /dev/null
+++ b/rt/share/html/NoAuth/rss/dhandler
@@ -0,0 +1,48 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+<& /Search/Elements/ResultsRSSView, %ARGS &>
diff --git a/rt/share/html/Prefs/Calendar.html b/rt/share/html/Prefs/Calendar.html
new file mode 100644
index 000000000..5fbdd2717
--- /dev/null
+++ b/rt/share/html/Prefs/Calendar.html
@@ -0,0 +1,123 @@
+<%args>
+$ChangeURL => undef
+$ResetURL => undef
+$SearchType => 'Ticket'
+$HiddenField => undef
+</%args>
+
+<& /Elements/Header, Title => $title &>
+<& /User/Elements/Tabs,
+ current_tab => 'Prefs/Calendar.html',
+ Title => $title
+&>
+
+<&| /Widgets/TitleBox, title => loc('ICal Feeds (ics)') &>
+
+<&| /Widgets/TitleBox, title => 'Help' &>
+
+<h3>displaying reminders :</h3>
+<p>If you want to have reminders in a search you need to go in the <a
+href="<%$RT::WebPath%>/Search/Edit.html"><%loc("Edit Query")%></a> tab
+of the <%loc("query builder")%> and add something like that :
+
+ <pre>
+ AND ( Type = 'ticket' OR Type = 'reminder' )
+</pre>
+</p>
+
+<h3>displaying other kind of dates :</h3>
+<p>By default RTx::Calendar display Due and Starts dates. You can
+select other kind of events you want with the <%loc("Display
+Columns")%> section in the <a
+href="<%$RT::WebPath%>/Search/Build.html"><%loc("Query
+Builder")%></a>. The following one will display the two latter and
+LastUpdated dates :
+
+<pre>
+ '&lt;small&gt;__Due__&lt;/small&gt;',
+ '&lt;small&gt;__Starts__&lt;/small&gt;',
+ '&lt;small&gt;__LastUpdated__&lt;/small&gt;'
+</pre>
+</p>
+
+<h3>changing the default query :</h3>
+<p>You can change the default Query of Calendar.html and MyCalendar
+portlet by saving a query with the name <code>calendar</code> in the
+<a href="<%$RT::WebPath%>/Search/Build.html"><%loc("Query
+Builder")%></a>.</p>
+
+</&>
+
+<& /Prefs/Elements/CalendarFeed &>
+
+% # only allow this part if
+% if ($AllowSearch) {
+
+% my $search_count;
+
+% # I'm quite sure the loop isn't usefull but...
+% my @Objects = $session{CurrentUser}->UserObj;
+% for my $object (@Objects) {
+% next unless ref($object) eq 'RT::User' && $object->id == $session{'CurrentUser'}->Id;
+% my @searches = $object->Attributes->Named('SavedSearch');
+% for my $search (@searches) {
+% next if ($search->SubValue('SearchType')
+% && $search->SubValue('SearchType') ne $SearchType);
+% $search_count++;
+<& /Prefs/Elements/CalendarFeed, Object => $object, Search => $search &>
+
+% }
+% }
+% unless ($search_count) {
+
+<&| /Widgets/TitleBox, title => loc('Private Search ICal feeds')
+ , title_class=> 'inverse'
+ , color => "#993333" &>
+
+You can add private ICal feeds by saving new queries in <a
+href="<%$RT::WebPath . '/Search/Build.html'%>">the Query Builder</a>
+
+</&>
+
+% }
+% } else {
+%#<&| /Widgets/TitleBox, title => loc('Private Search ICal feeds')
+%# , title_class=> 'inverse'
+%# , color => "#993333" &>
+%#
+%#<%loc('Private search ICal feeds disabled. To enable them, ask your admin for "[_1]" and "[_2]" rights',
+%# loc('CreateSavedSearch'),
+%# loc('LoadSavedSearch') )%>
+%#
+%#</&>
+% }
+
+</&>
+
+<%INIT>
+use Digest::SHA1;
+use RT::SavedSearches;
+
+my $title = loc("Calendar Prefs");
+my $AllowSearch;
+
+$AllowSearch = 1
+ if $session{'CurrentUser'}->HasRight( Right => 'LoadSavedSearch',
+ Object=> $RT::System );
+
+my $object;
+
+if ($HiddenField eq 'Private') {
+ $object = $session{CurrentUser}->UserObj;
+} elsif ($AllowSearch and my ($SearchId) = $HiddenField =~ m/SavedSearch\-(\d+)/) {
+ $object = $session{CurrentUser}->Attributes->WithId($SearchId);
+}
+
+if (defined $ChangeURL) {
+ my @args = $object->SetAttribute(Name => 'ICalURL', Content => Digest::SHA1::sha1_base64(time));
+} elsif (defined $ResetURL) {
+ my @args = $object->DeleteAttribute('ICalURL');
+}
+
+
+</%INIT>
diff --git a/rt/share/html/Prefs/Elements/CalendarFeed b/rt/share/html/Prefs/Elements/CalendarFeed
new file mode 100644
index 000000000..46893435e
--- /dev/null
+++ b/rt/share/html/Prefs/Elements/CalendarFeed
@@ -0,0 +1,68 @@
+<%args>
+$Search => undef
+$Object => undef
+$HiddenField => undef
+</%args>
+
+<&| /Widgets/TitleBox, title => $title &>
+
+% if ($FeedText) {
+<p><%$FeedText%></p>
+% } else {
+This feed will show tickets with due date find with query:<br />
+"<%$Search->SubValue('Query')%>".
+% }
+
+% if ($ICalURL) {
+<p>Your can paste this url in your calendar : <b><a href="<%$link%>"><%$link%></a></b><p>
+<table>
+<tr>
+<td>
+<form action="<%$RT::WebPath%>/Prefs/Calendar.html" method="post">
+<input type="hidden" name="HiddenField" value="<%$HiddenField%>" />
+<input type="submit" class="button" name="ResetURL" value="<%loc('Disable Feed')%>" />
+</form>
+</td>
+<td>
+<form action="<%$RT::WebPath%>/Prefs/Calendar.html" method="post">
+<input type="hidden" name="HiddenField" value="<%$HiddenField%>" />
+<input type="submit" class="button" name="ChangeURL" value="<%loc('Change Feed URL')%>" />
+</form>
+</td>
+</tr>
+</table>
+% } else {
+
+<form action="<%$RT::WebPath%>/Prefs/Calendar.html" method="post">
+<input type="hidden" name="HiddenField" value="<%$HiddenField%>" />
+<input type="submit" class="button" name="ChangeURL" value="<%loc('Enable Feed')%>" />
+</form>
+% }
+
+</&>
+
+<%init>
+my $title;
+my $ICalURL;
+my $Id;
+my $FeedText;
+my $link;
+
+if ($Object) {
+ $title = loc('Feed for "') . ($Search->Description || loc('Unnamed search')) . '" search';
+ $HiddenField = "SavedSearch-" . $Search->Id;
+ $ICalURL = $Search->FirstAttribute('ICalURL');
+ $Id = $session{CurrentUser}->Id . "@" . $Search->Id;
+ $title .= " (disabled)" unless $ICalURL;
+} else {
+ $title = loc('Feed for default calendar');
+ $HiddenField = "Private";
+ $ICalURL = $session{CurrentUser}->UserObj->FirstAttribute('ICalURL');
+ $Id = $session{CurrentUser}->Id;
+ $FeedText = "This feed will show yours and Nobody's tasks with due date.";
+}
+
+$link = $RT::WebURL . "NoAuth/Calendar/" . $Id . "/" . $ICalURL->Content
+ if $ICalURL;
+
+</%init> \ No newline at end of file
diff --git a/rt/share/html/Prefs/SearchOptions.html b/rt/share/html/Prefs/SearchOptions.html
index e40265f23..5e5ed46f1 100644
--- a/rt/share/html/Prefs/SearchOptions.html
+++ b/rt/share/html/Prefs/SearchOptions.html
@@ -45,7 +45,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/share/html/Search/Build.html b/rt/share/html/Search/Build.html
index 0fd79742a..c5067d5d1 100644
--- a/rt/share/html/Search/Build.html
+++ b/rt/share/html/Search/Build.html
@@ -85,9 +85,9 @@
<div id="pick-criteria">
<& Elements/PickCriteria, query => $query{'Query'}, cfqueues => $queues &>
-</div>
<& /Elements/Submit, Label => loc('Add these terms'), Name => 'AddClause'&>
<& /Elements/Submit, Label => loc('Add these terms and Search'), Name => 'DoSearch'&>
+</div>
<div id="editquery">
diff --git a/rt/share/html/Search/Bulk.html b/rt/share/html/Search/Bulk.html
index fa20e331c..f2ca45c26 100755
--- a/rt/share/html/Search/Bulk.html
+++ b/rt/share/html/Search/Bulk.html
@@ -163,7 +163,9 @@
<input type="submit" class="button" name="AddMoreAttach" value="<&|/l&>Add More Files</&>" />
<input type="hidden" class="hidden" name="UpdateAttach" value="1" /></td></tr>
<tr><td class="labeltop"><&|/l&>Message</&>:</td><td>
- <& /Elements/MessageBox, Name=>"UpdateContent"&>
+%# Currently, bulk update always starts with Comment not Reply selected, so we check this unconditionally
+% my $IncludeSignature = RT->Config->Get('MessageBoxIncludeSignatureOnComment');
+<& /Elements/MessageBox, Name => "UpdateContent", IncludeSignature => $IncludeSignature &>
</td></tr>
</table>
diff --git a/rt/share/html/Search/Calendar.html b/rt/share/html/Search/Calendar.html
new file mode 100644
index 000000000..9d2b6f546
--- /dev/null
+++ b/rt/share/html/Search/Calendar.html
@@ -0,0 +1,238 @@
+<%args>
+$Month => (localtime)[4]
+$Year => (localtime)[5] + 1900
+$Query => undef
+$Format => undef
+$Order => undef
+$OrderBy => undef
+$RowsPerPage => undef
+$NewQuery => 0
+</%args>
+
+<& /Elements/Header, Title => $title &>
+<& /Ticket/Elements/Tabs,
+ current_tab => "Search/Calendar.html?$QueryString",
+ Title => $title &>
+<&| /Widgets/TitleBox,
+ title => loc('Calendar for ') . $rtdate->GetMonth($Month) . " $Year" ,
+ title_class=> 'inverse',
+ color => "#993333" &>
+
+<table width="100%">
+<tr>
+<td align="left">
+% my ($PMonth, $PYear) = ($Month - 1, $Year);
+% if ($PMonth < 0) {
+% $PYear--;
+% $PMonth = 11;
+% }
+<a href="<%$RT::WebPath%>/Search/Calendar.html?Month=<%$PMonth%>&Year=<%$PYear%>&<%$QueryString%>">«<%$rtdate->GetMonth($PMonth)%></a>
+</td>
+<th align="center">
+ <font size="+1"><% $rtdate->GetMonth($Month). " $Year" %></font>
+</th>
+<td align="right">
+% my ($NMonth, $NYear) = ($Month + 1, $Year);
+% if ($NMonth > 11) {
+% $NYear++;
+% $NMonth = 0;
+% }
+<a href="<%$RT::WebPath%>/Search/Calendar.html?Month=<%$NMonth%>&Year=<%$NYear%>&<%$QueryString%>"><%$rtdate->GetMonth($NMonth)%>»</a>
+</td>
+</tr>
+</table>
+
+<table class="rtxcalendar">
+
+<thead>
+<tr>
+% for ( @{$week{$weekstart}} ) {
+<th width="14%"><%$rtdate->GetWeekday($_)%></th>
+% }
+</tr>
+</thead>
+
+<tbody>
+<tr>
+% while ($date <= $end) {
+%
+% my $offmonth = $date->month != ($Month + 1);
+% my $is_today = (DateTime->compare($today, $date) == 0);
+% my $is_yesterday = (DateTime->compare($yesterday, $date) == 0);
+% my $is_aweekago = (DateTime->compare($aweekago, $date) == 0);
+
+ <td class="<% $offmonth ? 'offmonth'
+ : $is_today ? 'today'
+ : $is_yesterday ? 'yesterday'
+ : $is_aweekago ? 'aweekago'
+ : ''
+ %>"
+ >
+ <div class="<% $is_today ? 'todays'
+ : $offmonth ? 'offmonth'
+ :'' %>calendardate"
+ ><%$date->day%></div>
+
+% my $sp = 3;
+% for my $t ( @{ $Tickets{$date->strftime("%F")} } ) {
+% $sp--;
+ <& /Elements/CalendarEvent, Object => $t, Date => $date, DateTypes => \%DateTypes &>
+% }
+ <% ($sp>0) ? '<BR>'x$sp : '' |n %>
+
+ </td>
+
+% $date = $set->next($date);
+% if ( $date->day_of_week == $startday_of_week ) {
+ </tr><tr>
+% }
+
+% }
+</tr>
+</tbody>
+</table>
+
+<table width="100%">
+<tr>
+<td align="left">
+<a href="<%$RT::WebPath%>/Search/Calendar.html?Month=<%$PMonth%>&Year=<%$PYear%>&<%$QueryString%>">«<%$rtdate->GetMonth($PMonth)%></a>
+</td>
+
+<td valign="top" align="center">
+<form action="<%$RT::WebPath%>/Search/Calendar.html?<%$QueryString%>" method="post">
+
+<select name="Month">
+% for (0..11) {
+<option value="<%$_%>" <% $_ == $Month ? 'selected' : ''%> ><%$rtdate->GetMonth($_)%></option>
+% }
+</select>
+% my $year = (localtime)[5] + 1900;
+<select name="Year">
+% for ( ($year-5) .. ($year+5)) {
+<option value="<%$_%>" <% $_ == $Year ? 'selected' : ''%>><%$_%></option>
+% }
+</select>
+
+%# <& /Elements/Submit&>
+<input type="submit" value="<% loc('Submit') %>" class="button" />
+
+</form>
+</td>
+
+<td align="right">
+<a href="<%$RT::WebPath%>/Search/Calendar.html?Month=<%$NMonth%>&Year=<%$NYear%>&<%$QueryString%>"><%$rtdate->GetMonth($NMonth)%>»</a>
+</td>
+</tr>
+</table>
+
+<table width="100%">
+<tr>
+
+<td valign="top" rowspan=9>
+ <BR>
+ <a href="<%$RT::WebPath%>/Prefs/Calendar.html">Calendar Preferences and Help</a>
+</td>
+
+% foreach my $legend (keys %legend) {
+ <tr>
+ <td align="right">
+ <img src="<%$RT::WebImagesURL%>/<%$legend%>.png" />
+ </td>
+ <td align="left">
+% my $more = 0;
+% foreach ( @{$legend{$legend}} ) {
+ <% $more++ ? ', ' : '' %>
+ <&|/l&><% $_ %></&>
+% }
+ </td>
+ </tr>
+% }
+
+</table>
+
+</&>
+
+<%ONCE>
+
+my %legend = (
+ 'created' => ['Created'],
+ 'due' => ['Due'],
+ 'resolved' => ['Resolved'],
+ 'updated' => ['Last Updated'],
+ 'created_due' => ['Created','Due'],
+ 'reminder' => ['Reminders'],
+ 'started' => ['Started'],
+ 'starts_due' => ['Starts','Due'],
+);
+
+</%ONCE>
+<%INIT>
+use RTx::Calendar qw(FirstDay LastDay);
+
+my $title = loc("Calendar");
+
+my @DateTypes = qw/Created Starts Started Due LastUpdated Resolved/;
+
+my $rtdate = RT::Date->new($session{'CurrentUser'});
+
+my $weekstart = 'Sunday'; #RT::SiteConfig? user pref?
+my %week = (
+ 'Saturday' => [6,0..5],
+ 'Sunday' => [0..6],
+ 'Monday' => [1..6,0],
+);
+my $startday_of_week = ${$week{$weekstart}}[0] || 7;
+my $endday_of_week = ${$week{$weekstart}}[-1] || 7;
+
+my $today = DateTime->today;
+my $yesterday = $today->clone->subtract( days=>1 );
+my $aweekago = $today->clone->subtract( days=>7 );
+my $date = FirstDay($Year, $Month + 1, $startday_of_week );
+my $end = LastDay ($Year, $Month + 1, $endday_of_week );
+
+# use this to loop over days until $end
+my $set = DateTime::Set->from_recurrence(
+ next => sub { $_[0]->truncate( to => 'day' )->add( days => 1 ) }
+);
+
+my $QueryString =
+ $m->comp(
+ '/Elements/QueryString',
+ Query => $Query,
+ Format => $Format,
+ Order => $Order,
+ OrderBy => $OrderBy,
+ Rows => $RowsPerPage
+ )
+ if ($Query);
+
+$QueryString ||= 'NewQuery=1';
+
+# Default Query and Format
+my $TempFormat = "__Starts__ __Due__";
+my $TempQuery = "( Status = 'new' OR Status = 'open' OR Status = 'stalled')
+ AND ( Owner = '" . $session{CurrentUser}->Id ."' OR Owner = 'Nobody' )
+ AND ( Type = 'reminder' OR 'Type' = 'ticket' )";
+
+if ( my $Search = RTx::Calendar::SearchDefaultCalendar($session{CurrentUser}) ) {
+ $TempFormat = $Search->SubValue('Format');
+ $TempQuery = $Search->SubValue('Query');
+}
+
+# we overide them if needed
+$TempQuery = $Query if $Query;
+$TempFormat = $Format if $Format;
+
+# we search all date types in Format string
+my @Dates = grep { $TempFormat =~ m/__${_}(Relative)?__/ } @DateTypes;
+
+# used to display or not a date in Element/CalendarEvent
+my %DateTypes = map { $_ => 1 } @Dates;
+
+$TempQuery .= RTx::Calendar::DatesClauses(\@Dates, $date->strftime("%F"), $end->strftime("%F"));
+
+# print STDERR ("-" x 30), "\n", $TempQuery, "\n";
+
+my %Tickets = RTx::Calendar::FindTickets($session{'CurrentUser'}, $TempQuery, \@Dates, $date->strftime("%F"), $end->strftime("%F"));
+
+</%INIT>
diff --git a/rt/share/html/Search/Chart b/rt/share/html/Search/Chart
index 59e9fc6fc..abee3e52a 100644
--- a/rt/share/html/Search/Chart
+++ b/rt/share/html/Search/Chart
@@ -66,52 +66,11 @@ if ($ChartStyle eq 'pie') {
use RT::Report::Tickets;
my $tix = RT::Report::Tickets->new( $session{'CurrentUser'} );
+
my ($count_name, $value_name) = $tix->SetupGroupings(
Query => $Query, GroupBy => $PrimaryGroupBy,
);
-my $chart = $chart_class->new( 600 => 400 );
-
-my $font = RT->Config->Get('ChartFont') || ['verdana', 'arial', gdMediumBoldFont];
-$chart->set_title_font( $font, 12 ) if $chart->can('set_title_font');
-$chart->set_legend_font( $font, 12 ) if $chart->can('set_legend_font');
-$chart->set_x_label_font( $font, 10 ) if $chart->can('set_x_label_font');
-$chart->set_y_label_font( $font, 10 ) if $chart->can('set_y_label_font');
-$chart->set_label_font( $font, 10 ) if $chart->can('set_label_font');
-$chart->set_x_axis_font( $font, 9 ) if $chart->can('set_x_axis_font');
-$chart->set_y_axis_font( $font, 9 ) if $chart->can('set_y_axis_font');
-$chart->set_values_font( $font, 9 ) if $chart->can('set_values_font');
-$chart->set_value_font( $font, 9 ) if $chart->can('set_value_font');
-
-# Pie charts don't like having no input, so we show a special image
-# that indicates an error message. Because this is used in an <img>
-# context, it can't be a simple error message. Without this check,
-# the chart will just be a non-loading image.
-if ($tix->Count == 0) {
- my $plot = GD::Image->new(600 => 400);
- $plot->colorAllocate(255, 255, 255); # background
- my $black = $plot->colorAllocate(0, 0, 0);
-
- require GD::Text::Wrap;
- my $error = GD::Text::Wrap->new($plot,
- color => $black,
- text => loc("No tickets found."),
- );
- $error->set_font( $font, 12 );
- $error->draw(0, 0);
-
- $m->comp( 'SELF:Plot', plot => $plot, %ARGS );
-}
-
-if ($chart_class eq "GD::Graph::bars") {
- $chart->set(
- x_label => $tix->Label( $PrimaryGroupBy ),
- x_labels_vertical => 1,
- y_label => loc('Tickets'),
- show_values => 1
- );
-}
-
my %class = (
Queue => 'RT::Queue',
Owner => 'RT::User',
@@ -121,15 +80,17 @@ my %class = (
my $class = $class{ $PrimaryGroupBy };
my %data;
+my $max_value = 0;
+my $max_key_length = 0;
while ( my $entry = $tix->Next ) {
my $key;
if ( $class ) {
my $q = $class->new( $session{'CurrentUser'} );
- $q->Load( $entry->__Value( $value_name ) );
+ $q->Load( $entry->LabelValue( $value_name ) );
$key = $q->Name;
}
else {
- $key = $entry->__Value($value_name);
+ $key = $entry->LabelValue($value_name);
}
$key ||= '(no value)';
@@ -140,26 +101,84 @@ while ( my $entry = $tix->Next ) {
$key = loc($key);
}
$data{ $key } = $value;
-}
-
-# XXX: Convert 1970-01-01 date to the 'Not Set'
-# this code should be generalized!!!
-if ( $PrimaryGroupBy =~ /(Daily|Monthly|Annually)$/ ) {
- my $re;
- $re = qr{1970-01-01} if $PrimaryGroupBy =~ /Daily$/;
- $re = qr{1970-01} if $PrimaryGroupBy =~ /Monthly$/;
- $re = qr{1970} if $PrimaryGroupBy =~ /Annually$/;
- foreach my $k (keys %data) {
- my $tmp = $k;
- $tmp =~ s/^$re/loc('Not Set')/e or next;
- $data{$tmp} = delete $data{$k};
- }
+ $max_value = $value if $max_value < $value;
+ $max_key_length = length $key if $max_key_length < length $key;
}
unless (keys %data) {
$data{''} = 0;
}
+
+my $chart = $chart_class->new( 600 => 400 );
+$chart->set( pie_height => 60 ) if $chart_class eq 'GD::Graph::pie';
+my %font_config = RT->Config->Get('ChartFont');
+my $font = $font_config{ $session{CurrentUser}->UserObj->Lang || '' }
+ || $font_config{'others'};
+$chart->set_title_font( $font, 16 ) if $chart->can('set_title_font');
+$chart->set_legend_font( $font, 16 ) if $chart->can('set_legend_font');
+$chart->set_x_label_font( $font, 14 ) if $chart->can('set_x_label_font');
+$chart->set_y_label_font( $font, 14 ) if $chart->can('set_y_label_font');
+$chart->set_label_font( $font, 14 ) if $chart->can('set_label_font');
+$chart->set_x_axis_font( $font, 12 ) if $chart->can('set_x_axis_font');
+$chart->set_y_axis_font( $font, 12 ) if $chart->can('set_y_axis_font');
+$chart->set_values_font( $font, 12 ) if $chart->can('set_values_font');
+$chart->set_value_font( $font, 12 ) if $chart->can('set_value_font');
+
+# Pie charts don't like having no input, so we show a special image
+# that indicates an error message. Because this is used in an <img>
+# context, it can't be a simple error message. Without this check,
+# the chart will just be a non-loading image.
+if ($tix->Count == 0) {
+ my $plot = GD::Image->new(600 => 400);
+ $plot->colorAllocate(255, 255, 255); # background
+ my $black = $plot->colorAllocate(0, 0, 0);
+
+ require GD::Text::Wrap;
+ my $error = GD::Text::Wrap->new($plot,
+ color => $black,
+ text => loc("No tickets found."),
+ );
+ $error->set_font( $font, 16 );
+ $error->draw(0, 0);
+
+ $m->comp( 'SELF:Plot', plot => $plot, %ARGS );
+}
+
+if ($chart_class eq "GD::Graph::bars") {
+ $chart->set(
+ x_label => $tix->Label( $PrimaryGroupBy ),
+ y_label => loc('Tickets'),
+ show_values => 1,
+ bar_spacing => 5,
+ bargroup_spacing => 10,
+ x_label_position => 0.6,
+ y_label_position => 0.6,
+ values_space => -1,
+# the following line to make sure there's enough space for values to show
+ y_max_value => 5*(int($max_value/5) + 2),
+# if there're too many bars or at least one key is too long, use vertical
+ x_labels_vertical => ( keys(%data) * $max_key_length > 60 ) ? 1 : 0,
+ );
+}
+
+# refine values' colors, with both Color::Scheme's help and my own tweak
+$chart->{dclrs} = [
+ '66cc66', 'ff6666', 'ffcc66', '663399',
+ '3333cc',
+ '339933', '993333', '996633', '663399',
+ '33cc33', 'cc3333', 'cc9933', '6633cc'
+];
+
+{
+ no warnings 'redefine';
+ *GD::Graph::pick_data_clr = sub {
+ my $self = shift;
+ my $color_hex = $self->{dclrs}[ $_[0] % @{ $self->{dclrs} } - 1 ];
+ return map { hex } ( $color_hex =~ /(..)(..)(..)/ );
+ };
+}
+
my $plot = $chart->plot( [ [sort keys %data], [map $data{$_}, sort keys %data] ] ) or die $chart->error;
$m->comp( 'SELF:Plot', plot => $plot, %ARGS );
</%init>
@@ -170,7 +189,6 @@ $plot => undef
</%ARGS>
<%INIT>
my @types = ('png', 'gif');
-
for my $type (@types) {
$plot->can($type)
or next;
diff --git a/rt/share/html/Search/Elements/BuildFormatString b/rt/share/html/Search/Elements/BuildFormatString
index 972851160..9935fdf91 100644
--- a/rt/share/html/Search/Elements/BuildFormatString
+++ b/rt/share/html/Search/Elements/BuildFormatString
@@ -71,6 +71,9 @@ $CurrentDisplayColumns => undef
# All the things we can display in the format string by default
my @fields = qw(
id QueueName Subject
+
+ Customer
+
Status ExtendedStatus UpdateStatus
Type
@@ -96,6 +99,7 @@ my @fields = qw(
Bookmark
NEWLINE
+
); # loc_qw
$m->callback( CallbackOnce => 1, CallbackName => 'SetFieldsOnce', Fields => \@fields );
diff --git a/rt/share/html/Search/Elements/Chart b/rt/share/html/Search/Elements/Chart
index 3db92c4d8..bf4cd0c1c 100644
--- a/rt/share/html/Search/Elements/Chart
+++ b/rt/share/html/Search/Elements/Chart
@@ -72,28 +72,16 @@ my (@keys, @values);
while ( my $entry = $tix->Next ) {
if ($class) {
my $q = $class->new( $session{'CurrentUser'} );
- $q->Load( $entry->__Value( $value_name ) );
+ $q->Load( $entry->LabelValue( $value_name ) );
push @keys, $q->Name;
}
else {
- push @keys, $entry->__Value( $value_name );
+ push @keys, $entry->LabelValue( $value_name );
}
$keys[-1] ||= loc('(no value)');
push @values, $entry->__Value( $count_name );
}
-# XXX: Convert 1970-01-01 date to the 'Not Set'
-# this code should be generalized!!!
-if ( $PrimaryGroupBy =~ /(Daily|Monthly|Annually)$/ ) {
- my $re;
- $re = qr{1970-01-01} if $PrimaryGroupBy =~ /Daily$/;
- $re = qr{1970-01} if $PrimaryGroupBy =~ /Monthly$/;
- $re = qr{1970} if $PrimaryGroupBy =~ /Annually$/;
- foreach (@keys) {
- s/^$re/loc('Not Set')/e;
- }
-}
-
my %data;
my %loc_keys;
foreach my $key (@keys) { $data{$key} = shift @values; $loc_keys{$key} = loc($key); }
@@ -126,7 +114,23 @@ my $query_string = $m->comp('/Elements/QueryString', %ARGS);
% $total += $value;
<tr class="<%$i%2 ? 'evenline' : 'oddline' %>">
<td class="label collection-as-table">
-<%$key%>
+%# TODO sadly we don't have "creator.city is null" or alike support yet
+%# so no link if the key is undef for now
+% if ( $PrimaryGroupBy !~ /(Hourly|Daily|Monthly|Annually)$/
+% && $key ne loc('(no value)') ) {
+% my $group = $PrimaryGroupBy; $group =~ s! !.!;
+% my %orig_keys = reverse %loc_keys;
+% my $QueryString = $m->comp('/Elements/QueryString',
+% Query => "$Query and $group = '$orig_keys{$key}'",
+% Format => $ARGS{Format},
+% Rows => $ARGS{Rows},
+% OrderBy => $ARGS{OrderBy},
+% Order => $ARGS{Order},
+% );
+<a href=<% RT->Config->Get('WebURL') %>Search/Results.html?<%$QueryString%>><%$key%></a>
+% } else {
+<% $key %>
+% }
</td>
<td class="value collection-as-table">
<%$value%>
diff --git a/rt/share/html/Search/Elements/DisplayOptions b/rt/share/html/Search/Elements/DisplayOptions
index 40d976cfd..7464ae936 100644
--- a/rt/share/html/Search/Elements/DisplayOptions
+++ b/rt/share/html/Search/Elements/DisplayOptions
@@ -115,6 +115,8 @@ $fields{$_}=1 for @cfs;
# Add PAW sort
$fields{'Custom.Ownership'} = 1;
+$fields{"Customer.$_"} = 1 foreach qw( Number Name ); #Freeside
+
my @Order = split /\|/, $Order;
my @OrderBy = split /\|/, $OrderBy;
if ($Order =~ /\|/) {
diff --git a/rt/share/html/Search/Elements/PickCFs b/rt/share/html/Search/Elements/PickCFs
index ba25cdeda..beda9f733 100644
--- a/rt/share/html/Search/Elements/PickCFs
+++ b/rt/share/html/Search/Elements/PickCFs
@@ -78,20 +78,41 @@ while ( my $CustomField = $CustomFields->Next ) {
my %line;
$line{'Name'} = "'CF.{" . $CustomField->Name . "}'";
$line{'Field'} = $CustomField->Name;
- $line{'Op'} = {
- Type => 'component',
- Path => '/Elements/SelectCustomFieldOperator',
- Arguments => { True => loc("is"),
- False => loc("isn't"),
- TrueVal=> '=',
- FalseVal => '!=',
- },
- };
- $line{'Value'} = {
- Type => 'component',
- Path => '/Elements/SelectCustomFieldValue',
- Arguments => { CustomField => $CustomField },
- };
+
+ # Op
+ if ($CustomField->Type eq 'Date') {
+ $line{'Op'} = {
+ Type => 'component',
+ Path => '/Elements/SelectDateRelation',
+ Arguments => {},
+ };
+ } else {
+ $line{'Op'} = {
+ Type => 'component',
+ Path => '/Elements/SelectCustomFieldOperator',
+ Arguments => { True => loc("is"),
+ False => loc("isn't"),
+ TrueVal=> '=',
+ FalseVal => '!=',
+ },
+ };
+ }
+
+ # Value
+ if ($CustomField->Type eq 'Date') {
+ $line{'Value'} = {
+ Type => 'component',
+ Path => '/Elements/SelectDate',
+ Arguments => {},
+ };
+ } else {
+ $line{'Value'} = {
+ Type => 'component',
+ Path => '/Elements/SelectCustomFieldValue',
+ Arguments => { CustomField => $CustomField },
+ };
+ }
+
push @lines, \%line;
}
diff --git a/rt/share/html/Search/Elements/ResultsRSSView b/rt/share/html/Search/Elements/ResultsRSSView
new file mode 100644
index 000000000..f335411f8
--- /dev/null
+++ b/rt/share/html/Search/Elements/ResultsRSSView
@@ -0,0 +1,143 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2009 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., 51 Franklin Street, Fifth Floor, Boston, MA
+%# 02110-1301 or visit their web page on the internet at
+%# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
+%#
+%#
+%# 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 }}}
+<%INIT>
+use Encode ();
+
+my $old_current_user;
+
+if ( $m->request_comp->path =~ RT->Config->Get('WebNoAuthRegex') ) {
+ my $path = $m->dhandler_arg;
+
+ my $notfound = sub {
+ my $mesg = shift;
+ $r->headers_out->{'Status'} = '404 Not Found';
+ $RT::Logger->info("Error encountered in rss generation: $mesg");
+ $m->clear_and_abort;
+ };
+
+ $notfound->("Invalid path: $path") unless $path =~ m!^([^/]+)/([^/]+)/?!;
+
+ my ( $name, $auth ) = ( $1, $2 );
+
+ # Unescape parts
+ $name =~ s/\%([0-9a-z]{2})/chr(hex($1))/gei;
+
+ # convert to perl strings
+ $name = Encode::decode_utf8($name);
+
+ my $user = RT::User->new($RT::SystemUser);
+ $user->Load($name);
+ $notfound->("Invalid user: $user") unless $user->id;
+
+ $notfound->("Invalid authstring")
+ unless $user->ValidateAuthString( $auth,
+ $ARGS{Query} . $ARGS{Order} . $ARGS{OrderBy} );
+
+ $old_current_user = $session{'CurrentUser'};
+ my $cu = RT::CurrentUser->new;
+ $cu->Load($user);
+ $session{'CurrentUser'} = $cu;
+}
+
+my $Tickets = RT::Tickets->new($session{'CurrentUser'});
+$Tickets->FromSQL($ARGS{'Query'});
+if ($OrderBy =~ /\|/) {
+ # Multiple Sorts
+ my @OrderBy = split /\|/,$OrderBy;
+ my @Order = split /\|/,$Order;
+ $Tickets->OrderByCols(
+ map { { FIELD => $OrderBy[$_], ORDER => $Order[$_] } } ( 0
+ .. $#OrderBy ) );;
+} else {
+ $Tickets->OrderBy(FIELD => $OrderBy, ORDER => $Order);
+}
+$r->content_type('application/rss+xml');
+
+
+
+ # create an RSS 1.0 file (http://purl.org/rss/1.0/)
+ use XML::RSS;
+ my $rss = new XML::RSS (version => '1.0');
+ $rss->channel(
+ title => RT->Config->Get('rtname').": Search " . $ARGS{'Query'},
+ link => RT->Config->Get('WebURL'),
+ description => "",
+ dc => {
+ },
+ generator => "RT v" . $RT::VERSION,
+ syn => {
+ updatePeriod => "hourly",
+ updateFrequency => "1",
+ updateBase => "1901-01-01T00:00+00:00",
+ },
+ );
+
+
+ while ( my $Ticket = $Tickets->Next()) {
+ my $creator_str = $m->scomp('/Elements/ShowUser', User => $Ticket->CreatorObj);
+ $creator_str =~ s/[\r\n]//g;
+ $rss->add_item(
+ title => $Ticket->Subject || loc('No Subject'),
+ link => RT->Config->Get('WebURL')."Ticket/Display.html?id=".$Ticket->id,
+ description => $Ticket->Transactions->First->Content,
+ dc => { creator => $creator_str,
+ date => $Ticket->CreatedObj->RFC2822,
+ },
+ guid => $Ticket->Queue . '_' . $Ticket->id,
+ );
+ }
+
+$m->out($rss->as_string);
+$session{'CurrentUser'} = $old_current_user if $old_current_user;
+$m->abort();
+</%INIT>
+<%ARGS>
+$OrderBy => 'Created'
+$Order => 'ASC'
+</%ARGS>
+
diff --git a/rt/share/html/Search/Results.html b/rt/share/html/Search/Results.html
index 13252eebb..22858f172 100755
--- a/rt/share/html/Search/Results.html
+++ b/rt/share/html/Search/Results.html
@@ -84,6 +84,7 @@
</div>
<div align="right" class="search-result-actions">
<& Elements/ResultViews,
+ Collection => $session{'tickets'},
QueryString => $QueryString,
Query => $Query,
Format => $Format,
@@ -118,6 +119,7 @@ if ( !defined($Rows) ) {
$Rows = 50;
}
}
+$Page = 1 unless $Page && $Page > 0;
my ($title, $ticketcount);
$session{'i'}++;
@@ -134,6 +136,8 @@ if ($OrderBy =~ /\|/) {
} else {
$session{'tickets'}->OrderBy(FIELD => $OrderBy, ORDER => $Order);
}
+$session{'tickets'}->RowsPerPage( $Rows ) if $Rows;
+$session{'tickets'}->GotoPage( $Page - 1 );
$session{'CurrentSearchHash'} = {
Format => $Format,
@@ -142,7 +146,7 @@ $session{'CurrentSearchHash'} = {
Order => $Order,
OrderBy => $OrderBy,
RowsPerPage => $Rows
- };
+};
if ( $session{'tickets'}->Query()) {
@@ -161,7 +165,10 @@ my $QueryString = "?".$m->comp('/Elements/QueryString',
Page => $Page);
my $ShortQueryString = "?".$m->comp('/Elements/QueryString', Query => $Query);
my $RSSQueryString = "?".$m->comp('/Elements/QueryString', Query => $Query, Order => $Order, OrderBy => $OrderBy);
-my $RSSFeedURL = RT->Config->Get('WebPath')."/Search/Results.rdf$RSSQueryString";
+my $RSSPath = join '/', map $m->interp->apply_escapes($_, 'u'),
+ $session{'CurrentUser'}->UserObj->Name,
+ $session{'CurrentUser'}->UserObj->GenerateAuthString( $Query.$Order.$OrderBy );
+my $RSSFeedURL = RT->Config->Get('WebPath')."/NoAuth/rss/$RSSPath/$RSSQueryString";
if ($ARGS{'TicketsRefreshInterval'}) {
$session{'tickets_refresh_interval'} = $ARGS{'TicketsRefreshInterval'};
diff --git a/rt/share/html/Search/Results.rdf b/rt/share/html/Search/Results.rdf
index 0a1943059..c402b6f8e 100644
--- a/rt/share/html/Search/Results.rdf
+++ b/rt/share/html/Search/Results.rdf
@@ -45,59 +45,4 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<%INIT>
-
-my $Tickets = RT::Tickets->new($session{'CurrentUser'});
-$Tickets->FromSQL($ARGS{'Query'});
-if ($OrderBy =~ /\|/) {
- # Multiple Sorts
- my @OrderBy = split /\|/,$OrderBy;
- my @Order = split /\|/,$Order;
- $Tickets->OrderByCols(
- map { { FIELD => $OrderBy[$_], ORDER => $Order[$_] } } ( 0
- .. $#OrderBy ) );;
-} else {
- $Tickets->OrderBy(FIELD => $OrderBy, ORDER => $Order);
-}
-$r->content_type('application/rss+xml');
-
-
-
- # create an RSS 1.0 file (http://purl.org/rss/1.0/)
- use XML::RSS;
- my $rss = new XML::RSS (version => '1.0');
- $rss->channel(
- title => RT->Config->Get('rtname').": Search" . $ARGS{'Query'},
- link => RT->Config->Get('WebURL'),
- description => "",
- dc => {
- },
- generator => "RT v" . $RT::VERSION,
- syn => {
- updatePeriod => "hourly",
- updateFrequency => "1",
- updateBase => "1901-01-01T00:00+00:00",
- },
- );
-
-
- while ( my $Ticket = $Tickets->Next()) {
- my $creator_str = $m->scomp('/Elements/ShowUser', User => $Ticket->CreatorObj);
- $creator_str =~ s/[\r\n]//g;
- $rss->add_item(
- title => $Ticket->Subject || loc('No Subject'),
- link => RT->Config->Get('WebURL')."Ticket/Display.html?id=".$Ticket->id,
- description => $Ticket->Transactions->First->Content,
- dc => { creator => $creator_str,
- date => $Ticket->CreatedObj->RFC2822,
- },
- guid => $Ticket->Queue . '_' . $Ticket->id,
- );
- }
-$m->out($rss->as_string);
-$m->abort();
-</%INIT>
-<%ARGS>
-$OrderBy => 'Created'
-$Order => 'ASC'
-</%ARGS>
+<& /Search/Elements/ResultsRSSView, %ARGS &>
diff --git a/rt/share/html/Search/Results.tsv b/rt/share/html/Search/Results.tsv
index bb3ac4482..946a35d02 100644
--- a/rt/share/html/Search/Results.tsv
+++ b/rt/share/html/Search/Results.tsv
@@ -107,7 +107,7 @@ $r->content_type('application/vnd.ms-excel');
$_ += @header - 1 foreach values %cf_name_to_pos;
- foreach my $name ( sort { $cf_name_to_pos{$a} <=> $cf_name_to_pos{$a} } keys %cf_name_to_pos ) {
+ foreach my $name ( sort { $cf_name_to_pos{$a} <=> $cf_name_to_pos{$b} } keys %cf_name_to_pos ) {
push @header, "CF-". $name;
}
$m->out(join("\t", @header));
diff --git a/rt/share/html/SelfService/Error.html b/rt/share/html/SelfService/Error.html
index 9c81ebbe6..8956c3ea1 100755
--- a/rt/share/html/SelfService/Error.html
+++ b/rt/share/html/SelfService/Error.html
@@ -66,6 +66,6 @@ $Why => loc("the calling component did not specify why")
</%args>
<%INIT>
-$Details ||= "No details";
+$Details ||= loc("No details");
$RT::Logger->error("WebRT: $Why ($Details)");
</%INIT>
diff --git a/rt/share/html/SelfService/Prefs.html b/rt/share/html/SelfService/Prefs.html
index dabab7937..468a3d508 100755
--- a/rt/share/html/SelfService/Prefs.html
+++ b/rt/share/html/SelfService/Prefs.html
@@ -50,13 +50,14 @@
<& /Elements/ListActions, actions => \@results &>
<form method="post">
-% unless (RT->Config->Get('WebExternalAuth') and !RT->Config->Get('WebFallbackToInternalAuth')) {
<&| /Widgets/TitleBox, title => loc('Change password') &>
-<&|/l&>New password</&>: <input type="password" name="NewPass1" size="16" autocomplete="off" />
-<&|/l&>Confirm</&>: <input type="password" name="NewPass2" size="16" autocomplete="off" />
+<& /Elements/EditPassword,
+ User => $user,
+ Name => [qw(CurrentPass NewPass1 NewPass2)],
+&>
</&>
+
<br />
-% }
<& /Elements/Submit, Label => loc('Save Changes') &>
</form>
@@ -64,29 +65,32 @@
<%INIT>
my @results;
-if ($NewPass1) {
- if ($NewPass1 ne $NewPass2) {
- push (@results, "Passwords did not match.");
- }
- else {
- my ($val, $msg)=$session{'CurrentUser'}->UserObj->SetPassword($NewPass1);
- push (@results, "Password: ".$msg);
- }
+my $user = $session{'CurrentUser'}->UserObj;
+
+if (defined $NewPass1 && length $NewPass1 ) {
+ my ($status, $msg) = $user->SafeSetPassword(
+ Current => $CurrentPass,
+ New => $NewPass1,
+ Confirmation => $NewPass2,
+ );
+ push @results, loc("Password: [_1]", $msg);
}
+
if ($Signature) {
$Signature =~ s/(\r\n|\r)/\n/g;
- if ($Signature ne $session{'CurrentUser'}->UserObj->Signature) {
- my ($val, $msg)=$session{'CurrentUser'}->UserObj->SetSignature($Signature);
+ if ($Signature ne $user->Signature) {
+ my ($val, $msg) = $user->SetSignature($Signature);
push (@results, "Signature: ".$msg);
}
}
-#A hack to make sure that session gets rewritten.
+#A hack to make sure that session gets rewritten.
$session{'i'}++;
</%INIT>
<%ARGS>
$Signature => undef
+$CurrentPass => undef
$NewPass1 => undef
$NewPass2 => undef
</%ARGS>
diff --git a/rt/share/html/Ticket/Attachment/dhandler b/rt/share/html/Ticket/Attachment/dhandler
index d4d556b24..8b41329ba 100755
--- a/rt/share/html/Ticket/Attachment/dhandler
+++ b/rt/share/html/Ticket/Attachment/dhandler
@@ -68,8 +68,11 @@
}
my $content_type = $AttachmentObj->ContentType || 'text/plain';
-
- unless (RT->Config->Get('TrustHTMLAttachments')) {
+
+ if (RT->Config->Get('AlwaysDownloadAttachments')) {
+ $r->headers_out->{'Content-Disposition'} = "attachment; filename=" . $AttachmentObj->Filename;
+ }
+ elsif (!RT->Config->Get('TrustHTMLAttachments')) {
$content_type = 'text/plain' if ($content_type =~ /^text\/html/i);
}
diff --git a/rt/share/html/Ticket/Checklist.html b/rt/share/html/Ticket/Checklist.html
new file mode 100644
index 000000000..7394b0c10
--- /dev/null
+++ b/rt/share/html/Ticket/Checklist.html
@@ -0,0 +1,30 @@
+<& /Elements/Header, Title => loc("Checklist for Ticket #[_1] [_2]", $Ticket->Id, $Ticket->Subject) &>
+<& /Ticket/Elements/Tabs,
+ Ticket => $Ticket, current_tab => 'Ticket/Checklist.html?id='.$Ticket->id,
+ Title => loc("Ticket Checklist # [_1] [_2]", $Ticket->Id, $Ticket->Subject) &>
+
+<& /Ticket/Elements/ShowMembers_Checklist, Ticket => $Ticket &>
+
+% if ( $show_hint ) {
+
+<A HREF="ModifyLinks.html?id=<%$Ticket->id%>">Link</A>
+or <A HREF="Create.html?Queue=<%$Ticket->QueueObj->Id%>&new-MemberOf=<%$Ticket->id%>">create</A>
+create child tickets to make a checklist.
+
+% }
+
+<%ARGS>
+$id => undef
+</%ARGS>
+
+<%INIT>
+
+my $Ticket = LoadTicket ($id);
+
+unless ($Ticket->CurrentUserHasRight('ShowTicket')) {
+ Abort("No permission to view ticket");
+}
+
+my $show_hint = ! $Ticket->Members->Count;
+
+</%INIT>
diff --git a/rt/share/html/Ticket/Create.html b/rt/share/html/Ticket/Create.html
index 28b655691..2c8e35778 100755
--- a/rt/share/html/Ticket/Create.html
+++ b/rt/share/html/Ticket/Create.html
@@ -112,6 +112,7 @@
</td>
<td class="value" colspan="5">
<input name="Subject" size="60" maxsize="200" value="<%$ARGS{Subject} || ''%>" />
+% $m->callback( %ARGS, CallbackName => 'AfterSubject' );
</td>
</tr>
<tr>
@@ -158,6 +159,7 @@
% } else {
<& /Elements/MessageBox, QuoteTransaction => $QuoteTransaction &>
%}
+% $m->callback( %ARGS, QueueObj => $QueueObj, CallbackName => 'AfterMessageBox' );
<br />
</td>
@@ -392,6 +394,22 @@ if ( !exists $ARGS{'AddMoreAttach'} && ($ARGS{'id'}||'') eq 'new' ) {
$checks_failure = 1 unless $status;
}
+# check email addresses for RT's
+{
+ foreach my $field ( qw(Requestors Cc AdminCc) ) {
+ my $value = $ARGS{ $field };
+ next unless defined $value && length $value;
+
+ my @emails = Email::Address->parse( $value );
+ foreach my $email ( grep RT::EmailParser->IsRTAddress($_->address), @emails ) {
+ push @results, loc("[_1] is an address RT receives mail at. Adding it as a '[_2]' would create a mail loop", $email->format, loc($field =~ /^(.*?)s?$/) );
+ $checks_failure = 1;
+ $email = undef;
+ }
+ $ARGS{ $field } = join ', ', map $_->format, grep defined, @emails;
+ }
+}
+
my $skip_create = 0;
$m->callback( CallbackName => 'BeforeCreate', ARGSRef => \%ARGS, skip_create => \$skip_create,
checks_failure => $checks_failure, results => \@results );
diff --git a/rt/share/html/Ticket/Display.html b/rt/share/html/Ticket/Display.html
index f8eaf3949..c1984bdca 100755
--- a/rt/share/html/Ticket/Display.html
+++ b/rt/share/html/Ticket/Display.html
@@ -46,12 +46,12 @@
%#
%# END BPS TAGGED BLOCK }}}
<& /Elements/Header,
- Title => loc("#[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject),
+ Title => loc("Ticket #[_1]: [_2]", $TicketObj->Id, $TicketObj->Subject),
LinkRel => \%link_rel &>
<& /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) &>
% $m->callback(CallbackName => 'BeforeActionList', %ARGS, Actions => \@Actions, ARGSRef => \%ARGS, Ticket => $TicketObj);
diff --git a/rt/share/html/Ticket/Elements/AddCustomers b/rt/share/html/Ticket/Elements/AddCustomers
new file mode 100644
index 000000000..e04c07702
--- /dev/null
+++ b/rt/share/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/share/html/Ticket/Elements/BulkLinks b/rt/share/html/Ticket/Elements/BulkLinks
index 7f87cefb8..d04eba426 100755
--- a/rt/share/html/Ticket/Elements/BulkLinks
+++ b/rt/share/html/Ticket/Elements/BulkLinks
@@ -163,7 +163,7 @@ $Tickets => undef
<%INIT>
my %hash;
if ( $Tickets && $Tickets->Count ) {
- my $first_ticket = $Tickets->Next;
+ my $first_ticket = $Tickets->Next or last; #avoid errors on bulk delete
# we only show current links that eixst on all the tickets
for my $type ( qw/DependsOn DependedOnBy Members MemberOf RefersTo
ReferredToBy/ ) {
diff --git a/rt/share/html/Ticket/Elements/CheckMandatoryFields b/rt/share/html/Ticket/Elements/CheckMandatoryFields
new file mode 100644
index 000000000..3d0324f98
--- /dev/null
+++ b/rt/share/html/Ticket/Elements/CheckMandatoryFields
@@ -0,0 +1,9 @@
+<%init>
+
+my $TicketObj = $ARGS{'Ticket'} or return ();
+my $ARGSRef = $ARGS{'ARGSRef'};
+my @fields = grep { $_->Required }
+ @{ $TicketObj->CustomFields->ItemsArrayRef };
+return grep { !defined($TicketObj->FirstCustomFieldValue($_->id)) } @fields;
+
+</%init>
diff --git a/rt/share/html/Ticket/Elements/EditCustomFields b/rt/share/html/Ticket/Elements/EditCustomFields
index c3a44ee22..5478c7871 100755
--- a/rt/share/html/Ticket/Elements/EditCustomFields
+++ b/rt/share/html/Ticket/Elements/EditCustomFields
@@ -45,6 +45,7 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+% $m->callback( %ARGS, CallbackName => 'BeforeCustomFields' );
<table>
% my $i = 0;
% while ( my $CustomField = $CustomFields->Next ) {
@@ -85,6 +86,7 @@
% }
</table>
+% $m->callback( %ARGS, CallbackName => 'AfterCustomFields', TicketObj => $TicketObj, QueueObj => $QueueObj );
<%INIT>
my $CustomFields;
diff --git a/rt/share/html/Ticket/Elements/EditCustomers b/rt/share/html/Ticket/Elements/EditCustomers
new file mode 100644
index 000000000..0ba6e447b
--- /dev/null
+++ b/rt/share/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/share/html/Ticket/Elements/EditDates b/rt/share/html/Ticket/Elements/EditDates
index fc17cdbd4..e6f724f7b 100755
--- a/rt/share/html/Ticket/Elements/EditDates
+++ b/rt/share/html/Ticket/Elements/EditDates
@@ -70,6 +70,7 @@
<& /Elements/SelectDate, menu_prefix => 'Due', current => 0 &> (<% $TicketObj->DueObj->AsString %>)
</td>
</tr>
+% $m->callback( %ARGS, CallbackName => 'EndOfList', Ticket => $TicketObj );
</table>
<%ARGS>
$TicketObj => undef
diff --git a/rt/share/html/Ticket/Elements/EditTransactionCustomFields b/rt/share/html/Ticket/Elements/EditTransactionCustomFields
index 8bf939db6..a58dded9b 100644
--- a/rt/share/html/Ticket/Elements/EditTransactionCustomFields
+++ b/rt/share/html/Ticket/Elements/EditTransactionCustomFields
@@ -45,6 +45,7 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+% $m->callback( CallbackName => 'BeforeTransactionCustomFields', TicketObj => $TicketObj, QueueObj => $QueueObj, NamePrefix => $NamePrefix );
% if ($CustomFields->Count) {
% while (my $CF = $CustomFields->Next()) {
% next unless $CF->CurrentUserHasRight('ModifyCustomField');
@@ -60,6 +61,7 @@
</td></tr>
% }
% }
+% $m->callback( CallbackName => 'AfterTransactionCustomFields', TicketObj => $TicketObj, QueueObj => $QueueObj, NamePrefix => $NamePrefix );
<%INIT>
my $CustomFields;
diff --git a/rt/share/html/Ticket/Elements/PreviewScrips b/rt/share/html/Ticket/Elements/PreviewScrips
index 7480adecf..d376f5d08 100755
--- a/rt/share/html/Ticket/Elements/PreviewScrips
+++ b/rt/share/html/Ticket/Elements/PreviewScrips
@@ -69,7 +69,11 @@ my @non_recipients = @{ $squelch{'EmailAddresses'} };
%my @addresses = $scrip->ActionObj->Action->$type();
<ul>
%foreach my $addr (@addresses) {
-<li> <b><%loc($type)%></b>: <input type="checkbox" class="checkbox" name="Ticket-<%$TicketObj->id%>-SquelchMailTo" value="<%$addr->address%>" /> <%$addr->address%>
+<li>
+ <b><%loc($type)%></b>: <input type="checkbox" class="checkbox" name="Ticket-<%$TicketObj->id%>-SquelchMailTo" value="<%$addr->address%>" /> <%$addr->address%>
+
+% $m->callback(CallbackName => 'AfterAddress', Ticket => $TicketObj, Address => $addr, Type => $type);
+</li>
% }
</ul>
% }
diff --git a/rt/share/html/Ticket/Elements/ShowAttachments b/rt/share/html/Ticket/Elements/ShowAttachments
index 72298d79f..ab0d92112 100755
--- a/rt/share/html/Ticket/Elements/ShowAttachments
+++ b/rt/share/html/Ticket/Elements/ShowAttachments
@@ -61,11 +61,22 @@
my $size = $rev->ContentLength;
if ($size) {
- if ($size > 1024) {
- $size = int($size/102.4)/10 . "k";
+ my $kb = int($size/102.4) / 10;
+ my $units = RT->Config->Get('AttachmentUnits');
+
+ if (!defined($units)) {
+ if ($size > 1024) {
+ $size = $kb . "k";
+ }
+ else {
+ $size = $size . "b";
+ }
+ }
+ elsif ($units eq 'k') {
+ $size = $kb . "k";
}
else {
- $size = $size ."b";
+ $size = $size . "b";
}
</%PERL>
diff --git a/rt/share/html/Ticket/Elements/ShowCustomers b/rt/share/html/Ticket/Elements/ShowCustomers
new file mode 100644
index 000000000..3acf92dd4
--- /dev/null
+++ b/rt/share/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/share/html/Ticket/Elements/ShowDates b/rt/share/html/Ticket/Elements/ShowDates
index d309907dc..07140c2e4 100755
--- a/rt/share/html/Ticket/Elements/ShowDates
+++ b/rt/share/html/Ticket/Elements/ShowDates
@@ -84,6 +84,7 @@
<td class="value date updated"><% $UpdatedString | h %></td>
% }
</tr>
+% $m->callback( %ARGS, CallbackName => 'EndOfList', TicketObj => $Ticket );
</table>
<%ARGS>
$Ticket => undef
diff --git a/rt/share/html/Ticket/Elements/ShowGroupMembers b/rt/share/html/Ticket/Elements/ShowGroupMembers
index a15f850b4..6597cc543 100644
--- a/rt/share/html/Ticket/Elements/ShowGroupMembers
+++ b/rt/share/html/Ticket/Elements/ShowGroupMembers
@@ -50,7 +50,9 @@
% my $Users = $Group->UserMembersObj( Recursively => $Recursively );
% while ( my $user = $Users->Next ) {
<& /Elements/ShowUser, User => $user, Ticket => $Ticket &>
-<& /Elements/ShowUserEmailFrequency, User => $user, Ticket => $Ticket &><br />
+<& /Elements/ShowUserEmailFrequency, User => $user, Ticket => $Ticket &>
+% $m->callback( User => $user, Ticket => $Ticket, %ARGS, CallbackName => 'AboutThisUser' );
+<br />
% }
% my $Groups = $Group->GroupMembersObj( Recursively => $Recursively );
% $Groups->LimitToUserDefinedGroups;
diff --git a/rt/share/html/Ticket/Elements/ShowMembers_Checklist b/rt/share/html/Ticket/Elements/ShowMembers_Checklist
new file mode 100644
index 000000000..68fb3b2c5
--- /dev/null
+++ b/rt/share/html/Ticket/Elements/ShowMembers_Checklist
@@ -0,0 +1,29 @@
+
+<style type="text/css">
+ul.checklist {
+ list-style-type: none
+}
+</style>
+
+<ul class="checklist">
+% while (my $link = $members->Next) {
+<li><& /Elements/ShowLink_Checklist, URI => $link->BaseURI &><br />
+% if ($depth < 8) { #why only 8?
+<& /Ticket/Elements/ShowMembers_Checklist, Ticket => $link->BaseObj, depth => ($depth+1) &>
+% }
+</li>
+% }
+</ul>
+
+<%INIT>
+
+return unless $Ticket;
+my $members = $Ticket->Members;
+return unless $members->Count;
+
+</%INIT>
+
+<%ARGS>
+$Ticket => undef
+$depth => 1
+</%ARGS>
diff --git a/rt/share/html/Ticket/Elements/ShowMessageStanza b/rt/share/html/Ticket/Elements/ShowMessageStanza
index 0d4fe6154..9d2f21120 100755
--- a/rt/share/html/Ticket/Elements/ShowMessageStanza
+++ b/rt/share/html/Ticket/Elements/ShowMessageStanza
@@ -48,7 +48,8 @@
<%perl>
if ( ref $Message ) {
$m->out('<pre>') if $plain_text_pre && !$Depth && !$plain_text_mono;
- $m->out( qq{<div class="message-stanza-depth-$Depth">} );
+ $m->out( qq{<div class="message-stanza-depth-$Depth } .($plain_text_mono ? "plain-text-white-space" : "") .qq{">} );
+
my @stack;
my $para = '';
diff --git a/rt/share/html/Ticket/Elements/ShowPeople b/rt/share/html/Ticket/Elements/ShowPeople
index ddd2e3c6f..1f0e5319e 100755
--- a/rt/share/html/Ticket/Elements/ShowPeople
+++ b/rt/share/html/Ticket/Elements/ShowPeople
@@ -50,7 +50,9 @@
<td class="label"><&|/l&>Owner</&>:</td>
% my $owner = $Ticket->OwnerObj;
<td class="value"><& /Elements/ShowUser, User => $owner, Ticket => $Ticket &>
- <& /Elements/ShowUserEmailFrequency, User => $owner, Ticket => $Ticket &></td>
+ <& /Elements/ShowUserEmailFrequency, User => $owner, Ticket => $Ticket &>
+% $m->callback( User => $owner, Ticket => $Ticket, %ARGS, CallbackName => 'AboutThisUser' );
+ </td>
</tr>
<tr>
<td class="labeltop"><&|/l&>Requestors</&>:</td>
diff --git a/rt/share/html/Ticket/Elements/ShowSummary b/rt/share/html/Ticket/Elements/ShowSummary
index 4c2d54e5e..295ac6d56 100755
--- a/rt/share/html/Ticket/Elements/ShowSummary
+++ b/rt/share/html/Ticket/Elements/ShowSummary
@@ -45,73 +45,89 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
- <table width="100%" class="ticket-summary">
- <tr>
- <td valign="top" class="boxcontainer">
- <&| /Widgets/TitleBox, title => loc('The Basics'),
- title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id,
- class => 'ticket-info-basics' &>
- <& /Ticket/Elements/ShowBasics, Ticket => $Ticket &>
- </&>
+<table width="100%" class="ticket-summary">
+<tr>
+ <td valign="top" class="boxcontainer">
+% $m->callback( %ARGS, CallbackName => 'LeftColumnTop' );
+
+ <&| /Widgets/TitleBox, title => loc('The Basics'),
+ title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id,
+ class => 'ticket-info-basics',
+ &>
+ <& /Ticket/Elements/ShowBasics, Ticket => $Ticket &>
+ </&>
% if ($Ticket->CustomFields->First) {
- <&| /Widgets/TitleBox, title => loc('Custom Fields'),
- title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id,
- class => 'ticket-info-cfs' &>
- <& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket &>
- </&>
+ <&| /Widgets/TitleBox, title => loc('Custom Fields'),
+ title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id,
+ class => 'ticket-info-cfs',
+ &>
+ <& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket &>
+ </&>
% }
- <&| /Widgets/TitleBox, title => loc('People'),
- title_href => RT->Config->Get('WebPath')."/Ticket/ModifyPeople.html?id=".$Ticket->Id,
- class => 'ticket-info-people' &>
- <& /Ticket/Elements/ShowPeople, Ticket => $Ticket &>
- </&>
- <& /Ticket/Elements/ShowAttachments, Ticket => $Ticket, Attachments => $Attachments &>
+ <&| /Widgets/TitleBox, title => loc('Customers'),
+ title_href => RT->Config->Get('WebPath')."/Ticket/ModifyCustomers.html?id=".$Ticket->Id,
+ class => 'ticket-info-customers'
+ &>
+ <& /Ticket/Elements/ShowCustomers, Ticket => $Ticket &>
+ </&>
+
+ <&| /Widgets/TitleBox, title => loc('People'),
+ title_href => RT->Config->Get('WebPath')."/Ticket/ModifyPeople.html?id=".$Ticket->Id,
+ class => 'ticket-info-people',
+ &>
+ <& /Ticket/Elements/ShowPeople, Ticket => $Ticket &>
+ </&>
- <& /Ticket/Elements/ShowRequestor, Ticket => $Ticket &>
+ <& /Ticket/Elements/ShowAttachments, Ticket => $Ticket, Attachments => $Attachments &>
+
+ <& /Ticket/Elements/ShowRequestor, Ticket => $Ticket &>
% $m->callback( %ARGS, CallbackName => 'LeftColumn' );
- </td>
- <td valign="top" class="boxcontainer">
+
+ </td>
+ <td valign="top" class="boxcontainer">
+
+% $m->callback( %ARGS, CallbackName => 'RightColumnTop' );
+
% if ( RT->Config->Get('EnableReminders') ) {
- <&|/Widgets/TitleBox, title => loc("Reminders"),
- title_href => RT->Config->Get('WebPath')."/Ticket/Reminders.html?id=".$Ticket->Id,
- class => 'ticket-info-reminders' &>
- <table>
- <tr>
- <td>
+ <&|/Widgets/TitleBox, title => loc("Reminders"),
+ title_href => RT->Config->Get('WebPath')."/Ticket/Reminders.html?id=".$Ticket->Id,
+ class => 'ticket-info-reminders',
+ &>
+ <table><tr><td>
<form action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" method="post">
- <& /Ticket/Elements/Reminders, Ticket => $Ticket, ShowCompleted => 0 &>
- <div align="right"><input type="submit" class="button" value="<&|/l&>Save</&>" /></div>
+ <& /Ticket/Elements/Reminders, Ticket => $Ticket, ShowCompleted => 0 &>
+ <div align="right"><input type="submit" class="button" value="<&|/l&>Save</&>" /></div>
</form>
- </td>
- </tr>
- </table>
- </&>
+ </td></tr></table>
+ </&>
% }
- <&| /Widgets/TitleBox, title => loc("Dates"),
- title_href => RT->Config->Get('WebPath')."/Ticket/ModifyDates.html?id=".$Ticket->Id,
- class => 'ticket-info-dates' &>
- <& /Ticket/Elements/ShowDates, Ticket => $Ticket &>
- </&>
+
+ <&| /Widgets/TitleBox, title => loc("Dates"),
+ title_href => RT->Config->Get('WebPath')."/Ticket/ModifyDates.html?id=".$Ticket->Id,
+ class => 'ticket-info-dates',
+ &>
+ <& /Ticket/Elements/ShowDates, Ticket => $Ticket &>
+ </&>
+
% my (@extra);
% push @extra, titleright_raw => '<a href="'. RT->Config->Get('WebPath'). '/Ticket/Graphs/index.html?id='.$Ticket->id.'">'.loc('Graph').'</a>' unless RT->Config->Get('DisableGraphViz');
- <&| /Widgets/TitleBox, title => loc('Links'),
- title_href => RT->Config->Get('WebPath')."/Ticket/ModifyLinks.html?id=".$Ticket->Id,
- class => 'ticket-info-links', @extra &>
- <& /Elements/ShowLinks, Ticket => $Ticket &>
- </&>
+ <&| /Widgets/TitleBox, title => loc('Links'),
+ title_href => RT->Config->Get('WebPath')."/Ticket/ModifyLinks.html?id=".$Ticket->Id,
+ class => 'ticket-info-links',
+ @extra,
+ &>
+ <& /Elements/ShowLinks, Ticket => $Ticket &>
+ </&>
+
% $m->callback( %ARGS, CallbackName => 'RightColumn' );
- </td>
- </tr>
- </table>
+ </td>
+</tr>
+</table>
<%ARGS>
$Ticket => undef
$Attachments => undef
</%ARGS>
-
-
-
-
diff --git a/rt/share/html/Ticket/Elements/ShowTransaction b/rt/share/html/Ticket/Elements/ShowTransaction
index a533323a9..6ccbb0c89 100755
--- a/rt/share/html/Ticket/Elements/ShowTransaction
+++ b/rt/share/html/Ticket/Elements/ShowTransaction
@@ -55,11 +55,13 @@
<a name="txn-<% $Transaction->Id %>" href="<% $DisplayPath %>#txn-<% $Transaction->Id %>">#</a>
<% $LastTransaction ? '<a id="lasttrans" name="lasttrans"></a>' : ''|n %>
</span>
+% $m->callback( Transaction => $Transaction, %ARGS, CallbackName => 'AfterAnchor' );
<span class="date"><% $transdate|n %></span>
% my $desc = $Transaction->BriefDescription;
% $m->callback( text => \$desc, Transaction => $Transaction, %ARGS, CallbackName => 'ModifyDisplay' );
<span class="description">
<& /Elements/ShowUser, User => $Transaction->CreatorObj &> - <% $TicketString %> <% $desc %>
+% $m->callback( Transaction => $Transaction, %ARGS, CallbackName => 'AfterDescription' );
</span>
% $m->callback( TimeTaken => \$TimeTaken, Transaction => $Transaction, %ARGS, CallbackName => 'ModifyTimeTaken' );
<span class="time-taken"><% $TimeTaken %></span>
diff --git a/rt/share/html/Ticket/Elements/ShowTransactionAttachments b/rt/share/html/Ticket/Elements/ShowTransactionAttachments
index 9c40b28da..95ffcbd64 100644
--- a/rt/share/html/Ticket/Elements/ShowTransactionAttachments
+++ b/rt/share/html/Ticket/Elements/ShowTransactionAttachments
@@ -67,7 +67,10 @@ foreach my $message ( grep $_->__Value('Parent') == $Parent, @$Attachments ) {
% if ( $DownloadableHeaders && !$message->Filename && $message->ContentType =~ /text/ ) {
/ <a href="<% $AttachPath %>/WithHeaders/<% $message->Id %>"><% loc('with headers') %></a>
% }
-<br />
+
+% $m->callback(CallbackName => 'AfterDownloadLinks', ARGSRef => \%ARGS, Ticket => $Ticket, Transaction => $Transaction, Attachment => $message);
+
+<br />
<span class="downloadcontenttype"><% $message->ContentType %> <% $size_to_str->( $size ) %></span>
</div>
% }
@@ -76,7 +79,7 @@ foreach my $message ( grep $_->__Value('Parent') == $Parent, @$Attachments ) {
% if ( scalar ( grep $_->__Value('Parent') == $message->id, @$Attachments ) ) {
<div class="messageattachments">
% } else {
-<div class="messagebody <% RT->Config->Get('PlainTextMono', $session{'CurrentUser'}) ? ' plain-text-white-space' : ''%>">
+<div class="messagebody">
% }
<%PERL>
@@ -207,8 +210,14 @@ my $render_attachment = sub {
# if it's a text/plain show the body
elsif ( $message->ContentType =~ m{^(text|message)}i ) {
- eval { require Text::Quoted; $content = Text::Quoted::extract($content); };
- if ($@) { $RT::Logger->warning( "Text::Quoted failed: $@" ) }
+ #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 ($@) { $RT::Logger->warning( "Text::Quoted failed: $@" ) }
$m->comp(
'ShowMessageStanza',
diff --git a/rt/share/html/Ticket/Elements/Tabs b/rt/share/html/Ticket/Elements/Tabs
index 7deb8c18d..6943a2703 100755
--- a/rt/share/html/Ticket/Elements/Tabs
+++ b/rt/share/html/Ticket/Elements/Tabs
@@ -75,11 +75,13 @@ if ($Ticket) {
# Don't display prev links if we're on the first ticket
if ( $item_map->{ $Ticket->Id }->{prev} ) {
- $searchtabs->{'_a'} = {
- class => "nav",
- path => "Ticket/Display.html?id=" . $item_map->{first},
- title => '<< ' . loc('First')
- };
+ if ( $item_map->{first} ) {
+ $searchtabs->{'_a'} = {
+ class => "nav",
+ path => "Ticket/Display.html?id=" . $item_map->{first},
+ title => '<< ' . loc('First')
+ };
+ }
$searchtabs->{"_b"} = {
class => "nav",
path => "Ticket/Display.html?id="
@@ -96,11 +98,13 @@ if ($Ticket) {
. $item_map->{ $Ticket->Id }->{next},
title => loc('Next') . ' >'
};
- $searchtabs->{'e'} = {
- class => "nav",
- path => "Ticket/Display.html?id=" . $item_map->{last},
- title => loc('Last') . ' >>'
- };
+ if ( $item_map->{last} ) {
+ $searchtabs->{'e'} = {
+ class => "nav",
+ path => "Ticket/Display.html?id=" . $item_map->{last},
+ title => loc('Last') . ' >>'
+ };
+ }
}
}
@@ -138,6 +142,14 @@ if ($Ticket) {
title => loc('Links'),
path => "Ticket/ModifyLinks.html?id=" . $id,
},
+ _Ea => {
+ title => loc('Checklist'),
+ path => "Ticket/Checklist.html?id=" . $id,
+ },
+ _Eb=> {
+ title => loc('Customers'),
+ path => "Ticket/ModifyCustomers.html?id=" . $id,
+ },
_X => {
title => loc('Jumbo'),
path => "Ticket/ModifyAll.html?id=" . $id,
diff --git a/rt/share/html/Ticket/Elements/UpdateCc b/rt/share/html/Ticket/Elements/UpdateCc
index 2538c82df..2559e5652 100644
--- a/rt/share/html/Ticket/Elements/UpdateCc
+++ b/rt/share/html/Ticket/Elements/UpdateCc
@@ -49,24 +49,32 @@
<input type="hidden" id="UpdateIgnoreAddressCheckboxes" name="UpdateIgnoreAddressCheckboxes" value="0">
<br />
-%foreach my $addr ( keys %txn_addresses) {
-% next if ( grep {$addr eq $_} @req_addresses );
+%if (scalar @one_time_Ccs) {
+<i class="label">(<&|/l&>check to add</&>)</i>
+%}
+%foreach my $addr ( @one_time_Ccs ) {
<input
id="UpdateCc-<%$addr%>"
name="UpdateCc-<%$addr%>"
type="checkbox"
- onClick="checkboxToInput('UpdateCc', 'UpdateCc-<%$addr%>','<%$txn_addresses{$addr}->format%>' ); $(UpdateIgnoreAddressCheckboxes).value=1"
+% my $clean_addr = $txn_addresses{$addr}->format;
+% $clean_addr =~ s/'/\\'/g;
+ onClick="checkboxToInput('UpdateCc', 'UpdateCc-<%$addr%>','<%$clean_addr%>' ); $(UpdateIgnoreAddressCheckboxes).value=1"
<% $ARGS{'UpdateCc-'.$addr} ? 'checked="checked"' : ''%> > <& /Elements/ShowUser, Address => $txn_addresses{$addr}&>
%}
</td></tr>
<tr><td class="label"><&|/l&>One-time Bcc</&>:</td><td><& /Elements/EmailInput, Name => 'UpdateBcc', Size => '60', Default => $ARGS{UpdateBcc} &><br />
-%foreach my $addr ( keys %txn_addresses) {
-% next if ( grep {$addr eq $_} @req_addresses );
+%if (scalar @one_time_Ccs) {
+<i class="label">(<&|/l&>check to add</&>)</i>
+%}
+%foreach my $addr ( @one_time_Ccs ) {
<input
id="UpdateBcc-<%$addr%>"
name="UpdateBcc-<%$addr%>"
type="checkbox"
- onClick="checkboxToInput('UpdateBcc', 'UpdateBcc-<%$addr%>','<%$txn_addresses{$addr}->format%>' ); $(UpdateIgnoreAddressCheckboxes).value=1"
+% my $clean_addr = $txn_addresses{$addr}->format;
+% $clean_addr =~ s/'/\\'/g;
+ onClick="checkboxToInput('UpdateBcc', 'UpdateBcc-<%$addr%>','<%$clean_addr%>' ); $(UpdateIgnoreAddressCheckboxes).value=1"
<% $ARGS{'UpdateBcc-'.$addr} ? 'checked="checked"' : ''%>>
<& /Elements/ShowUser, Address => $txn_addresses{$addr}&>
%}
@@ -77,4 +85,10 @@ $TicketObj
<%init>
my %txn_addresses = %{$TicketObj->TransactionAddresses};
my @req_addresses = split /,/, $TicketObj->RequestorAddresses;
+my @one_time_Ccs;
+
+foreach my $addr ( keys %txn_addresses) {
+ next if ( grep {$addr eq $_} @req_addresses );
+ push @one_time_Ccs,$addr;
+}
</%init>
diff --git a/rt/share/html/Ticket/ModifyAll.html b/rt/share/html/Ticket/ModifyAll.html
index 762870099..41eda1b97 100755
--- a/rt/share/html/Ticket/ModifyAll.html
+++ b/rt/share/html/Ticket/ModifyAll.html
@@ -97,6 +97,7 @@
<option value="response"><&|/l&>Reply to requestors</&></option>
% }
</select>
+% $m->callback( %ARGS, CallbackName => 'AfterUpdateType' );
</td>
</tr>
<tr>
@@ -133,8 +134,13 @@
</tr>
<tr>
<td class="labeltop"><&|/l&>Content</&>:</td>
- <td class="entry"><& /Elements/MessageBox, Name=>"UpdateContent", QuoteTransaction=>$ARGS{QuoteTransaction} &></td>
- </tr>
+ <td class="entry">
+% if (exists $ARGS{UpdateContent}) {
+ <& /Elements/MessageBox, Name=>"UpdateContent", Default=>$ARGS{UpdateContent}, IncludeSignature => 0 &>
+% } else {
+ <& /Elements/MessageBox, Name=>"UpdateContent", QuoteTransaction=>$ARGS{QuoteTransaction} &>
+% }
+ </td></tr>
</table>
</&>
diff --git a/rt/share/html/Ticket/ModifyCustomers.html b/rt/share/html/Ticket/ModifyCustomers.html
new file mode 100644
index 000000000..72d103b23
--- /dev/null
+++ b/rt/share/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/share/html/Ticket/ModifyDates.html b/rt/share/html/Ticket/ModifyDates.html
index 69bfde8ef..22bac10cb 100755
--- a/rt/share/html/Ticket/ModifyDates.html
+++ b/rt/share/html/Ticket/ModifyDates.html
@@ -69,6 +69,7 @@
my $TicketObj = LoadTicket($id);
$m->callback( TicketObj => $TicketObj, ARGSRef => \%ARGS );
my @results = ProcessTicketDates( TicketObj => $TicketObj, ARGSRef => \%ARGS);
+push @results, ProcessObjectCustomFieldUpdates(Object => $TicketObj, ARGSRef => \%ARGS);
$TicketObj->ApplyTransactionBatch;
</%INIT>
diff --git a/rt/share/html/Ticket/Update.html b/rt/share/html/Ticket/Update.html
index d3c2a09c4..f5cdddea8 100755
--- a/rt/share/html/Ticket/Update.html
+++ b/rt/share/html/Ticket/Update.html
@@ -55,7 +55,7 @@
<form action="Update.html" name="TicketUpdate"
method="post" enctype="multipart/form-data">
-% $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS, Ticket => $TicketObj );
+% $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS, Ticket => $TicketObj, CanRespond => $CanRespond, CanComment => $CanComment, ResponseDefault => $ResponseDefault, CommentDefault => $CommentDefault );
<input type="hidden" class="hidden" name="QuoteTransaction" value="<% $ARGS{QuoteTransaction}||'' %>" />
<input type="hidden" class="hidden" name="DefaultStatus" value="<% $DefaultStatus ||''%>" />
<input type="hidden" class="hidden" name="Action" value="<% $ARGS{Action}||'' %>" />
@@ -97,8 +97,11 @@
<option value="response" <% ($ARGS{'UpdateType'} && $ARGS{'UpdateType'} eq "response") ? qq[ selected="selected"] : !$ARGS{'UpdateType'}&&$ResponseDefault |n %>><&|/l&>Reply to requestors</&></option>
% }
</select>
+% $m->callback( %ARGS, CallbackName => 'AfterUpdateType' );
+</td></tr>
+<tr><td class="label"><&|/l&>Subject</&>:</td><td> <input name="UpdateSubject" size="60" value="<% $ARGS{UpdateSubject} || $TicketObj->Subject()%>" />
+% $m->callback( %ARGS, CallbackName => 'AfterSubject' );
</td></tr>
-<tr><td class="label"><&|/l&>Subject</&>:</td><td> <input name="UpdateSubject" size="60" value="<% $ARGS{UpdateSubject} || $TicketObj->Subject()%>" /></td></tr>
<& /Ticket/Elements/UpdateCc, %ARGS, TicketObj => $TicketObj &>
@@ -126,6 +129,7 @@
&>
</td></tr>
% }
+% $m->callback( %ARGS, CallbackName => 'AfterGnuPG' );
<tr><td class="label" valign="top"><&|/l&>Message</&>:</td><td>
% $m->callback( %ARGS, CallbackName => 'BeforeMessageBox' );
@@ -136,7 +140,9 @@
<& /Elements/MessageBox, Name=>"UpdateContent", Default=>$ARGS{UpdateContent}, IncludeSignature => 0, %ARGS&>
% $ARGS{'QuoteTransaction'} = $temp;
% } else {
-<& /Elements/MessageBox, Name=>"UpdateContent", %ARGS &>
+% my $IncludeSignature = 1;
+% $IncludeSignature = 0 if $Action ne 'Respond' && !RT->Config->Get('MessageBoxIncludeSignatureOnComment');
+<& /Elements/MessageBox, Name=>"UpdateContent", IncludeSignature => $IncludeSignature, %ARGS &>
% }
</td></tr>
</table>
@@ -256,6 +262,22 @@ if ( $ARGS{'SubmitTicket'} ) {
$checks_failure = 1 unless $status;
}
+# check email addresses for RT's
+{
+ foreach my $field ( qw(UpdateCc UpdateBcc) ) {
+ my $value = $ARGS{ $field };
+ next unless defined $value && length $value;
+
+ my @emails = Email::Address->parse( $value );
+ foreach my $email ( grep RT::EmailParser->IsRTAddress($_->address), @emails ) {
+ push @results, loc("[_1] is an address RT receives mail at. Adding it as a '[_2]' would create a mail loop", $email->format, loc(substr($field, 6)) );
+ $checks_failure = 1;
+ $email = undef;
+ }
+ $ARGS{ $field } = join ', ', map $_->format, grep defined, @emails;
+ }
+}
+
if ( !$checks_failure && exists $ARGS{SubmitTicket} ) {
$m->callback( Ticket => $TicketObj, ARGSRef => \%ARGS, CallbackName => 'BeforeDisplay' );
return $m->comp('Display.html', TicketObj => $TicketObj, %ARGS);
diff --git a/rt/share/html/Tools/Reports/CreatedByDates.html b/rt/share/html/Tools/Reports/CreatedByDates.html
index 9ca69557e..ce075970b 100644
--- a/rt/share/html/Tools/Reports/CreatedByDates.html
+++ b/rt/share/html/Tools/Reports/CreatedByDates.html
@@ -76,8 +76,8 @@ $q->LoadByCols(Name => $Queue);
% if ($Queue|| $CreatedBefore ||$CreatedAfter) {
% # if we have a queue, do the search
% if ($Queue) { $query .= " AND Queue = '$Queue'"}
-% if ($CreatedBefore) { $query .= " AND Created < '".$before->ISO."'"; }
-% if ($CreatedAfter) { $query .= " AND Created > '".$after->ISO."'"}
+% if ($CreatedBefore) { $query .= " AND Created < '".$before->ISO(Timezone => 'user') ."'"; }
+% if ($CreatedAfter) { $query .= " AND Created > '".$after->ISO(Timezone => 'user')."'"}
% my $groupby = 'Status';
<& /Search/Elements/Chart, Query => $query, PrimaryGroupBy => $groupby &>
% }
@@ -86,9 +86,9 @@ $q->LoadByCols(Name => $Queue);
<br /><&|/l&>Queue</&>: <& /Elements/SelectQueue, Name => 'Queue', NamedValues => 1, Default => $q->id &>
<br /><&|/l&>Tickets created after</&>:
-<& /Elements/SelectDate, Name => 'CreatedAfter', Default => ($CreatedAfter) ? $after->ISO : ''&>
+<& /Elements/SelectDate, Name => 'CreatedAfter', Default => ($CreatedAfter) ? $after->ISO(Timezone => 'user') : ''&>
<br /><&|/l&>Tickets created before</&>:
-<& /Elements/SelectDate, Name => 'CreatedBefore', Default => ($CreatedBefore) ? $before->ISO : ''&>
+<& /Elements/SelectDate, Name => 'CreatedBefore', Default => ($CreatedBefore) ? $before->ISO(Timezone => 'user') : ''&>
<& /Elements/Submit&>
</form>
diff --git a/rt/share/html/Tools/Reports/ResolvedByDates.html b/rt/share/html/Tools/Reports/ResolvedByDates.html
index 455eaedd2..48a952682 100644
--- a/rt/share/html/Tools/Reports/ResolvedByDates.html
+++ b/rt/share/html/Tools/Reports/ResolvedByDates.html
@@ -77,8 +77,8 @@ $q->LoadByCols(Name => $Queue);
% # if we have a queue, do the search
% $query = "Status = 'resolved'";
% if ($Queue) { $query .= " AND Queue = '$Queue'"}
-% if ($ResolvedBefore) { $query .= " AND Resolved < '".$before->ISO."'"; }
-% if ($ResolvedAfter) { $query .= " AND Resolved > '".$after->ISO."'"}
+% if ($ResolvedBefore) { $query .= " AND Resolved < '".$before->ISO(Timezone => 'user')."'"; }
+% if ($ResolvedAfter) { $query .= " AND Resolved > '".$after->ISO(Timezone => 'user')."'"}
% my $groupby = 'Owner';
<& /Search/Elements/Chart, Query => $query, PrimaryGroupBy => $groupby &>
% }
@@ -87,9 +87,9 @@ $q->LoadByCols(Name => $Queue);
<br /><&|/l&>Queue</&>: <& /Elements/SelectQueue, Name => 'Queue', NamedValues => 1, Default => $q->id &>
<br /><&|/l&>Tickets resolved after</&>:
-<& /Elements/SelectDate, Name => 'ResolvedAfter', Default => ($ResolvedAfter) ? $after->ISO : ''&>
+<& /Elements/SelectDate, Name => 'ResolvedAfter', Default => ($ResolvedAfter) ? $after->ISO(Timezone => 'user') : ''&>
<br /><&|/l&>Tickets resolved before</&>:
-<& /Elements/SelectDate, Name => 'ResolvedBefore', Default => ($ResolvedBefore) ? $before->ISO : ''&>
+<& /Elements/SelectDate, Name => 'ResolvedBefore', Default => ($ResolvedBefore) ? $before->ISO(Timezone => 'user') : ''&>
<& /Elements/Submit&>
</form>
diff --git a/rt/share/html/User/Elements/Tabs b/rt/share/html/User/Elements/Tabs
index 48cf1808b..7f9aca4dd 100755
--- a/rt/share/html/User/Elements/Tabs
+++ b/rt/share/html/User/Elements/Tabs
@@ -52,41 +52,43 @@
Title => $Title &>
<%INIT>
- my $tabs = {
-
- a => { title => loc('Settings'),
- path => 'Prefs/Other.html',
- },
-
- b => { title => loc('About me'),
- path => 'User/Prefs.html',
- },
- g => { title => loc('Personal Groups'),
- path => 'User/Groups/',
- },
- h => { title => loc('Delegation'),
- path => 'User/Delegation.html',
- },
- f => { title => loc('Search options'),
- path => 'Prefs/SearchOptions.html',
- },
- r => { title => loc('RT at a glance'),
- path => 'Prefs/MyRT.html',
- },
- };
+my $tabs = {
+ a => {
+ title => loc('Settings'),
+ path => 'Prefs/Other.html',
+ },
+ b => {
+ title => loc('About me'),
+ path => 'User/Prefs.html',
+ },
+ g => {
+ title => loc('Personal Groups'),
+ path => 'User/Groups/',
+ },
+ h => {
+ title => loc('Delegation'),
+ path => 'User/Delegation.html',
+ },
+ f => {
+ title => loc('Search options'),
+ path => 'Prefs/SearchOptions.html',
+ },
+ r => {
+ title => loc('RT at a glance'),
+ path => 'Prefs/MyRT.html',
+ },
+};
- # Now let callbacks add their extra tabs
- $m->callback( %ARGS, tabs => $tabs );
-
- foreach my $tab (sort keys %{$tabs}) {
- if ($tabs->{$tab}->{'path'} eq $current_tab) {
- $tabs->{$tab}->{"subtabs"} = $subtabs;
- $tabs->{$tab}->{"current_subtab"} = $current_subtab;
- }
- }
-</%INIT>
+# Now let callbacks add their extra tabs
+$m->callback( %ARGS, tabs => $tabs );
+foreach my $tab (values %$tabs) {
+ next unless $tab->{'path'} eq $current_tab;
+ $tab->{"subtabs"} = $subtabs;
+ $tab->{"current_subtab"} = $current_subtab;
+}
+</%INIT>
<%ARGS>
$subtabs => undef
$current_tab => undef
diff --git a/rt/share/html/User/Prefs.html b/rt/share/html/User/Prefs.html
index f52fdcbdf..e3a00f6ef 100755
--- a/rt/share/html/User/Prefs.html
+++ b/rt/share/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") &>
@@ -107,27 +107,13 @@
% $m->callback( %ARGS, UserObj => $UserObj, CallbackName => 'FormLeftColumn' );
</td>
<td valign="top" class="boxcontainer">
-% unless (RT->Config->Get('WebExternalAuth') and !RT->Config->Get('WebFallbackToInternalAuth')) {
+
<&| /Widgets/TitleBox, title => loc('Password'), id => "user-prefs-password" &>
-<table>
-<tr>
-<td class="label">
-<&|/l&>New Password</&>:
-</td>
-<td class="value">
-<input type="password" name="Pass1" autocomplete="off"/>
-</td>
-</tr>
-<tr><td class="label">
-<&|/l&>Retype Password</&>:
-</td>
-<td class="value">
-<input type="password" name="Pass2" autocomplete="off" />
-</td>
-</tr>
-</table>
+<& /Elements/EditPassword,
+ User => $UserObj,
+ Name => [qw(CurrentPass Pass1 Pass2)],
+&>
</&>
-% }
<&| /Widgets/TitleBox, title => loc('Location'), id => "user-prefs-location" &>
<table cellspacing="0" cellpadding="0">
@@ -221,6 +207,7 @@ unless ( $UserObj->id ) {
if $Name;
Abort(loc("Couldn't load user"));
}
+$id = $UserObj->id;
my @results;
@@ -259,13 +246,14 @@ if ( $SetPrivileged and $Privileged != $UserObj->Privileged ) {
push @results, loc('Privileged status: [_1]', loc_fuzzy($msg));
}
-#TODO: make this report errors properly
-if ( defined $Pass1 and length $Pass1 and $Pass1 eq $Pass2 and !$UserObj->IsPassword($Pass1) ) {
- my ($code, $msg);
- ($code, $msg) = $UserObj->SetPassword($Pass1);
- push @results, loc('Password: [_1]', loc_fuzzy($msg));
-} elsif ( defined $Pass1 && length $Pass1 && $Pass1 ne $Pass2 ) {
- push @results, loc("Passwords do not match. Your password has not been changed");
+my %password_cond = $UserObj->CurrentUserRequireToSetPassword;
+if (defined $Pass1 && length $Pass1 ) {
+ my ($status, $msg) = $UserObj->SafeSetPassword(
+ Current => $CurrentPass,
+ New => $Pass1,
+ Confirmation => $Pass2,
+ );
+ push @results, loc("Password: [_1]", $msg);
}
if ( $ARGS{'ResetAuthToken'} ) {
@@ -308,7 +296,8 @@ $City => undef
$State => undef
$Zip => undef
$Country => undef
+$CurrentPass => undef
$Pass1 => undef
-$Pass2=> undef
+$Pass2 => undef
$Create=> undef
</%ARGS>
diff --git a/rt/share/html/Widgets/Form/Select b/rt/share/html/Widgets/Form/Select
index e77861740..4587f1d58 100644
--- a/rt/share/html/Widgets/Form/Select
+++ b/rt/share/html/Widgets/Form/Select
@@ -117,7 +117,10 @@ if ( $ValuesCallback ) {
}
}
unless (defined $DefaultLabel ) {
- $DefaultLabel = loc('Use system default ([_1])', join ', ', map{ loc($ValuesLabel{$_} || $_) } @DefaultValue);
+ $DefaultLabel = loc('Use system default ([_1])',
+ join ', ', map loc($ValuesLabel{$_} || $_), grep defined,
+ @DefaultValue
+ );
}
</%INIT>
</%METHOD>
diff --git a/rt/share/html/Widgets/TitleBoxEnd b/rt/share/html/Widgets/TitleBoxEnd
index 402124e28..4a698e9f7 100755
--- a/rt/share/html/Widgets/TitleBoxEnd
+++ b/rt/share/html/Widgets/TitleBoxEnd
@@ -50,7 +50,7 @@
</div>
% #Manually flush the content buffer after each titlebox is displayed
-% $m->flush_buffer();
+% #wtf? this causes us to lose content #$m->flush_buffer();
<%ARGS>
$title => undef
diff --git a/rt/share/html/autohandler b/rt/share/html/autohandler
index 1bb2c939f..b44bd68d5 100755
--- a/rt/share/html/autohandler
+++ b/rt/share/html/autohandler
@@ -52,7 +52,9 @@ $m->callback( ARGSRef => \%ARGS, CallbackName => 'Init', CallbackPage => '/autoh
RT::Interface::Web::HandleRequest(\%ARGS);
-$m->comp( '/Elements/Footer', %ARGS );
+$m->comp( '/Elements/Footer', %ARGS )
+ unless $r->content_type =~ qr<^(text|application)/(x-)?(css|javascript)>;
+
</%INIT>
<%ARGS>
$user => undef