[Rt-commit] rt branch, 4.0/custom-fields-groups, created. rt-4.0.4-227-g1f03dbf

Ruslan Zakirov ruz at bestpractical.com
Tue Sep 4 12:13:53 EDT 2012


The branch, 4.0/custom-fields-groups has been created
        at  1f03dbf232da529db13cce11dac57720e5fded54 (commit)

- Log -----------------------------------------------------------------
commit 9edc6d0bfeae43af5dc57cf1a7dfc702eaeabe62
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Wed Aug 22 22:46:12 2012 +0400

    ::Test::Web->dom method that return Mojo::DOM
    
    Code with it looks sweet.
    
    It's a big module, but no production code will
    need it as it only required when --with-tests-deps
    configure option is used. We have plenty of modules
    required only for tests.
    
    Conflicts:
    	lib/RT/Test/Web.pm

diff --git a/lib/RT/Test/Web.pm b/lib/RT/Test/Web.pm
index 0d044cd..f95f41f 100644
--- a/lib/RT/Test/Web.pm
+++ b/lib/RT/Test/Web.pm
@@ -381,6 +381,14 @@ sub check_links {
     return Test::More::ok( 1, "expected links" );
 }
 
+sub dom {
+    my $self = shift;
+    Carp::croak("Can not get DOM, not HTML repsone")
+        unless $self->is_html;
+    require Mojo::DOM;
+    return Mojo::DOM->new( $self->content );
+}
+
 sub DESTROY {
     my $self = shift;
     if ( !$RT::Test::Web::DESTROY++ ) {
diff --git a/sbin/rt-test-dependencies.in b/sbin/rt-test-dependencies.in
index 758c4e7..613d832 100755
--- a/sbin/rt-test-dependencies.in
+++ b/sbin/rt-test-dependencies.in
@@ -280,6 +280,7 @@ Log::Dispatch::Perl
 Test::WWW::Mechanize::PSGI
 Plack::Middleware::Test::StashWarnings
 Test::LongString
+Mojo::DOM
 .
 
 $deps{'FASTCGI'} = [ text_to_hash( << '.') ];

commit 931d827179e0f5edf647c9a5afbaaf0adb386cec
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Fri Aug 24 04:09:24 2012 +0400

    use messages returned by ValidateCustomFields
    
    ValidateCustomFields component returns validation
    errors in list context for a while. We can use it
    instead of looping through custom fields once again.
    
    Prefix messages with custom field name as we did in
    every caller.

diff --git a/share/html/Elements/ValidateCustomFields b/share/html/Elements/ValidateCustomFields
index 9963039..b2b81ba 100644
--- a/share/html/Elements/ValidateCustomFields
+++ b/share/html/Elements/ValidateCustomFields
@@ -90,7 +90,7 @@ while ( my $CF = $CustomFields->Next ) {
                     my $msg =
                       loc( "Input can not be parsed as an IP address" );
                     $m->notes( ( 'InvalidField-' . $CF->Id ) => $msg );
-                    push @res, $msg;
+                    push @res, loc($CF->Name) .': '. $msg;
                     $valid = 0;
                 }
             }
@@ -101,7 +101,7 @@ while ( my $CF = $CustomFields->Next ) {
                     my $msg =
                       loc( "Input can not be parsed as an IP address range" );
                     $m->notes( ( 'InvalidField-' . $CF->Id ) => $msg );
-                    push @res, $msg;
+                    push @res, loc($CF->Name) .': '. $msg;
                     $valid = 0;
                 }
             }
@@ -111,7 +111,7 @@ while ( my $CF = $CustomFields->Next ) {
 
         my $msg = loc("Input must match [_1]", $CF->FriendlyPattern);
         $m->notes( ('InvalidField-' . $CF->Id) => $msg );
-        push @res, $msg;
+        push @res, loc($CF->Name) .': '. $msg;
         $valid = 0;
     }
 }
diff --git a/share/html/SelfService/Create.html b/share/html/SelfService/Create.html
index ec86fb7..082e2b9 100755
--- a/share/html/SelfService/Create.html
+++ b/share/html/SelfService/Create.html
@@ -121,29 +121,29 @@ $Queue => undef
 my @results;
 my $queue_obj = RT::Queue->new($session{'CurrentUser'});
 $queue_obj->Load($Queue);
-my $CFs = $queue_obj->TicketCustomFields();
-my $ValidCFs = $m->comp(
-    '/Elements/ValidateCustomFields',
-    CustomFields => $CFs,
-    ARGSRef => \%ARGS
-);
 
 my $skip_create = 0;
