diff options
Diffstat (limited to 'rt/share/html')
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"> </td><td> +<input type="checkbox" class="checkbox" name="Required" value="1" <% $RequiredChecked |n%> /> +<&|/l&>Required for ticket resolution</&> +</td></tr> + +<tr><td class="label"> </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" /> [_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" /> [_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, '»|«', $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 => \' ', + 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 Binary files differnew file mode 100644 index 000000000..9c126c7e3 --- /dev/null +++ b/rt/share/html/NoAuth/css/freeside2.1/images/source/background-gradient.png 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 Binary files differnew file mode 100644 index 000000000..4d5eeb9ea --- /dev/null +++ b/rt/share/html/NoAuth/images/created.png diff --git a/rt/share/html/NoAuth/images/created_due.png b/rt/share/html/NoAuth/images/created_due.png Binary files differnew file mode 100644 index 000000000..52dfc96f0 --- /dev/null +++ b/rt/share/html/NoAuth/images/created_due.png diff --git a/rt/share/html/NoAuth/images/due.png b/rt/share/html/NoAuth/images/due.png Binary files differnew file mode 100644 index 000000000..30a3aff8a --- /dev/null +++ b/rt/share/html/NoAuth/images/due.png diff --git a/rt/share/html/NoAuth/images/reminder.png b/rt/share/html/NoAuth/images/reminder.png Binary files differnew file mode 100644 index 000000000..4370b6902 --- /dev/null +++ b/rt/share/html/NoAuth/images/reminder.png diff --git a/rt/share/html/NoAuth/images/resolved.png b/rt/share/html/NoAuth/images/resolved.png Binary files differnew file mode 100644 index 000000000..09db36d5a --- /dev/null +++ b/rt/share/html/NoAuth/images/resolved.png diff --git a/rt/share/html/NoAuth/images/started.png b/rt/share/html/NoAuth/images/started.png Binary files differnew file mode 100644 index 000000000..e177addea --- /dev/null +++ b/rt/share/html/NoAuth/images/started.png diff --git a/rt/share/html/NoAuth/images/starts.png b/rt/share/html/NoAuth/images/starts.png Binary files differnew file mode 100644 index 000000000..88064ba50 --- /dev/null +++ b/rt/share/html/NoAuth/images/starts.png diff --git a/rt/share/html/NoAuth/images/starts_due.png b/rt/share/html/NoAuth/images/starts_due.png Binary files differnew file mode 100644 index 000000000..16a4de46f --- /dev/null +++ b/rt/share/html/NoAuth/images/starts_due.png diff --git a/rt/share/html/NoAuth/images/updated.png b/rt/share/html/NoAuth/images/updated.png Binary files differnew file mode 100644 index 000000000..680e79a54 --- /dev/null +++ b/rt/share/html/NoAuth/images/updated.png 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> + '<small>__Due__</small>', + '<small>__Starts__</small>', + '<small>__LastUpdated__</small>' +</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 |