summaryrefslogtreecommitdiff
path: root/rt/share/html
diff options
context:
space:
mode:
Diffstat (limited to 'rt/share/html')
-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
162 files changed, 5681 insertions, 923 deletions
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