[Rt-commit] rt branch, 4.6/priority-as-string, created. rt-4.4.4-567-gb420bf72eb
Michel Rodriguez
michel at bestpractical.com
Tue Dec 31 11:52:35 EST 2019
The branch, 4.6/priority-as-string has been created
at b420bf72ebbc4ed778f207bcf7f39f2749975c68 (commit)
- Log -----------------------------------------------------------------
commit e698a7d3021e086620defbe4ac04d5b5c3e20463
Author: michel <michel at bestpractical.com>
Date: Wed Dec 18 16:02:28 2019 +0100
Cores PriorityAsString
Add PriorityAsString to core.
Priority is kept as a number in the DB, but is displayed
as a string, based on the mapping defined in the config.
Everywhere a priority needs to be displayed or input, the
Ticket object can return the string, based on the queue.
Example configuration:
Set($EnablePriorityAsString, 1);
Set(%PriorityAsString,
# default (for non specified queues)
Default => { Low => 0, Medium => 50, High => 100 },
# per queue priorities
General => { Low => 0, High => 1 },
# drop-downs will display in order Low/High/Medium
LHM => [ Low => 0, High => 100, Medium => 50 ],
# use numerical priorities
NumQueue => 0,
);
diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index b76df54f9b..a38d4265f7 100644
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -1877,6 +1877,91 @@ Set this to 1 to hide unset fields.
Set($HideUnsetFieldsOnDisplay, 0);
+=item C<%EnablePriorityAsString>
+
+Set this to C<0> to disable string priorities and only use
+numerical ones
+
+=cut
+
+Set($EnablePriorityAsString, 1);
+
+=item C<%PriorityAsString>
+
+RT can assign a priority value to tickets. Priority is stored as an
+integer in the database, but RT supports mapping strings to numerical
+values.
+
+RT supports different priority string mappings for individual queues
+with C<%PriorityAsString>.
+
+For example, the default mapping is:
+
+ Set(%PriorityAsString,
+ Default => { Low => 0, Medium => 50, High => 100 },
+ )
+
+Use queue names as keys in this hash.
+
+Values in the hash define the mapping:
+
+=over 4
+
+=item
+
+C<0> sets the queue to use numerical priorities:
+
+ NumQueue => 0
+
+=item
+
+a hash C<< { string => numerical_value,... } >> maps each string to
+the numerical value:
+
+ QueueWith3Levels => { Low => 0, Medium => 50, High => 100 }
+
+=item
+
+an array C<< [ string => numerical_value, ... ] >> maps each string to
+the numerical value, and additionaly tells RT to display strings in the
+order they were given in drop-down menus:
+
+ Ordered => [ Low => 0, High => 100, Medium => 50 ]
+
+In this case the drop-down menus used to choose the priority in RT will
+display Low/High/Medium, in this order
+
+=back
+
+Tickets in queues that aren't defined in this hash will use the mapping
+defined for C<Default>.
+
+A complete example of per-queue priority strings:
+
+ Set(%PriorityAsString,
+ # all queues not listed here will use this mapping
+ Default => { Low => 0, Medium => 50, High => 100 },
+ # These queues use strings,
+ # drop-downs show labels ordered by ascending priority value
+ General => { Low => 0, High => 1 },
+ ColorQueue => { Green => 0, Yellow => 50, Red => 100 },
+ # drop-downs will display in order Low/High/Medium
+ LHM => [ Low => 0, High => 100, Medium => 50 ],
+ # use numerical priorities
+ NumQueue => 0,
+ );
+
+Redefine C<%PriorityAsString> in C<RT_SiteConfig.pm> to set site
+priority strings.
+
+The default is 3 levels of priority: Low, Medium and High
+
+=cut
+
+ Set(%PriorityAsString,
+ Default => { Low => 0, Medium => 50, High => 100 },
+ );
+
=back
=head2 Group Summary Configuration
diff --git a/lib/RT/Config.pm b/lib/RT/Config.pm
index ab42501fdf..24aae41a57 100644
--- a/lib/RT/Config.pm
+++ b/lib/RT/Config.pm
@@ -560,6 +560,14 @@ our %META;
}
},
+ EnablePriorityAsString => {
+ Widget => '/Widgets/Form/Boolean',
+ },
+ PriorityAsString => {
+ Widget => '/Widgets/Form/String',
+ },
+
+
# User overridable locale options
DateTimeFormat => {
Section => 'Locale', #loc
@@ -1859,6 +1867,114 @@ sub EnableExternalAuth {
return;
}
+=head2 Methods for specific options
+
+=head2 PriorityMap( <optional_queue_name> )
+
+Returns a hash ref C<< { <priority_as_string> => <priority_value>, ... } >>
+
+If no queue name is given uses the configuration for C<'Default'>.
+
+If the queue has no C<PriorityAsString> option, uses the one for C<'Default'>.
+
+Returns C<undef> if C<EnablePriorityAsString> is set to 0, if the
+queue has C<PriorityAsString> switched off (by setting it to C<0>) or if no
+map is available.
+
+Logs an error if a PriorityAsString is found but it is neither a hash nor an
+array, nor 0.
+
+=cut
+
+sub PriorityMap
+ { my $self = shift;
+ my $queue = shift || 'Default';
+
+ my $option = $self->PriorityAsStringForQueue( $queue );
+ return undef if ! $option;
+
+ my $map;
+ if ( ref $option eq 'HASH' ) {
+ # regular map
+ $map = $option
+ } elsif ( ref $option eq 'ARRAY' ) {
+ # order is irrelevent here, load the array as a hash
+ $map = { @$option };
+ } else {
+ # try to diagnose the problem by showing some details about the map
+ # note: this could also be done when the config is loaded
+
+ # where was the map defined
+ my $queues= $self->Get('PriorityAsString');
+ my $real_queue = defined $queues->{$queue} ? "queue $queue"
+ : defined $queues->{Default} ? 'Default queue'
+ : 'cannot happen';
+
+ # what's in the map definition
+ my $option_desc = ref $option ? "map is a " . ref( $option )
+ : length $option < 20 ? $option
+ : substr( $option, 0, 17 ) . '...';
+
+ $RT::Logger->error( "Wrong priority map for $real_queue: $option_desc" );
+ return undef;
+ }
+ return $map;
+ }
+
+=head2 PriorityMapOrder( <optional_queue_name> )
+
+Returns an array of priority strings, in the proper order for display.
+
+The order is either given in the C<PriorityAsString> option by using an
+array for the queue, or is based on the numerical values of the options
+(lower values first).
+
+=cut
+
+sub PriorityMapOrder
+ { my $self = shift;
+ my $queue = shift || 'Default';
+
+ my $option = $self->PriorityAsStringForQueue( $queue );
+ return undef if ! $option;
+
+ my @ordered;
+ if ( ref $option eq 'HASH' ) {
+ # hash: sort it on the value
+ @ordered = sort { $option->{$a} <=> $option->{$b} } keys %$option
+ } elsif ( ref $option eq 'ARRAY' ) {
+ # array: use the array order, extract every other element
+ foreach( my $i=0; $i<@$option; $i+=2) {
+ push @ordered, $option->[$i];
+ }
+ } else {
+ return undef;
+ }
+
+ return \@ordered;
+
+ }
+
+# internal method, PriorityAsStringForQueue( <queue name> )
+# returns a hashref { <label> => <value>, ... } or undef if no
+# priority mapping was found
+
+sub PriorityAsStringForQueue
+ { my $self = shift;
+ my $queue = shift;
+
+ return undef if ! $self->Get( 'EnablePriorityAsString' );
+
+ my $queues = $self->Get( 'PriorityAsString' );
+ return undef if ! $queues;
+
+ my $map = defined $queues->{$queue} ? $queues->{$queue}
+ : defined $queues->{Default}? $queues->{Default}
+ : undef;
+
+ return $map;
+ }
+
RT::Base->_ImportOverlays();
1;
diff --git a/lib/RT/Queue.pm b/lib/RT/Queue.pm
index dc286a756b..af101f20e2 100644
--- a/lib/RT/Queue.pm
+++ b/lib/RT/Queue.pm
@@ -1230,6 +1230,11 @@ sub SetDefaultValue {
},
);
+ if( $args{Name}=~ /^(Initial|Final)Priority/ ) {
+ $old_value= $self->PriorityAsString( $old_value );
+ $new_value= $self->PriorityAsString( $new_value );
+ }
+
if ( $ret ) {
return ( $ret, $self->loc( 'Default value of [_1] changed from [_2] to [_3]', $args{Name}, $old_value, $new_value ) );
}
@@ -1238,6 +1243,12 @@ sub SetDefaultValue {
}
}
+sub PriorityAsString {
+ my( $self, $priority )= @_;
+ my $map = RT->Config->PriorityMap( $self->Name );
+ return RT::Ticket->_PriorityAsString( $priority, $map );
+}
+
sub SLA {
my $self = shift;
my $value = shift;
diff --git a/lib/RT/Ticket.pm b/lib/RT/Ticket.pm
index 5c400464cd..80c3a4d19e 100644
--- a/lib/RT/Ticket.pm
+++ b/lib/RT/Ticket.pm
@@ -2820,10 +2820,18 @@ sub _Set {
return ( $ret, $msg ) unless $args{'RecordTransaction'};
my $trans;
+
+ my $New= $args{'Value'};
+ # *Priority fields may need to be translated
+ if( $args{'Field'} =~ m{^(Initial|Final)?Priority$} ) {
+ $Old= $self->_PriorityAsString( $Old );
+ $New= $self->_PriorityAsString( $New );
+ }
+
( $ret, $msg, $trans ) = $self->_NewTransaction(
Type => $args{'TransactionType'},
Field => $args{'Field'},
- NewValue => $args{'Value'},
+ NewValue => $New,
OldValue => $Old,
TimeTaken => $args{'TimeTaken'},
);
@@ -3348,7 +3356,9 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
Returns the current value of InitialPriority.
(In the database, InitialPriority is stored as int(11).)
+=head2 InitialPriorityAsString
+Returns the current mapped string value of InitialPriority.
=head2 SetInitialPriority VALUE
@@ -3366,7 +3376,9 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
Returns the current value of FinalPriority.
(In the database, FinalPriority is stored as int(11).)
+=head2 FinalPriorityAsString
+Returns the current mapped string value of FinalPriority.
=head2 SetFinalPriority VALUE
@@ -3384,7 +3396,9 @@ Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
Returns the current value of Priority.
(In the database, Priority is stored as int(11).)
+=head2 PriorityAsString
+Returns the current mapped string value of Priority.
=head2 SetPriority VALUE
@@ -3729,6 +3743,53 @@ sub Serialize {
return %store;
}
+# Returns String: Various Ticket Priorities as either a string or integer
+sub PriorityAsString {
+ my $self = shift;
+ return $self->_PriorityAsString( $self->Priority );
+}
+
+sub InitialPriorityAsString {
+ my $self = shift;
+ return $self->_PriorityAsString( $self->InitialPriority );
+}
+
+sub FinalPriorityAsString {
+ my $self=shift;
+ return $self->_PriorityAsString( $self->FinalPriority );
+}
+
+sub _PriorityAsString {
+ my $self = shift;
+ my $priority = shift;
+ return undef unless defined $priority && length $priority;
+
+ my $map;
+ if ( @_ ) {
+ $map = shift;
+ } else {
+ my $queue_name = $self->QueueObj->Name;
+ $map = RT->Config->PriorityMap($queue_name);
+ }
+
+ return $priority if !$map;
+
+ my @orderedLabels = sort { $map->{$b} <=> $map->{$a} } keys %$map;
+
+ # priority could be '(no value)' (or a localized version)
+ $priority = 0 if $priority !~ m{^\d+$};
+
+ # return the label for the first priority <= $priority
+ foreach my $label ( @orderedLabels ) {
+ return $label if $priority >= $map->{$label};
+ }
+
+ # if we get here the priority is lower than the lowest in the map
+ # return the label associated with the lowest priority
+ return $orderedLabels[-1];
+
+}
+
RT::Base->_ImportOverlays();
1;
diff --git a/share/html/Admin/Queues/DefaultValues.html b/share/html/Admin/Queues/DefaultValues.html
index ca8e2d3dab..35e97a5e13 100644
--- a/share/html/Admin/Queues/DefaultValues.html
+++ b/share/html/Admin/Queues/DefaultValues.html
@@ -59,7 +59,11 @@
<&|/l&>Priority</&>:
</div>
<div class="col-md-9 value">
- <& /Elements/SelectPriority, Name => "InitialPriority", Default => $queue->DefaultValue('InitialPriority') &>
+ <& /Elements/SelectPriority,
+ Name => "InitialPriority",
+ Default => $queue->DefaultValue('InitialPriority'),
+ QueueObj => $queue
+ &>
</div>
</div>
@@ -68,7 +72,11 @@
<&|/l&>Final Priority</&>:
</div>
<div class="col-md-9 value">
- <& /Elements/SelectPriority, Name => "FinalPriority", Default => $queue->DefaultValue('FinalPriority') &>
+ <& /Elements/SelectPriority,
+ Name => "FinalPriority",
+ Default => $queue->DefaultValue('FinalPriority'),
+ QueueObj => $queue
+ &>
<span><em><&|/l&>requires running rt-crontool</&></em></span>
</div>
</div>
diff --git a/share/html/Elements/RT__Queue/ColumnMap b/share/html/Elements/RT__Queue/ColumnMap
index 8c902fbe74..b12b3663c4 100644
--- a/share/html/Elements/RT__Queue/ColumnMap
+++ b/share/html/Elements/RT__Queue/ColumnMap
@@ -67,7 +67,10 @@ my $COLUMN_MAP = {
},
Priority => {
title => 'Priority', # loc
- value => sub { return join '-', $_[0]->DefaultValue('InitialPriority') || '', $_[0]->DefaultValue('FinalPriority') || '' },
+ value => sub { return join '/',
+ map { $_[0]->PriorityAsString( $_[0]->DefaultValue( $_ ) || 0 ) }
+ qw( InitialPriority FinalPriority );
+ },
},
DefaultDueIn => {
title => 'DefaultDueIn', # loc
diff --git a/share/html/Elements/RT__Ticket/ColumnMap b/share/html/Elements/RT__Ticket/ColumnMap
index 5f5d4b6b27..c949a6a565 100644
--- a/share/html/Elements/RT__Ticket/ColumnMap
+++ b/share/html/Elements/RT__Ticket/ColumnMap
@@ -363,6 +363,43 @@ if(RT->Config->Get('DisplayTotalTimeWorked')) {
}
}
+my $printer = sub {
+ my ( $class, $string ) = @_;
+ return '' unless defined $string && length $string;
+
+ my $request_path = $HTML::Mason::Commands::r->path_info;
+ if ( $request_path and $request_path =~ /Results\.tsv/ ) {
+ return loc( $string);
+ }
+
+ my $escaped = $m->interp->apply_escapes( $string, 'h' );
+ my $loc_escaped = $m->interp->apply_escapes( loc( $string ), 'h' );
+ return \( qq{<span class="ticket-info-$class-} . lc( $escaped ) . qq{">$loc_escaped</span>} );
+};
+
+my $queues = RT->Config->Get( 'PriorityAsString' ) || {};
+
+foreach my $field ( qw( Priority InitialPriority FinalPriority ) ) {
+ $COLUMN_MAP->{ $field .'Number' } ||= $COLUMN_MAP->{ $field };
+
+ my $class = lc( $field );
+ $class =~ s/(?=<.)(?=priority)/-/;
+
+ my $method = $field . 'AsString';
+
+ if ( not keys %$queues ) {
+ $COLUMN_MAP->{ $field }{'value'} = sub {
+ return $printer->( $class, $_[0]->$method() );
+ };
+ } else {
+ $COLUMN_MAP->{ $field }{'value'} = sub {
+ return $queues->{$_[0]->QueueObj->Name}
+ ? $printer->( $class, $_[0]->$method() )
+ : $_[0]->$field;
+ };
+ }
+}
+
$m->callback( GenericMap => $GenericMap, COLUMN_MAP => $COLUMN_MAP, CallbackName => 'Once', CallbackOnce => 1 );
return GetColumnMapEntry( Map => $COLUMN_MAP, Name => $Name, Attribute => $Attr );
</%init>
diff --git a/share/html/Elements/SelectPriority b/share/html/Elements/SelectPriority
index 2889b4629e..2166fac1a4 100644
--- a/share/html/Elements/SelectPriority
+++ b/share/html/Elements/SelectPriority
@@ -45,11 +45,48 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
+% if ( %Map ) {
+<select class="select-priority form-control" name="<% $Name %>">
+% unless ( defined $Default ) {
+<option value="">-</option>
+% }
+<%PERL>
+foreach my $Label ( @Order ) {
+ my ( $Value, $Selected );
+ if ( $Label eq $DefaultLabel ) {
+ ( $Value, $Selected ) = ( $Default, 'selected="selected"' );
+ } else {
+ ( $Value, $Selected ) = ( $Map{ $Label }, '' );
+ }
+</%PERL>
+<option class="<% lc $Label %>" value="<% $Value %>" <% $Selected |n %>><% loc($Label) %></option>
+% }
+</select>
+% } else {
<input name="<% $Name %>" type="text" value="<% $Default %>" size="5" class="form-control" />
+% }
<%ARGS>
$Name => 'Priority'
$Default => ''
+$QueueObj => undef
+$PriorityStringMap => undef
</%ARGS>
<%INIT>
+
+my @Order;
+my $DefaultLabel = '';
+my %Map = ();
+
+
+if ( $QueueObj and $QueueObj->Id ) {
+ if ( my $Map = RT->Config->PriorityMap( $QueueObj->Name ) ) {
+ %Map = %$Map;
+ @Order = @{RT->Config->PriorityMapOrder( $QueueObj->Name )};
+ if ( defined $Default && length $Default ) {
+ $DefaultLabel = $QueueObj->PriorityAsString( $Default );
+ }
+ }
+}
+
$Default = '' unless defined $Default;
</%INIT>
diff --git a/share/html/Search/Elements/PickBasics b/share/html/Search/Elements/PickBasics
index 124fc7d9b3..86a7f48ceb 100644
--- a/share/html/Search/Elements/PickBasics
+++ b/share/html/Search/Elements/PickBasics
@@ -398,6 +398,18 @@ else {
Value => { Type => 'text', Size => 5 }
},
);
+
+ if ( RT->Config->Get('EnablePriorityAsString') ) {
+ my ( $priority_dropdown ) = grep { $_->{Name} eq "Priority" } @lines;
+ my %priority_map = ( '-' => '' );
+ for my $queue (keys %queues) {
+ my $queue_priority_map= RT::Config->PriorityMap( $queue );
+ for my $priority ( keys %$queue_priority_map ) {
+ $priority_map{ keys %queues > 1 ? "$queue: $priority" : "$priority" } = $queue_priority_map->{$priority};
+ }
+ }
+ $priority_dropdown->{Value}{Arguments}{PriorityStringMap} = \%priority_map;
+ }
}
$m->callback( Conditions => \@lines );
diff --git a/share/html/Ticket/Create.html b/share/html/Ticket/Create.html
index 35848d74be..a34a03bddf 100644
--- a/share/html/Ticket/Create.html
+++ b/share/html/Ticket/Create.html
@@ -246,7 +246,8 @@
<div class="form-row">
<div class="label col-md-3"><&|/l&>Priority</&>:</div>
<div class="value col-md-9"><& /Elements/SelectPriority,
- Name => "InitialPriority",
+ Name => "InitialPriority",
+ QueueObj => $QueueObj,
Default => $ARGS{InitialPriority} ? $ARGS{InitialPriority} : $QueueObj->DefaultValue('InitialPriority'),
&></div>
</div>
@@ -255,6 +256,7 @@
<div class="label col-md-3"><&|/l&>Final Priority</&>:</div>
<div class="value col-md-9"><& /Elements/SelectPriority,
Name => "FinalPriority",
+ QueueObj => $QueueObj,
Default => $ARGS{FinalPriority} ? $ARGS{FinalPriority} : $QueueObj->DefaultValue('FinalPriority'),
&></div>
</div>
diff --git a/share/html/Ticket/Elements/EditBasics b/share/html/Ticket/Elements/EditBasics
index 56171cd439..c8e86a38a2 100644
--- a/share/html/Ticket/Elements/EditBasics
+++ b/share/html/Ticket/Elements/EditBasics
@@ -127,6 +127,7 @@ unless ( @fields ) {
comp => '/Elements/SelectPriority',
args => {
Name => $field,
+ QueueObj => $QueueObj,
Default => $defaults{$field} || $TicketObj->$field,
}
}
diff --git a/share/html/Ticket/Elements/ShowPriority b/share/html/Ticket/Elements/ShowPriority
index 5fb0ad82c6..0c8670d04f 100644
--- a/share/html/Ticket/Elements/ShowPriority
+++ b/share/html/Ticket/Elements/ShowPriority
@@ -45,7 +45,7 @@
%# those contributions and any derivatives thereof.
%#
%# END BPS TAGGED BLOCK }}}
-<% $Ticket->Priority %>/<% $Ticket->FinalPriority || ''%>
+<% $Ticket->PriorityAsString %>/<% $Ticket->FinalPriorityAsString || ''%>
<%ARGS>
$Ticket => undef
</%ARGS>
diff --git a/t/web/mobile.t b/t/web/mobile.t
index 3f32e49e66..2a1b847330 100644
--- a/t/web/mobile.t
+++ b/t/web/mobile.t
@@ -2,6 +2,9 @@ use strict;
use warnings;
use RT::Test tests => 170;
+# we want to check the numerical priorities
+RT::Config->Set( EnablePriorityAsString => 0 );
+
my ( $url, $m ) = RT::Test->started_ok;
my $root = RT::Test->load_or_create_user( Name => 'root' );
commit b420bf72ebbc4ed778f207bcf7f39f2749975c68
Author: michel <michel at bestpractical.com>
Date: Wed Dec 18 16:45:44 2019 +0100
Test PriorityAsString.
diff --git a/t/web/queue_create.t b/t/web/queue_create.t
index 40f7b3b8b8..680a2ddd9c 100644
--- a/t/web/queue_create.t
+++ b/t/web/queue_create.t
@@ -1,7 +1,7 @@
use strict;
use warnings;
-use RT::Test tests => 13;
+use RT::Test tests => 16;
my ( $baseurl, $m ) = RT::Test->started_ok;
ok $m->login, 'logged in as root';
@@ -69,5 +69,15 @@ diag "Create a queue";
$queue_id = $m->form_name('ModifyQueue')->value('id');
ok $queue_id, "found id of the queue in the form, it's #$queue_id";
-}
+ # Test setting priority
+ $m->follow_link(id => 'page-default-values');
+ $m->content_contains('Final Priority');
+ $m->form_name('ModifyDefaultValues');
+ $m->click_button(value => 'Save Changes');
+ $m->content_contains('Default value of InitialPriority changed');
+ $m->form_name('ModifyDefaultValues');
+ $m->set_fields( FinalPriority => 50);
+ $m->click_button(value => 'Save Changes');
+ $m->content_contains('Default value of FinalPriority changed from Low to Medium');
+}
-----------------------------------------------------------------------
More information about the rt-commit
mailing list