+
+{
+    my ($status, @msg) = $m->comp(
+        '/Elements/ValidateCustomFields',
+        CustomFields => $queue_obj->TicketCustomFields,
+        ARGSRef => \%ARGS
+    );
+    unless ($status) {
+        push @results, @msg;
+        $skip_create = 1;
+    }
+}
+
 $m->callback( CallbackName => 'BeforeCreate', ARGSRef => \%ARGS, skip_create => \$skip_create, results => \@results );
 
 if ( defined($ARGS{'id'}) and $ARGS{'id'} eq 'new' ) { # new ticket?
-    if ( $ValidCFs && !$skip_create ) {
+    if ( !$skip_create ) {
         $m->comp('Display.html', %ARGS);
         $RT::Logger->crit("After display call; error is $@");
         $m->abort();
     }
-    elsif ( !$ValidCFs ) {
-        # Invalid CFs
-        while (my $CF = $CFs->Next) {
-            my $msg = $m->notes('InvalidField-' . $CF->Id) or next;
-            push @results, $CF->Name . ': ' . $msg;
-        }
-    }
 }
 
 </%init>
diff --git a/share/html/Ticket/Update.html b/share/html/Ticket/Update.html
index fb86b25..6469272 100755
--- a/share/html/Ticket/Update.html
+++ b/share/html/Ticket/Update.html
@@ -283,21 +283,17 @@ if ( $ARGS{'SubmitTicket'} ) {
     my @squelchlist = grep {not $checked{$_}} split /,/, ($ARGS{'TxnRecipients'}||'');
     $ARGS{'SquelchMailTo'} = \@squelchlist if @squelchlist;
 
-    my $CFs = $TicketObj->TransactionCustomFields;
-    my $ValidCFs = $m->comp(
+    my ($status, @msg) = $m->comp(
         '/Elements/ValidateCustomFields',
-        CustomFields => $CFs,
+        CustomFields => $TicketObj->TransactionCustomFields,
         NamePrefix => "Object-RT::Transaction--CustomField-",
         ARGSRef => \%ARGS
     );
-    unless ( $ValidCFs ) {
+    unless ( $status ) {
+        push @results, @msg;
         $checks_failure = 1;
-        while (my $CF = $CFs->Next) {
-            my $msg = $m->notes('InvalidField-' . $CF->Id) or next;
-            push @results, loc($CF->Name) . ': ' . $msg;
-        }
     }
-    my $status = $m->comp('/Elements/GnuPG/SignEncryptWidget:Check',
+    $status = $m->comp('/Elements/GnuPG/SignEncryptWidget:Check',
         self      => $gnupg_widget,
         TicketObj => $TicketObj,
     );
diff --git a/share/html/m/ticket/create b/share/html/m/ticket/create
index 3bf402d..729e40c 100644
--- a/share/html/m/ticket/create
+++ b/share/html/m/ticket/create
@@ -157,14 +157,6 @@ $m->callback( QueueObj => $QueueObj, title => \$title, results => \@results, ARG
 
 $QueueObj->Disabled && Abort(loc("Cannot create tickets in a disabled queue."));
 
-my $CFs = $QueueObj->TicketCustomFields();
-
-my $ValidCFs = $m->comp(
-    '/Elements/ValidateCustomFields',
-    CustomFields => $CFs,
-    ARGSRef => \%ARGS
-);
-
 # deal with deleting uploaded attachments
 foreach my $key (keys %ARGS) {
     if ($key =~ m/^DeleteAttach-(.+)$/) {
@@ -193,6 +185,18 @@ unless (keys %{$session{'Attachments'}} and $ARGS{'id'} eq 'new') {
 
 my $checks_failure = 0;
 
+{
+    my ($status, @msg) = $m->comp(
+        '/Elements/ValidateCustomFields',
+        CustomFields => $QueueObj->TicketCustomFields,
+        ARGSRef      => \%ARGS
+    );
+    unless ( $status ) {
+        $checks_failure = 1;
+        push @results, @msg;
+    }
+}
+
 my $gnupg_widget = $m->comp('/Elements/GnuPG/SignEncryptWidget:new', Arguments => \%ARGS );
 $m->comp( '/Elements/GnuPG/SignEncryptWidget:Process',
     self      => $gnupg_widget,
@@ -230,18 +234,11 @@ $m->callback( CallbackName => 'BeforeCreate', ARGSRef => \%ARGS, skip_create =>
               checks_failure => $checks_failure, results => \@results );
 
 if ((!exists $ARGS{'AddMoreAttach'}) and (defined($ARGS{'id'}) and $ARGS{'id'} eq 'new')) { # new ticket?
-    if ( $ValidCFs && !$checks_failure && !$skip_create ) {
+    if ( !$checks_failure && !$skip_create ) {
         $m->comp('show', %ARGS);
         $RT::Logger->crit("After display call; error is $@");
         $m->abort();
     }
-    elsif ( !$ValidCFs ) {
-        # Invalid CFs
-        while (my $CF = $CFs->Next) {
-            my $msg = $m->notes('InvalidField-' . $CF->Id) or next;
-            push @results, $CF->Name . ': ' . $msg;
-        }
-    }
 }
 
 

commit 5e73de16a71e1c69f6911c4e7e22e167ece4a93a
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Aug 25 02:06:23 2012 +0400

    names for forms on Ticket's pages
    
    testing is easier and it's more consistent to have
    them like on other pages.

diff --git a/share/html/Ticket/ModifyDates.html b/share/html/Ticket/ModifyDates.html
index 18406fb..f195302 100755
--- a/share/html/Ticket/ModifyDates.html
+++ b/share/html/Ticket/ModifyDates.html
@@ -51,7 +51,7 @@
 % $m->callback(CallbackName => 'BeforeActionList', Actions => \@results, ARGSRef => \%ARGS, Ticket => $TicketObj);
 <& /Elements/ListActions, actions => \@results &>
 
-<form method="post" action="ModifyDates.html">
+<form method="post" action="ModifyDates.html" name="TicketDates">
 % $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS );
 <input type="hidden" class="hidden" name="id" value="<%$TicketObj->Id%>" />
 <&| /Widgets/TitleBox,title => loc('Modify dates for ticket # [_1]', $TicketObj->Id), class=> 'ticket-info-dates' &>
diff --git a/share/html/Ticket/ModifyPeople.html b/share/html/Ticket/ModifyPeople.html
index 9748a69..d5daf59 100755
--- a/share/html/Ticket/ModifyPeople.html
+++ b/share/html/Ticket/ModifyPeople.html
@@ -51,7 +51,7 @@
 % $m->callback(CallbackName => 'BeforeActionList', Actions => \@results, ARGSRef => \%ARGS, Ticket => $Ticket);
 <& /Elements/ListActions, actions => \@results &>
 
-<form method="post" action="ModifyPeople.html">
+<form method="post" action="ModifyPeople.html" name="TicketPeople">
 <input type="hidden" class="hidden" name="id" value="<%$Ticket->Id%>" />
 % $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS );
 <&| /Widgets/TitleBox, title => loc('Modify people related to ticket #[_1]', $Ticket->Id),   width => "100%", color=> "#333399", class=>'ticket-info-people' &>

commit fa929f282f8667671a850a0eb851da87fa1d86ca
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Sep 1 02:55:58 2012 +0400

    add Groups related methods to RT::CustomField[s]
    
    We will have several built in groups for each object,
    for example Basics, People, Dates, etc. for Tickets.
    
    Now assigning custom fields to groups is in config,
    but we should move it to UI.

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index d8e8780..abce5f8 100755
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -2597,4 +2597,13 @@ with L</Lifecycles> (see L</Labeling and defining actions>).
 
 =cut
 
+Set(%CustomFieldGroups,
+    'RT::Ticket' => {
+        Basics => [],
+        Dates => [],
+        People => [],
+        Links   => [],
+    },
+);
+
 1;
diff --git a/lib/RT/CustomField.pm b/lib/RT/CustomField.pm
index 2770f42..d605662 100644
--- a/lib/RT/CustomField.pm
+++ b/lib/RT/CustomField.pm
@@ -1183,6 +1183,51 @@ sub CollectionClassFromLookupType {
     return $collection_class;
 }
 
+
+sub Group {
+
+
+}
+
+sub Groups {
+    my $self = shift;
+    my $record = shift;
+
+    my $record_class = ref($record) || $record || '';
+    $record_class = $self->RecordClassFromLookupType
+        if !$record_class && $self->id;
+
+    my $config = RT->Config->Get('CustomFieldGroups');
+    my @groups;
+    if ( $record_class ) {
+        @groups = keys %{ $config->{$record_class} };
+    } else {
+        @groups = map { keys %$_ } values %$config;
+    }
+
+    my %seen;
+    return
+        sort { lc($a) cmp lc($b) }
+        grep defined && length && !$seen{lc $_}++,
+        @groups;
+}
+
+my %BUILTIN_GROUPS = (
+    'RT::Ticket' => { map { $_ => 1 } qw(Basics Dates Links People) },
+);
+$BUILTIN_GROUPS{''} = { map { %$_ } values %BUILTIN_GROUPS  };
+
+sub CustomGroups {
+    my $self = shift;
+    my $record = shift;
+
+    my $record_class = ref($record) || $record || '';
+    $record_class = $self->RecordClassFromLookupType
+        if !$record_class && $self->id;
+
+    return grep !$BUILTIN_GROUPS{$record_class}{$_}, $self->Groups( $record_class );
+}
+
 =head1 ApplyGlobally
 
 Certain custom fields (users, groups) should only be applied globally
diff --git a/lib/RT/CustomFields.pm b/lib/RT/CustomFields.pm
index 185cf8b..e7c0b23 100644
--- a/lib/RT/CustomFields.pm
+++ b/lib/RT/CustomFields.pm
@@ -95,6 +95,36 @@ sub _Init {
     return ( $self->SUPER::_Init(@_) );
 }
 
+sub LimitToGroup {
+    my $self = shift;
+    my $group = shift;
+
+    if ( $group ) {
+        my $list = RT->Config->Get('CustomFieldGroups')->{'RT::Ticket'}{$group};
+        unless ( $list && @$list ) {
+            return $self->Limit( FIELD => 'id', VALUE => 0, ENTRYAGGREGATOR => 'AND' );
+        }
+        foreach ( @$list ) {
+            $self->Limit( FIELD => 'Name', VALUE => $_ );
+        }
+    } else {
+        my @list = map {@$_} grep defined && ref $_,
+            values %{ RT->Config->Get('CustomFieldGroups')->{'RT::Ticket'} };
+
+        return unless @list;
+        foreach ( @list ) {
+            $self->Limit(
+                FIELD => 'Name',
+                OPERATOR => '!=',
+                VALUE => $_,
+                ENTRYAGGREGATOR => 'AND',
+            );
+        }
+
+    }
+    return;
+}
+
 
 =head2 LimitToLookupType
 

commit 0c11e3aecfaf4f20e4f0d49e6e4747ac9cf23faf
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Sep 1 02:59:51 2012 +0400

    Group argument in {Show,Edit}CustomFields comps
    
    If argument is defined then show/edit only custom fields from
    this particular group.

diff --git a/share/html/Elements/ShowCustomFields b/share/html/Elements/ShowCustomFields
index 2f7fc24..5d2679b 100644
--- a/share/html/Elements/ShowCustomFields
+++ b/share/html/Elements/ShowCustomFields
@@ -83,6 +83,8 @@ $m->callback(
     CustomFields => $CustomFields,
 );
 
+$CustomFields->LimitToGroup($Group) if defined $Group;
+
 # don't print anything if there is no custom fields
 return unless $CustomFields->First;
 $CustomFields->GotoFirstItem;
@@ -127,5 +129,6 @@ my $print_value = sub {
 <%ARGS>
 $Object => undef
 $CustomFields => $Object->CustomFields
+$Group => undef
 $Table => 1
 </%ARGS>
diff --git a/share/html/Ticket/Elements/EditCustomFields b/share/html/Ticket/Elements/EditCustomFields
index d4e2f73..abe5500 100755
--- a/share/html/Ticket/Elements/EditCustomFields
+++ b/share/html/Ticket/Elements/EditCustomFields
@@ -90,6 +90,8 @@ if ($TicketObj && !$OnCreate) {
     $NamePrefix .= "Object-RT::Ticket--CustomField-";
 }
 
+$CustomFields->LimitToGroup( $Group ) if defined $Group;
+
 $m->callback( %ARGS, CallbackName => 'MassageCustomFields', CustomFields => $CustomFields );
 
 $AsTable ||= $InTable;
@@ -108,6 +110,7 @@ $NamePrefix => ''
 $TicketObj => undef
 $QueueObj => undef
 $OnCreate => undef
+$Group => undef
 $DefaultsFromTopArguments => 1
 $AsTable => 0
 $InTable => 0

commit f0991b519d62adbacd815fa72156d1a1899bea54
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Sep 1 03:24:09 2012 +0400

    pass all arguments from Tickets's ShowCustomFields
    
    It's a wrapper for /Elements/ShowCustomFields and
    there is no reason not to pass everything

diff --git a/share/html/Ticket/Elements/ShowCustomFields b/share/html/Ticket/Elements/ShowCustomFields
index 3a2924d..4543250 100755
--- a/share/html/Ticket/Elements/ShowCustomFields
+++ b/share/html/Ticket/Elements/ShowCustomFields
@@ -45,7 +45,7 @@
 %# those contributions and any derivatives thereof.
 %#
 %# END BPS TAGGED BLOCK }}}
-<& /Elements/ShowCustomFields, Object => $Ticket &>
+<& /Elements/ShowCustomFields, %ARGS, Object => $Ticket &>
 <%ARGS>
 $Ticket => undef
 </%ARGS>

commit 828c2701407b5998efc433ff10571d0f8ac13277
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Sep 1 03:29:47 2012 +0400

    show custom fields in different places in UI

diff --git a/share/html/Elements/ShowLinks b/share/html/Elements/ShowLinks
index 6a06d6a..0958a32 100755
--- a/share/html/Elements/ShowLinks
+++ b/share/html/Elements/ShowLinks
@@ -138,6 +138,7 @@ while ( my $link = $depends_on->Next ) {
 </ul>
     </td>
   </tr>
+  <& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Group => 'Links', Table => 0 &>
 % # Allow people to add more rows to the table
 % $m->callback( %ARGS );
 </table>
diff --git a/share/html/Ticket/Elements/ShowBasics b/share/html/Ticket/Elements/ShowBasics
index 64012da..4a86366 100755
--- a/share/html/Ticket/Elements/ShowBasics
+++ b/share/html/Ticket/Elements/ShowBasics
@@ -83,6 +83,7 @@
     <td class="value"><& ShowQueue, Ticket => $Ticket, QueueObj => $Ticket->QueueObj &></td>
   </tr>
 % }
+  <& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Group => 'Basics', Table => 0 &>
 % $m->callback( %ARGS, CallbackName => 'EndOfList', TicketObj => $Ticket );
 </table>
 <%ARGS>
diff --git a/share/html/Ticket/Elements/ShowDates b/share/html/Ticket/Elements/ShowDates
index 09a4eec..de18e1d 100755
--- a/share/html/Ticket/Elements/ShowDates
+++ b/share/html/Ticket/Elements/ShowDates
@@ -84,6 +84,7 @@
     <td class="value"><% $UpdatedString | n %></td>
 % }
   </tr>
+  <& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Group => 'Dates', Table => 0 &>
 % $m->callback( %ARGS, CallbackName => 'EndOfList', TicketObj => $Ticket );
 </table>
 <%ARGS>
diff --git a/share/html/Ticket/Elements/ShowPeople b/share/html/Ticket/Elements/ShowPeople
index cb5fb32..af55efd 100755
--- a/share/html/Ticket/Elements/ShowPeople
+++ b/share/html/Ticket/Elements/ShowPeople
@@ -66,6 +66,7 @@
     <td class="labeltop"><&|/l&>AdminCc</&>:</td>
     <td class="value"><& ShowGroupMembers, Group => $Ticket->AdminCc, Ticket => $Ticket &></td>
   </tr>
+  <& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Group => 'People', Table => 0 &>
 </table>
 <%INIT>
 </%INIT>
diff --git a/share/html/Ticket/Elements/ShowSummary b/share/html/Ticket/Elements/ShowSummary
index 8189de7..f42afe4 100755
--- a/share/html/Ticket/Elements/ShowSummary
+++ b/share/html/Ticket/Elements/ShowSummary
@@ -53,11 +53,13 @@
         (($can_modify || $can_modify_cf) ? (title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id) : ()),
         class => 'ticket-info-basics',
     &><& /Ticket/Elements/ShowBasics, Ticket => $Ticket &></&>
+% foreach my $group ( RT::CustomField->CustomGroups($Ticket), '' ) {
     <&| /Widgets/TitleBox, title => loc('Custom Fields'),
         (($can_modify || $can_modify_cf) ? (title_href => RT->Config->Get('WebPath')."/Ticket/Modify.html?id=".$Ticket->Id) : ()),
         class => 'ticket-info-cfs',
         hide_empty => 1,
-    &><& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket &></&>
+    &><& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Group => $group &></&>
+% }
 
     <&| /Widgets/TitleBox, title => loc('People'),
         (($can_modify || $can_modify_owner) ? (title_href => RT->Config->Get('WebPath')."/Ticket/ModifyPeople.html?id=".$Ticket->Id) : ()),

commit 7712c44c8831f8248b3f542f9b9432860ea0adaf
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Sep 1 03:31:11 2012 +0400

    don't render any wrappers if content is empty
    
    this allows us to hide whole title boxes without content,
    but it fails if anything is rendered even an empty div.

diff --git a/share/html/Ticket/Elements/EditCustomFields b/share/html/Ticket/Elements/EditCustomFields
index abe5500..742df6f 100755
--- a/share/html/Ticket/Elements/EditCustomFields
+++ b/share/html/Ticket/Elements/EditCustomFields
@@ -94,6 +94,10 @@ $CustomFields->LimitToGroup( $Group ) if defined $Group;
 
 $m->callback( %ARGS, CallbackName => 'MassageCustomFields', CustomFields => $CustomFields );
 
+# don't print anything if there is no custom fields
+return unless $CustomFields->First;
+$CustomFields->GotoFirstItem;
+
 $AsTable ||= $InTable;
 my $FIELD = $AsTable ? 'tr' : 'div';
 my $CELL  = $AsTable ? 'td' : 'div';

commit 64cb4dbd382c30580d8f76e275ce1188275300d3
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Sep 1 03:36:46 2012 +0400

    split editing CFs into groups
    
    we place CF editors links/dates/people pages and
    modify/modify all/create we place them into different
    boxes.

diff --git a/share/html/Elements/EditLinks b/share/html/Elements/EditLinks
index 05a9280..91fb80d 100755
--- a/share/html/Elements/EditLinks
+++ b/share/html/Elements/EditLinks
@@ -158,6 +158,9 @@
     <td class="label"><& ShowRelationLabel, id => $id, Label => loc('Referred to by'), Relation => 'ReferredToBy' &>:</td>
     <td class="entry"> <input name="RefersTo-<%$id%>" /></td>
   </tr>
+% if ( $Object->isa('RT::Ticket') ) {
+  <& /Ticket/Elements/EditCustomFields, TicketObj => $Object, Group => 'Links', InTable => 1 &>
+% }
 % $m->callback( CallbackName => 'NewLink' );
 </table>
 </td>
diff --git a/share/html/Ticket/Create.html b/share/html/Ticket/Create.html
index 6ddbdd0..7165189 100755
--- a/share/html/Ticket/Create.html
+++ b/share/html/Ticket/Create.html
@@ -101,11 +101,18 @@
 
 % $m->callback( CallbackName => 'AfterOwner', ARGSRef => \%ARGS );
 
-      <& /Ticket/Elements/EditCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1 &>
+      <& /Ticket/Elements/EditCustomFields, %ARGS, QueueObj => $QueueObj, Group => 'Basics', InTable => 1 &>
       <& /Ticket/Elements/EditTransactionCustomFields, %ARGS, QueueObj => $QueueObj, InTable => 1 &>
     </table>
   </&>
 % $m->callback( CallbackName => 'AfterBasics', QueueObj => $QueueObj );
+
+% foreach my $group ( RT::CustomField->CustomGroups( 'RT::Ticket' ), '' ) {
+<&| /Widgets/TitleBox, title => $group? loc($group) : loc('Custom Fields'), class => 'ticket-info-cfs', hide_empty => 1 &>
+<& Elements/EditCustomFields, %ARGS, QueueObj => $QueueObj, DefaultsFromTopArguments => 0, Group => $group &>
+</&>
+% }
+
 </div>
 
 <div id="ticket-create-message">
@@ -152,6 +159,8 @@
   </td>
 </tr>
 
+<& Elements/EditCustomFields, QueueObj => $QueueObj, Group => 'People', InTable => 1 &>
+
 <tr>
 <td class="label">
 <&|/l&>Subject</&>:
@@ -238,6 +247,7 @@
 <table>
 <tr><td class="label"><&|/l&>Starts</&>:</td><td><& /Elements/SelectDate, Name => "Starts", Default => $ARGS{Starts} || '' &></td></tr>
 <tr><td class="label"><&|/l&>Due</&>:</td><td><& /Elements/SelectDate, Name => "Due", Default => $ARGS{Due} || '' &></td></tr>
+<& Elements/EditCustomFields, QueueObj => $QueueObj, Group => 'Dates', InTable => 1 &>
 </table>
 </&>
 </div>
@@ -257,8 +267,7 @@
 <tr><td class="label"><&|/l&>Children</&></td><td><input size="10" name="MemberOf-new" value="<% $ARGS{'MemberOf-new'} || '' %>" /></td></tr>
 <tr><td class="label"><&|/l&>Refers to</&></td><td><input size="10" name="new-RefersTo" value="<% $ARGS{'new-RefersTo'} || '' %>" /></td></tr>
 <tr><td class="label"><&|/l&>Referred to by</&></td><td><input size="10" name="RefersTo-new" value="<% $ARGS{'RefersTo-new'} || '' %>" /></td></tr>
-
-
+<& Elements/EditCustomFields, QueueObj => $QueueObj, Group => 'Links', InTable => 1 &>
 </table>
 </&>
 </div>
diff --git a/share/html/Ticket/Elements/EditDates b/share/html/Ticket/Elements/EditDates
index bfa3a30..7b6d7a6 100755
--- a/share/html/Ticket/Elements/EditDates
+++ b/share/html/Ticket/Elements/EditDates
@@ -70,6 +70,7 @@
       <& /Elements/SelectDate, menu_prefix => 'Due', current => 0 &> (<% $TicketObj->DueObj->AsString %>)
     </td>
   </tr>
+  <& EditCustomFields, TicketObj => $TicketObj, Group => 'Dates', InTable => 1 &>
 % $m->callback( %ARGS, CallbackName => 'EndOfList', Ticket => $TicketObj );
 </table>
 <%ARGS>
diff --git a/share/html/Ticket/Elements/EditPeople b/share/html/Ticket/Elements/EditPeople
index 980700e..87afade 100755
--- a/share/html/Ticket/Elements/EditPeople
+++ b/share/html/Ticket/Elements/EditPeople
@@ -66,17 +66,29 @@
 <h3><&|/l&>Owner</&></h3>
 <&|/l&>Owner</&>: <& /Elements/SelectOwner, Name => 'Owner', QueueObj => $Ticket->QueueObj, TicketObj => $Ticket, Default => $Ticket->OwnerObj->Id, DefaultValue => 0&>
 <h3><&|/l&>Current watchers</&></h3>
+<i><&|/l&>(Check box to delete)</&></i><br />
 
-<&|/l&>Requestors</&>:
-<& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->Requestors &>
+<table>
 
-<&|/l&>Cc</&>:
-<& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->Cc &>
+<tr>
+  <td class="label"><&|/l&>Requestors</&>:</td>
+  <td class="value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->Requestors &></td>
+</tr>
 
-<&|/l&>Administrative Cc</&>:
-<& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->AdminCc &>
+<tr>
+  <td class="label"><&|/l&>Cc</&>:</td>
+  <td class="value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->Cc &></td>
+</tr>
+
+<tr>
+  <td class="label"><&|/l&>Administrative Cc</&>:</td>
+  <td class="value"><& EditWatchers, TicketObj => $Ticket, Watchers => $Ticket->AdminCc &></td>
+</tr>
+
+<& EditCustomFields, TicketObj => $Ticket, Group => 'People', InTable => 1 &>
+
+</table>
 
-<i><&|/l&>(Check box to delete)</&></i><br />
 </td>
 </tr>
 </table>
diff --git a/share/html/Ticket/Modify.html b/share/html/Ticket/Modify.html
index d5ca8b9..e6f46cf 100755
--- a/share/html/Ticket/Modify.html
+++ b/share/html/Ticket/Modify.html
@@ -57,10 +57,16 @@
 
 <&| /Widgets/TitleBox, title => loc('Modify ticket #[_1]',$TicketObj->Id), class=>'ticket-info-basics' &>
 <& Elements/EditBasics, TicketObj => $TicketObj &>
-<& Elements/EditCustomFields, TicketObj => $TicketObj, DefaultsFromTopArguments => 0 &>
+<& Elements/EditCustomFields, TicketObj => $TicketObj, DefaultsFromTopArguments => 0, Group => 'Basics' &>
 </&>
 % $m->callback( CallbackName => 'AfterBasics', Ticket => $TicketObj );
 
+% foreach my $group ( RT::CustomField->CustomGroups( $TicketObj ), '' ) {
+<&| /Widgets/TitleBox, title => $group? loc($group) : loc('Custom Fields'), class=>'ticket-info-cfs', hide_empty => 1 &>
+<& Elements/EditCustomFields, TicketObj => $TicketObj, DefaultsFromTopArguments => 0, Group => $group &>
+</&>
+% }
+
 <& /Elements/Submit, Name => 'SubmitTicket', Label => loc('Save Changes'), Caption => loc("If you've updated anything above, be sure to"), color => "#993333" &>
 </form>
 <%INIT>
diff --git a/share/html/Ticket/ModifyAll.html b/share/html/Ticket/ModifyAll.html
index 6be9a5e..2fba239 100755
--- a/share/html/Ticket/ModifyAll.html
+++ b/share/html/Ticket/ModifyAll.html
@@ -57,11 +57,16 @@
 
 <&| /Widgets/TitleBox, title => loc('Modify ticket # [_1]', $Ticket->Id), class=>'ticket-info-basics' &>
 <& Elements/EditBasics, TicketObj => $Ticket &>
-<& Elements/EditCustomFields, TicketObj => $Ticket &>
+<& Elements/EditCustomFields, TicketObj => $Ticket, Group => 'Basics' &>
 </&>
 
 % $m->callback(CallbackName => 'AfterBasics', Ticket => $Ticket);
-<br />
+
+% foreach my $group ( RT::CustomField->CustomGroups( $Ticket ), '' ) {
+<&| /Widgets/TitleBox, title => $group? loc($group) : loc('CustomFields'), class => 'ticket-info-cfs', hide_empty => 1 &>
+<& Elements/EditCustomFields, TicketObj => $Ticket, Group => $group &>
+</&>
+% }
 
 <&| /Widgets/TitleBox, title => loc('Dates'), class=>'ticket-info-dates'&>
 <& Elements/EditDates, TicketObj => $Ticket &>

commit 785e59637c901a9d9c05e4695c2a2045af06a66f
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Sep 1 03:38:50 2012 +0400

    add CFs processing to pages where we need it

diff --git a/share/html/Ticket/ModifyLinks.html b/share/html/Ticket/ModifyLinks.html
index fdb23e4..cc39138 100755
--- a/share/html/Ticket/ModifyLinks.html
+++ b/share/html/Ticket/ModifyLinks.html
@@ -72,6 +72,7 @@ my $Ticket = LoadTicket($id);
 my @results;  
 $m->callback( TicketObj => $Ticket, ARGSRef => \%ARGS, Results => \@results );
 push @results, ProcessTicketLinks( TicketObj => $Ticket, ARGSRef => \%ARGS );
+push @results, ProcessObjectCustomFieldUpdates( TicketObj => $Ticket, ARGSRef => \%ARGS );
 $Ticket->ApplyTransactionBatch;
     
 </%INIT>
diff --git a/share/html/Ticket/ModifyPeople.html b/share/html/Ticket/ModifyPeople.html
index d5daf59..c5ae01e 100755
--- a/share/html/Ticket/ModifyPeople.html
+++ b/share/html/Ticket/ModifyPeople.html
@@ -100,6 +100,8 @@ $Ticket->SquelchMailTo($_)
 unless ($OnlySearchForPeople or $OnlySearchForGroup) {
     push @results, ProcessTicketBasics( TicketObj => $Ticket, ARGSRef => \%ARGS);
     push @results, ProcessTicketWatchers( TicketObj => $Ticket, ARGSRef => \%ARGS);
+    push @results, ProcessObjectCustomFieldUpdates( TicketObj => $Ticket, ARGSRef => \%ARGS );
+
     $Ticket->ApplyTransactionBatch;
 }
 

commit 1f03dbf232da529db13cce11dac57720e5fded54
Author: Ruslan Zakirov <ruz at bestpractical.com>
Date:   Sat Sep 1 04:12:30 2012 +0400

    test custom field groups

diff --git a/share/html/Ticket/ModifyLinks.html b/share/html/Ticket/ModifyLinks.html
index cc39138..18bc681 100755
--- a/share/html/Ticket/ModifyLinks.html
+++ b/share/html/Ticket/ModifyLinks.html
@@ -51,7 +51,7 @@
 % $m->callback(CallbackName => 'BeforeActionList', Actions => \@results, ARGSRef => \%ARGS, Ticket => $Ticket);
 <& /Elements/ListActions, actions => \@results &>
 
-<form action="ModifyLinks.html" method="post">
+<form action="ModifyLinks.html" method="post" name="TicketLinks">
 <input type="hidden" class="hidden" name="id" value="<%$Ticket->id%>" />
 % $m->callback( CallbackName => 'FormStart', ARGSRef => \%ARGS );
 % my (@extra);
diff --git a/t/web/cf_groups.t b/t/web/cf_groups.t
new file mode 100644
index 0000000..d7062a5
--- /dev/null
+++ b/t/web/cf_groups.t
@@ -0,0 +1,158 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use RT::Test tests => 67;
+
+RT->Config->Set( 'CustomFieldGroups',
+    'RT::Ticket' => {
+        Basics => ['TestBasics'],
+        Dates  => ['TestDates'],
+        People => ['TestPeople'],
+        Links  => ['TestLinks'],
+        More   => ['TestMore'],
+    },
+);
+
+my %CF;
+
+foreach my $name ( map { @$_ } values %{ RT->Config->Get('CustomFieldGroups')->{'RT::Ticket'} } ) {
+    my $cf = RT::CustomField->new( RT->SystemUser );
+    my ($id, $msg) = $cf->Create(
+        Name => $name,
+        Queue => '0',
+        Description => 'A Testing custom field',
+        Type => 'FreeformSingle',
+        Pattern => qr{^(?!bad value).*$},
+    );
+    ok $id, "custom field '$name' correctly created";
+    $CF{$name} = $cf;
+}
+
+my $queue = RT::Test->load_or_create_queue( Name => 'General' );
+
+my ( $baseurl, $m ) = RT::Test->started_ok;
+ok $m->login, 'logged in as root';
+
+{
+    note "testing Create";
+    $m->goto_create_ticket($queue);
+
+    my $prefix = 'Object-RT::Ticket--CustomField-';
+    my $dom = $m->dom;
+    $m->form_name('TicketCreate');
+
+    my $input_name = $prefix . $CF{'TestBasics'}->id .'-Value';
+    is $dom->find(qq{input[name="$input_name"]})->size, 1, "only one CF input on the page";
+    ok $dom->at(qq{.ticket-info-basics input[name="$input_name"]}), "CF is in the right place";
+    $m->field( $input_name, 'TestBasicsValue' );
+
+    $input_name = $prefix . $CF{'TestPeople'}->id .'-Value';
+    is $dom->find(qq{input[name="$input_name"]})->size, 1, "only one CF input on the page";
+    ok $dom->at(qq{#ticket-create-message input[name="$input_name"]}), "CF is in the right place";
+    $m->field( $input_name, 'TestPeopleValue' );
+
+    $input_name = $prefix . $CF{'TestDates'}->id .'-Value';
+    is $dom->find(qq{input[name="$input_name"]})->size, 1, "only one CF input on the page";
+    ok $dom->at(qq{.ticket-info-dates input[name="$input_name"]}), "CF is in the right place";
+    $m->field( $input_name, 'TestDatesValue' );
+
+    $input_name = $prefix . $CF{'TestLinks'}->id .'-Value';
+    is $dom->find(qq{input[name="$input_name"]})->size, 1, "only one CF input on the page";
+    ok $dom->at(qq{.ticket-info-links input[name="$input_name"]}), "CF is in the right place";
+    $m->field( $input_name, 'TestLinksValue' );
+
+    $input_name = $prefix . $CF{'TestMore'}->id .'-Value';
+    is $dom->find(qq{input[name="$input_name"]})->size, 1, "only one CF input on the page";
+    ok $dom->at(qq{.ticket-info-cfs input[name="$input_name"]}), "CF is in the right place";
+    $m->field( $input_name, 'TestMoreValue' );
+
+    $m->submit;
+
+    note "testing Display";
+    my $id = $m->get_ticket_id;
+    ok $id, "created a ticket";
+    $dom = $m->dom;
+
+    foreach my $name ( qw(Basics People Dates Links) ) {
+        my $row_id = 'CF-'. $CF{"Test$name"}->id .'-ShowRow';
+        is $dom->find(qq{#$row_id})->size, 1, "CF on the page";
+        is $dom->at(qq{#$row_id})->all_text, "Test$name: Test${name}Value", "value is set";
+        ok $dom->at(qq{.ticket-info-\L$name\E #$row_id}), "CF is in the right place";
+    }
+    {
+        my $row_id = 'CF-'. $CF{"TestMore"}->id .'-ShowRow';
+        is $dom->find(qq{#$row_id})->size, 1, "CF on the page";
+        is $dom->at(qq{#$row_id})->all_text, "TestMore: TestMoreValue", "value is set";
+        ok $dom->at(qq{.ticket-info-cfs #$row_id}), "CF is in the right place";
+    }
+
+    $prefix = 'Object-RT::Ticket-'. $id .'-CustomField-';
+
+    note "testing Basics/People/Dates/Links pages";
+    { # Basics
+        $m->follow_link_ok({id => 'page-basics'}, 'Ticket -> Basics');
+        $m->form_name("TicketModify");
+        is $m->dom->find(qq{input[name^="$prefix"][name\$="-Value"]})->size, 2,
+            "only one CF input on the page";
+        my $input_name = $prefix . $CF{'TestBasics'}->id .'-Value';
+        ok $m->dom->at(qq{.ticket-info-basics input[name="$input_name"]}),
+            "CF is in the right place";
+        $m->field( $input_name, "TestBasicsChanged" );
+        $m->click('SubmitTicket');
+        $m->content_like(qr{to TestBasicsChanged});
+
+        $m->form_name("TicketModify");
+        $m->field( $input_name, "bad value" );
+        $m->click('SubmitTicket');
+        $m->content_like(qr{Input must match});
+    }
+    { # Custom group 'More'
+        $m->follow_link_ok({id => 'page-basics'}, 'Ticket -> Basics');
+        $m->form_name("TicketModify");
+        my $input_name = $prefix . $CF{'TestMore'}->id .'-Value';
+        ok $m->dom->at(qq{.ticket-info-cfs input[name="$input_name"]}),
+            "CF is in the right place";
+        $m->field( $input_name, "TestMoreChanged" );
+        $m->click('SubmitTicket');
+        $m->content_like(qr{to TestMoreChanged});
+
+        $m->form_name("TicketModify");
+        $m->field( $input_name, "bad value" );
+        $m->click('SubmitTicket');
+        $m->content_like(qr{Input must match});
+    }
+
+    foreach my $name ( qw(People Dates Links) ) {
+        $m->follow_link_ok({id => "page-\L$name"}, "Ticket's $name page");
+        $m->form_name("Ticket$name");
+        is $m->dom->find(qq{input[name^="$prefix"][name\$="-Value"]})->size, 1,
+            "only one CF input on the page";
+        my $input_name = $prefix . $CF{"Test$name"}->id .'-Value';
+        $m->field( $input_name, "Test${name}Changed" );
+        $m->click('SubmitTicket');
+        $m->content_like(qr{to Test${name}Changed});
+
+        $m->form_name("Ticket$name");
+        $m->field( $input_name, "bad value" );
+        $m->click('SubmitTicket');
+        $m->content_like(qr{Input must match});
+    }
+
+    note "testing Jumbo";
+    $m->follow_link_ok({id => "page-jumbo"}, "Ticket's Jumbo page");
+    $dom = $m->dom;
+    $m->form_name("TicketModifyAll");
+
+    foreach my $name ( qw(Basics People Dates Links More) ) {
+        my $input_name = $prefix . $CF{"Test$name"}->id .'-Value';
+        is $dom->find(qq{input[name="$input_name"]})->size, 1,
+            "only one CF input on the page";
+        $m->field( $input_name, "Test${name}Again" );
+    }
+    $m->click('SubmitTicket');
+    foreach my $name ( qw(Basics People Dates Links More) ) {
+        $m->content_like(qr{to Test${name}Again});
+    }
+}

-----------------------------------------------------------------------


More information about the Rt-commit mailing list