[Rt-commit] rt branch 5.0/add-create-tickets-template-gui created. rt-5.0.5-108-g9d4a5b91d5

BPS Git Server git at git.bestpractical.com
Wed Dec 20 23:44:08 UTC 2023


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "rt".

The branch, 5.0/add-create-tickets-template-gui has been created
        at  9d4a5b91d51ce938bcb512fd5a9dcf6b1b895b9b (commit)

- Log -----------------------------------------------------------------
commit 9d4a5b91d51ce938bcb512fd5a9dcf6b1b895b9b
Author: Brad Embree <brad at bestpractical.com>
Date:   Sun Dec 17 18:11:22 2023 -0800

    Update tests

diff --git a/t/web/html_template.t b/t/web/html_template.t
index abb895c75a..7d071da370 100644
--- a/t/web/html_template.t
+++ b/t/web/html_template.t
@@ -15,6 +15,7 @@ my $content  = Encode::decode("UTF-8", "测试");
 {
     $m->follow_link_ok( { id => 'admin-global-templates' }, '-> Templates' );
     $m->follow_link_ok( { text => 'Autoreply in HTML' },    '-> Autoreply in HTML' );
+    $m->follow_link_ok( { text => 'Content' },              '-> Content' );
 
     $m->submit_form(
         form_name => 'ModifyTemplate',
diff --git a/t/web/template.t b/t/web/template.t
index 4bca733c65..69a570fef9 100644
--- a/t/web/template.t
+++ b/t/web/template.t
@@ -60,10 +60,12 @@ $m->form_name('ModifyTemplate');
 is($m->value('Type'), 'Perl', 'now that we have ExecuteCode we can update Type to Perl');
 
 { # 21152: Each time you save a Template a newline is chopped off the front
+  # go to Content tab
+  $m->follow_link( text => 'Content' );
+
   $m->form_name('ModifyTemplate');
   my $content;
 
-
   TODO: {
 
     local $TODO = "WWW::Mechanize doesn't strip newline following <textarea> tag like browsers do";

commit 5c4164bf364ae93ee1e15144d35dd540e94e99af
Author: Brad Embree <brad at bestpractical.com>
Date:   Tue Dec 19 20:53:10 2023 -0800

    Update Templates AdminSearchResultFormat
    
    Use the new Admin/Templates/ pages for the Templates
    AdminSearchResultFormat links to modify the template.

diff --git a/etc/RT_Config.pm.in b/etc/RT_Config.pm.in
index 6433198a36..026b065c40 100644
--- a/etc/RT_Config.pm.in
+++ b/etc/RT_Config.pm.in
@@ -3992,8 +3992,8 @@ Set(%AdminSearchResultFormat,
         .q{,__Condition__, __Action__, __Template__, __Disabled__,__HasLogs__},
 
     Templates =>
-        q{'<a href="__WebPath__/__WebRequestPathDir__/Template.html?Queue=__QueueId__&Template=__id__">__id__</a>/TITLE:#'}
-        .q{,'<a href="__WebPath__/__WebRequestPathDir__/Template.html?Queue=__QueueId__&Template=__id__">__Name__</a>/TITLE:Name'}
+        q{'<a href="__WebPath__/Admin/Templates/Basics.html?Queue=__QueueId__&Template=__id__">__id__</a>/TITLE:#'}
+        .q{,'<a href="__WebPath__/Admin/Templates/Basics.html?Queue=__QueueId__&Template=__id__">__Name__</a>/TITLE:Name'}
         .q{,'__Description__','__UsedBy__','__IsEmpty__'},
     Classes =>
         q{ '<a href="__WebPath__/Admin/Articles/Classes/Modify.html?id=__id__">__id__</a>/TITLE:#'}

commit 742772401b36d3d5da9edb401adb1330f183255f
Author: Brad Embree <brad at bestpractical.com>
Date:   Sun Dec 17 16:22:26 2023 -0800

    Update menus to use Admin/Templates/ pages
    
    Replace the current menu links to different pages for Global vs Queue
    templates with links to a common page under Admin/Templates

diff --git a/lib/RT/Interface/Web/MenuBuilder.pm b/lib/RT/Interface/Web/MenuBuilder.pm
index 82f67b0018..0fd632e523 100644
--- a/lib/RT/Interface/Web/MenuBuilder.pm
+++ b/lib/RT/Interface/Web/MenuBuilder.pm
@@ -1204,10 +1204,10 @@ sub _BuildAdminMenu {
     my $templates = $admin_global->child( templates =>
         title       => loc('Templates'),
         description => loc('Edit system templates'),
-        path        => '/Admin/Global/Templates.html',
+        path        => '/Admin/Templates/',
     );
-    $templates->child( select => title => loc('Select'), path => "/Admin/Global/Templates.html" );
-    $templates->child( create => title => loc('Create'), path => "/Admin/Global/Template.html?Create=1" );
+    $templates->child( select => title => loc('Select'), path => "/Admin/Templates/" );
+    $templates->child( create => title => loc('Create'), path => "/Admin/Templates/Create.html" );
 
     my $cfadmin = $admin_global->child( 'custom-fields' =>
         title       => loc('Custom Fields'),
@@ -1427,8 +1427,8 @@ sub _BuildAdminMenu {
                 $queue->child( people => title => loc('Watchers'), path => "/Admin/Queues/People.html?id=" . $id );
 
                 my $templates = $queue->child(templates => title => loc('Templates'), path => "/Admin/Queues/Templates.html?id=" . $id);
-                $templates->child( select => title => loc('Select'), path => "/Admin/Queues/Templates.html?id=".$id);
-                $templates->child( create => title => loc('Create'), path => "/Admin/Queues/Template.html?Create=1;Queue=".$id);
+                $templates->child( select => title => loc('Select'), path => "/Admin/Queues/Templates.html?id=" . $id);
+                $templates->child( create => title => loc('Create'), path => "/Admin/Templates/Create.html?Queue=".$id);
 
                 my $scrips = $queue->child( scrips => title => loc('Scrips'), path => "/Admin/Queues/Scrips.html?id=" . $id);
                 $scrips->child( select => title => loc('Select'), path => "/Admin/Queues/Scrips.html?id=" . $id );
@@ -1654,9 +1654,22 @@ sub _BuildAdminMenu {
         $page->child( create => title => loc('Create'), path => "/Admin/Actions/Create.html" );
     }
 
-    if ( $request_path =~ m{^/Admin/Global/Templates?\.html} ) {
-        $page->child( select => title => loc('Select'), path => "/Admin/Global/Templates.html" );
-        $page->child( create => title => loc('Create'), path => "/Admin/Global/Template.html?Create=1" );
+    if ( $request_path =~ m{^/Admin/Templates/} ) {
+        if ( $HTML::Mason::Commands::m->request_args->{'Template'} && $HTML::Mason::Commands::m->request_args->{'Template'} =~ /^\d+$/ ) {
+            my $id = $HTML::Mason::Commands::m->request_args->{'Template'};
+            my $queue = $HTML::Mason::Commands::m->request_args->{'Queue'} || 0;
+            my $templates = $page->child( select => title => loc('Templates'),
+                                          path => "/Admin/Templates/" );
+            $templates->child( select => title => loc('Select'), path => "/Admin/Templates/" );
+            $templates->child( create => title => loc('Create'), path => "/Admin/Templates/Create.html" );
+            $page->child( basics => title => loc('Basics'), path => "/Admin/Templates/Basics.html?Queue=$queue&Template=$id" );
+            $page->child( content => title => loc('Content'), path => "/Admin/Templates/Content.html?Queue=$queue&Template=$id" );
+            $page->child( advanced => title => loc('Advanced'), path => "/Admin/Templates/Advanced.html?Queue=$queue&Template=$id" );
+        }
+        else {
+            $page->child( select => title => loc('Select'), path => "/Admin/Templates/" );
+            $page->child( create => title => loc('Create'), path => "/Admin/Templates/Create.html" );
+        }
     }
 
     if ( $request_path =~ m{^/Admin/Articles/Classes/} ) {

commit dc24212a4e4576a08e2effa939cad80aad3c7299
Author: Brad Embree <brad at bestpractical.com>
Date:   Wed Dec 20 14:34:15 2023 -0800

    Add Admin/Templates/Advanced.html

diff --git a/share/html/Admin/Templates/Advanced.html b/share/html/Admin/Templates/Advanced.html
new file mode 100644
index 0000000000..8d0a289921
--- /dev/null
+++ b/share/html/Admin/Templates/Advanced.html
@@ -0,0 +1,48 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<& /Admin/Elements/ModifyTemplatePage, %ARGS, Page => 'Advanced' &>
\ No newline at end of file

commit 8b662c5260dea142ecf094ce72ef6b627dd3b283
Author: Brad Embree <brad at bestpractical.com>
Date:   Wed Dec 20 14:33:58 2023 -0800

    Add Admin/Templates/Content.html

diff --git a/share/html/Admin/Templates/Content.html b/share/html/Admin/Templates/Content.html
new file mode 100644
index 0000000000..7d5e202d59
--- /dev/null
+++ b/share/html/Admin/Templates/Content.html
@@ -0,0 +1,48 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<& /Admin/Elements/ModifyTemplatePage, %ARGS, Page => 'Content' &>
\ No newline at end of file

commit d699f86b80e68851917c22cb2201fc65dbe3cbe1
Author: Brad Embree <brad at bestpractical.com>
Date:   Wed Dec 20 14:33:40 2023 -0800

    Add Admin/Templates/Basics.html

diff --git a/share/html/Admin/Templates/Basics.html b/share/html/Admin/Templates/Basics.html
new file mode 100644
index 0000000000..ec3b521c08
--- /dev/null
+++ b/share/html/Admin/Templates/Basics.html
@@ -0,0 +1,48 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<& /Admin/Elements/ModifyTemplatePage, %ARGS &>
\ No newline at end of file

commit bfa072035559c32a301c58a29a2741b3a4f3ac1c
Author: Brad Embree <brad at bestpractical.com>
Date:   Tue Dec 19 20:50:04 2023 -0800

    Add Admin/Templates/Create.html

diff --git a/share/html/Admin/Templates/Create.html b/share/html/Admin/Templates/Create.html
new file mode 100644
index 0000000000..edb84be408
--- /dev/null
+++ b/share/html/Admin/Templates/Create.html
@@ -0,0 +1,109 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<& /Admin/Elements/Header, Title => $title &>
+<& /Elements/Tabs &>
+<& /Elements/ListActions, actions => \@results &>
+
+<form method="post" name="ModifyTemplate" id="ModifyTemplate" action="Create.html" class="mx-auto max-width-lg">
+<input type="hidden" class="hidden" name="Template" value="new" />
+
+%# hang onto the queue id and tab setting
+<input type="hidden" class="hidden" name="Queue" value="<%$Queue%>" />
+<& /Admin/Elements/ModifyTemplate,
+    ARGSRef     => \%ARGS,
+    TemplateObj => $TemplateObj,
+    QueueObj    => $QueueObj,
+&>
+  <div class="form-row">
+    <div class="col-12">
+      <& /Elements/Submit, Label => $SubmitLabel, Reset => 1 &>
+    </div>
+  </div>
+</form>
+<%INIT>
+my $TemplateObj = RT::Template->new( $session{'CurrentUser'} );
+my ( $title, @results, $SubmitLabel, $QueueObj );
+
+if ( defined($Template) && $Template eq 'new' ) {
+    my ( $val, $msg ) =  $TemplateObj->Create( Queue => $Queue, Name => $Name, Type => $Type );
+    push @results, $msg;
+}
+
+if ( $TemplateObj->Id() ) {
+    $QueueObj = $TemplateObj->QueueObj
+        if $Queue;
+
+    push @results, ProcessTemplateUpdate( TemplateObj => $TemplateObj, ARGSRef => \%ARGS );
+
+    # if this was a new template need to reload the page so the Basics, Content, and Advanced menu options show
+    if ( defined($Template) && $Template eq 'new' ) {
+      my $request_path = $HTML::Mason::Commands::r->path_info;
+      MaybeRedirectForResults(
+          Actions   => \@results,
+          Path      => '/Admin/Templates/Basics.html',
+          Arguments => { Queue => $Queue, Template => $TemplateObj->Id },
+      );
+    }
+}
+else {
+    if ( $Queue ) {
+        $QueueObj = RT::Queue->new( $session{'CurrentUser'} );
+        $QueueObj->Load($Queue)
+    }
+}
+
+$title = ( $QueueObj && $QueueObj->id ) ? loc( 'Create a new template for queue [_1]', $QueueObj->Name )
+                                        : loc("Create a template");
+$SubmitLabel = loc('Create');
+</%INIT>
+<%ARGS>
+$Queue => ''
+$Template => ''
+$Name => ''
+$Type => ''
+</%ARGS>
\ No newline at end of file

commit bf332dcec400e37dee58f86bd3d44bf5986283cd
Author: Brad Embree <brad at bestpractical.com>
Date:   Tue Dec 19 20:48:52 2023 -0800

    Add Admin/Templates/index.html

diff --git a/share/html/Admin/Templates/index.html b/share/html/Admin/Templates/index.html
new file mode 100644
index 0000000000..4f00b597da
--- /dev/null
+++ b/share/html/Admin/Templates/index.html
@@ -0,0 +1,57 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<& /Admin/Elements/Header, Title => $title, FeedURI => 'templates' &>
+<& /Elements/Tabs &>
+<& /Admin/Elements/EditTemplates, title => $title, %ARGS &>
+<%init>
+my $title = loc("Modify templates which apply to all queues");
+my (@actions);
+</%init>
+<%ARGS>
+$id => undef
+</%ARGS>

commit 55b55bcc6448fa6d6b438e4ed60913d45f59d3ce
Author: Brad Embree <brad at bestpractical.com>
Date:   Wed Dec 20 14:30:38 2023 -0800

    Split fields into Basics, Content, and Advanced
    
    Add logic to display different fields based on what view we are loading.

diff --git a/share/html/Admin/Elements/ModifyTemplate b/share/html/Admin/Elements/ModifyTemplate
index 53ddc794cc..29ce6bcc9c 100644
--- a/share/html/Admin/Elements/ModifyTemplate
+++ b/share/html/Admin/Elements/ModifyTemplate
@@ -46,63 +46,106 @@
 %#
 %# END BPS TAGGED BLOCK }}}
 <&| /Widgets/TitleBox, class => 'template-info-basics', content_class => 'mx-auto width-lg' &>
-<div class="form-row">
-  <div class="label col-2">
-    <&|/l&>Name</&>:
-  </div>
-  <div class="value col-6">
-    <input type="text" class="form-control" name="Name" value="<%$Name||''%>" size="80" />
-  </div>
-</div>
-
-<div class="form-row">
-  <div class="label col-2">
-    <&|/l&>Description</&>:
+% if ( $Page eq 'Basics' ) {
+  <div class="form-row">
+    <div class="label col-2">
+      <&|/l&>Name</&>:
+    </div>
+    <div class="value col-6">
+      <input type="text" class="form-control" name="Name" value="<%$Name||''%>" size="80" />
+    </div>
   </div>
-  <div class="value col-6">
-    <input type="text" class="form-control" name="Description" value="<%$Description||''%>" size="80" />
+  <div class="form-row">
+    <div class="label col-2">
+      <&|/l&>Description</&>:
+    </div>
+    <div class="value col-6">
+      <input type="text" class="form-control" name="Description" value="<%$Description||''%>" size="80" />
+    </div>
   </div>
-</div>
-
-<div class="form-row">
-  <div class="label col-2">
-    <&|/l&>Type</&>:
+  <div class="form-row">
+    <div class="label col-2">
+      <&|/l&>Type</&>:
+    </div>
+    <div class="value col-6">
+      <select class="selectpicker form-control" name="Type">
+        <option value="Perl" <% $Type eq 'Perl' ? 'selected="selected"' : '' |n%>>
+          <% loc('Perl') %>
+        </option>
+        <option value="Simple" <% $Type eq 'Simple' ? 'selected="selected"' : '' |n%>>
+          <% loc('Simple') %>
+        </option>
+        <option value="Create" <% $Type eq 'Create' ? 'selected="selected"' : '' |n%>>
+          <% loc('Create Ticket') %>
+        </option>
+      </select>
+    </div>
   </div>
-  <div class="value col-6">
-    <div class="custom-control custom-radio">
-      <input type="radio" name="Type" class="custom-control-input" id="Type-Perl" value="Perl" <% $Type eq "Perl" ? 'checked="checked"' : "" |n %>></input>
-      <label class="custom-control-label" for="Type-Perl"><&|/l&>Perl</&></label><br />
+  <div class="form-row">
+    <div class="label col-2">
+      <&|/l&>Applied to</&>:
     </div>
-    <div class="custom-control custom-radio">
-      <input type="radio" name="Type" class="custom-control-input" id="Type-Simple" value="Simple" <% $Type eq "Simple" ? 'checked="checked"' : "" |n %>>
-      <label class="custom-control-label" for="Type-Simple"><&|/l&>Simple</&></label><br />
+    <div class="label">
+% if ( $AppliedTo ) {
+      <span>
+        <a href="<% RT->Config->Get('WebPath') %>/Admin/Queues/Templates.html?id=<% $AppliedTo %>"><% $AppliedToName %></a>
+      </span>
+% }
+% else {
+      <span>
+        <&|/l&>Global</&>
+      </span>
+% }
     </div>
   </div>
-</div>
-
+% }
+% else {
+  <input type="hidden" class="hidden" name="Name" value="<% $Name || '' %>" />
+  <input type="hidden" class="hidden" name="Description" value="<% $Description || '' %>" />
+  <input type="hidden" class="hidden" name="Type" value="<% $Type || '' %>" />
+% }
 <div class="form-row">
+% if ( ( $Page eq 'Content' ) && ( $Type eq 'Create' ) ) {
+  <div class="col-12">
+    <& /Admin/Elements/ModifyCreateTemplate,
+      TemplateObj => $TemplateObj,
+      QueueObj    => $QueueObj,
+      &>
+ </div>
+% }
+% elsif ( ( $Page eq 'Content' ) || ( $Page eq 'Advanced' ) ) {
   <div class="label col-2">
     <&|/l&>Content</&>:
   </div>
   <div class="value col-8">
-    <textarea name="Content" class="form-control" rows="25" cols="80" wrap="soft">
-<%$Content||''%></textarea>
+    <textarea name="Content" class="form-control" rows="25" cols="80" wrap="soft"><% $Content || '' %></textarea>
   </div>
+% }
 </div>
 </&>
-
 <%INIT>
+my $Name        = $TemplateObj->Name // $ARGS{Name};
+my $Description = $TemplateObj->Description // $ARGS{Description};
+my $Content     = $TemplateObj->Content // $ARGS{Content};
+my $Type        = $TemplateObj->Type // $ARGS{Type};
 
 unless ($Type) {
     $Type = $session{'CurrentUser'}->HasRight(Right => 'ExecuteCode', Object => $RT::System) ?
         'Perl' : 'Simple';
 }
 
-</%INIT>
+my $AppliedTo;
+$AppliedTo = $QueueObj->id
+  if $QueueObj;
 
+if ( $AppliedTo ) {
+    $AppliedToName = $QueueObj->Name;
+}
+
+</%INIT>
 <%ARGS>
-$Name => ''
-$Description => ''
-$Content => ''
-$Type => ''
+$TemplateObj
+$QueueObj => undef
+$Page => 'Basics'
+$AppliedToName => ''
 </%ARGS>

commit 76c36e1fb3c3823bf53977f21219fc97513787fc
Author: Brad Embree <brad at bestpractical.com>
Date:   Wed Dec 20 14:28:06 2023 -0800

    Add ModifyTemplatePage Element
    
    Add a new element for the new template admin pages to reduce duplicated
    code.

diff --git a/share/html/Admin/Elements/ModifyTemplatePage b/share/html/Admin/Elements/ModifyTemplatePage
new file mode 100644
index 0000000000..d1ee719185
--- /dev/null
+++ b/share/html/Admin/Elements/ModifyTemplatePage
@@ -0,0 +1,89 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<& /Admin/Elements/Header, Title => $title &>
+<& /Elements/Tabs &>
+<& /Elements/ListActions, actions => \@results &>
+
+<form method="post" name="ModifyTemplate" id="ModifyTemplate" action="<% $Page %>.html" class="mx-auto max-width-lg">
+<input type="hidden" class="hidden" name="Template" value="<%$TemplateObj->Id%>" />
+%# hang onto the queue id and tab setting
+<input type="hidden" class="hidden" name="Queue" value="<%$Queue%>" />
+<& /Admin/Elements/ModifyTemplate,
+    ARGSRef     => \%ARGS,
+    QueueObj    => $QueueObj,
+    TemplateObj => $TemplateObj,
+    Page        => $Page,
+&>
+  <div class="form-row">
+    <div class="col-12">
+      <& /Elements/Submit, Label => $SubmitLabel, Reset => 1 &>
+    </div>
+  </div>
+</form>
+<%INIT>
+my $TemplateObj = RT::Template->new($session{'CurrentUser'});
+my ( $title, @results, $SubmitLabel, $QueueObj );
+
+$TemplateObj->Load($Template) || Abort( loc('No Template') );
+
+if ( $TemplateObj->Id() ) {
+    $QueueObj = $TemplateObj->QueueObj
+        if $Queue;
+
+    push @results, ProcessTemplateUpdate( TemplateObj => $TemplateObj, ARGSRef => \%ARGS );
+}
+
+$title = ( $QueueObj && $QueueObj->id ) ? loc( 'Modify template [_1] for queue [_2]', loc( $TemplateObj->Name() ), $QueueObj->Name )
+                                        : loc( 'Modify template [_1]', loc( $TemplateObj->Name() ) );
+$SubmitLabel = loc('Save Changes');
+</%INIT>
+<%ARGS>
+$Queue => ''
+$Template => ''
+$Page => 'Basics'
+</%ARGS>
\ No newline at end of file

commit 2ed75229a677529d65bee2bbc16da134e0a87e2f
Author: Brad Embree <brad at bestpractical.com>
Date:   Sun Dec 17 16:27:57 2023 -0800

    Add ModifyCreateTemplate Element
    
    Add a new element for modifying a create tickets template.

diff --git a/share/html/Admin/Elements/ModifyCreateTemplate b/share/html/Admin/Elements/ModifyCreateTemplate
new file mode 100644
index 0000000000..9aabed5578
--- /dev/null
+++ b/share/html/Admin/Elements/ModifyCreateTemplate
@@ -0,0 +1,346 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
+%#                                          <sales at 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 ( $Error ) {
+  <div class="row col-12">
+    <p><% $Error %></p>
+  </div>
+% }
+% else {
+<&| /Widgets/TitleBox, title => loc("Create Ticket Templates"), class => 'template-info-basics', content_class => 'mx-auto width-lg' &>
+  <div class="row col-12">
+    <p>
+      Each Create Ticket Section in the template has its own tab below.
+      Click on the tab to change field values for that section.
+    </p>
+    <p>
+      Click on the Add New Section tab to add a new Create Ticket Section to the template.
+      The Section Name field is required when adding a new Create Ticket Section to the template.
+    </p>
+    <p>
+      Each Section can start with a block of Perl Code that allows you to initialize and set variables or add some logic to determine if you should create the ticket or not.
+      The Skip Create field allows you to skip creating a ticket for that section programatically. See here for details: <a href="https://docs.bestpractical.com/rt/latest/RT/Action/CreateTickets.html#SkipCreate" target="_blank">Skip Create</a>
+    </p>
+    <p>
+      All fields accept a string value or you can enter Perl Code by wrapping it in brackets: { PERL CODE HERE }
+      <br />
+      Make sure you end the Perl code with a value to set a value for that field: { my $val = 'Value'; $val; }
+    </p>
+    <p>
+      See here for more documentation on the format of the Create Ticket Templates: <a href="https://docs.bestpractical.com/rt/latest/RT/Action/CreateTickets.html#Format" target="_blank">Create Tickets</a>
+    </p>
+  </div>
+</&>
+% if ( @sections ) {
+  <br/>
+  <ul class="nav nav-pills" role="tablist">
+% for my $section ( @sections ) {
+    <li class="nav-item" id="<% $section->{name} %>-nav">
+      <a class="nav-link <% $section->{active} ? 'active' : ''  %>" href="#<% $section->{name} %>-content" id="<% "category-tab-" . $section->{name} %>" data-toggle="tab" role="tab" aria-controls="<% $section->{name} %>" aria-selected="false">
+        <% $section->{name} eq 'ADD-NEW-SECTION' ? 'Add New Section' : $section->{name}  %>
+      </a>
+    </li>
+% }
+  </ul>
+  <div class="tab-content">
+% for my $section ( @sections ) {
+    <div id="<% $section->{name} %>-content" class="tab-pane fade <% $section->{active} ? 'show active' : ''  %>" role="tabpanel" aria-labelledby="<% "category-tab-" . $section->{name} %>">
+<&| /Widgets/TitleBox, title => loc("Perl Code"), class=>'ticket-info-basics' &>
+%   if ( $section->{name} eq 'ADD-NEW-SECTION' ) {
+      <&| /Elements/LabeledValue, Label => loc('Section Name'), Class => 'edit-custom-field' &>
+      <div class="form-row">
+        <div class="col-12">
+          <input name="AddNewSectionName" type="text" value="" placeholder="Section Name is Required" <% scalar(@sections) > 1 ? '' : 'required' %> class="form-control" />
+        </div>
+      </div>
+      </&>
+% }
+% else {
+    <input type="hidden" name="CreateSectionName" value="<% $section->{name} %>">
+      <&| /Elements/LabeledValue, Label => loc('Section Name'), Class => 'edit-custom-field' &>
+      <div class="form-row">
+        <div class="col-12">
+          <input name="<% $section->{name} %>-NewSectionName" type="text" value="<% $section->{name} %>" placeholder="Section Name is Required" required class="form-control" />
+        </div>
+      </div>
+      <div class="form-row">
+        <div class="col-12">
+          <p id="<% $section->{name} %>-NewSectionName-error"></p>
+        </div>
+      </div>
+      </&>
+% }
+
+      <&| /Elements/LabeledValue, Label => loc('Perl Code'), Class => 'edit-custom-field' &>
+      <div class="form-row">
+        <div class="col-12">
+% my $perlcode = $section->{perlcode} || '';
+% $perlcode =~ s/^\s?{//;
+% $perlcode =~ s/}\s?$//;
+          <textarea class="form-control" name="<% $section->{name} %>-PerlCode" cols="50" rows="3"><% $perlcode %></textarea>
+        </div>
+      </div>
+      </&>
+
+      <&| /Elements/LabeledValue, Label => loc('Skip Create'), Class => 'edit-custom-field' &>
+      <div class="form-row">
+        <div class="col-12">
+          <input name="<% $section->{name} %>-SkipCreate" type="text" value="<% $section->{skipcreate} || '' %>" class="form-control" />
+        </div>
+      </div>
+      </&>
+</&>
+
+<&| /Widgets/TitleBox, title => loc("Content"), class=>'ticket-info-basics' &>
+% foreach my $field ( qw( UpdateType ContentType Content ) ) {
+  <& /Elements/CreateTemplate/FieldInput,
+    Section => $section->{name},
+    Field   => $field,
+    Value   => $section->{ lc $field } || '',
+  &>
+% }
+</&>
+
+<div class="form-row">
+<div class="boxcontainer col-md-6">
+<&| /Widgets/TitleBox, title => loc("The Basics"), class=>'ticket-info-basics' &>
+% foreach my $field ( qw( Type Subject Status Queue SLA TimeEstimated TimeWorked TimeLeft InitialPriority FinalPriority ) ) {
+  <& /Elements/CreateTemplate/FieldInput,
+    Section => $section->{name},
+    Field   => $field,
+    Value   => $section->{ lc $field } || '',
+  &>
+% }
+</&>
+
+<&| /Widgets/TitleBox, title => loc("People"), class=>'ticket-info-people' &>
+% foreach my $field ( qw( Owner Requestor Cc AdminCc RequestorGroup CcGroup AdminCcGroup ) ) {
+  <& /Elements/CreateTemplate/FieldInput,
+    Section => $section->{name},
+    Field   => $field,
+    Value   => $section->{ lc $field } || '',
+  &>
+% }
+</&>
+</div>
+<div class="boxcontainer col-md-6">
+<&| /Widgets/TitleBox, title => loc("Dates"), class=>'ticket-info-dates' &>
+% foreach my $field ( qw( Starts Started Due Resolved ) ) {
+  <& /Elements/CreateTemplate/FieldInput,
+    Section => $section->{name},
+    Field   => $field,
+    Value   => $section->{ lc $field } || '',
+  &>
+% }
+</&>
+
+<&| /Widgets/TitleBox, title => loc("Links"), class=>'ticket-info-links' &>
+% foreach my $field ( qw( DependsOn DependedOnBy RefersTo ReferredToBy Members MemberOf ) ) {
+  <& /Elements/CreateTemplate/FieldInput,
+    Section => $section->{name},
+    Field   => $field,
+    Value   => $section->{ lc $field } || '',
+  &>
+% }
+</&>
+
+<&| /Widgets/TitleBox, title => loc("Custom Fields"), class=>'ticket-info-cfs' &>
+      <&| /Elements/LabeledValue, Label => loc('Custom Fields'), Class => 'edit-custom-field' &>
+<div id="CustomFields-<% $section->{name} %>">
+%   foreach my $cf ( @{ $section->{CustomFields} || [] } ) {
+%     my ( $cf_id, $value ) = @$cf;
+      <div class="form-row" id="<% $section->{name} %>-CustomField-<% $cf_id || '' %>">
+        <div class="col-5">
+          <select name="<% $section->{name} %>-CustomField-id" class="form-control selectpicker">
+%       my $cfs = RT::CustomFields->new( $session{'CurrentUser'});
+%       $cfs->LimitToGlobal;
+%       $cfs->OrderBy( FIELD => 'Name', ORDER => 'ASC' );
+            <option value=""></option>
+%       while ( my $cf = $cfs->Next ) {
+            <option value="<% $cf->id %>" <% $cf_id eq $cf->id ? 'selected' : '' %>><% $cf->Name  %></option>
+% }
+          </select>
+        </div>
+        <div class="col-5">
+          <input name="<% $section->{name} %>-CustomField-val" type="text" value="<% $value || '' %>" class="form-control" />
+        </div>
+        <div class="col-2">
+          <input type="submit" class="button btn btn-primary" name="<% $section->{name} %>-RemoveCustomField-<% $cf_id %>" value=" - " onclick="RemoveCustomField('<% $section->{name} %>-CustomField-<% $cf_id || '' %>'); return false;">
+        </div>
+      </div>
+%   }
+      </&>
+</div>
+      <div class="form-row">
+        <div class="col-12 text-right">
+          <input type="submit" class="button btn btn-primary form-control" name="<% $section->{name} %>-AddCustomField" value="<% loc("Add Custom Field") %>" onclick="AddCustomField('<% $section->{name} %>'); return false;">
+        </div>
+      </div>
+</&>
+</div>
+</div>
+%   unless ( $section->{name} eq 'ADD-NEW-SECTION' ) {
+      <div class="text-right">
+        <button class="btn btn-danger" id="<% $section->{name} %>-button" type="button" onclick="RemoveSection('<% $section->{name} %>'); return false;">Delete Section</button>
+      </div>
+%   }
+    </div>
+% }
+  </div>
+% }
+
+<script type="text/javascript">
+jQuery(document).ready( function() {
+    jQuery('#ModifyTemplate input[required]').blur( function() {
+        var $id           = "#" + jQuery(this).attr("name") + "-error";
+        var $tab_name     = jQuery(this).attr("name").replace( "-NewSectionName", "" );
+        var $caption_text = jQuery("div.buttons span.caption").text();
+        if ( ! jQuery(this).val() ) {
+            jQuery($id).text("Section Name is required!");
+            jQuery($id).addClass("text-danger");
+
+            if ( $caption_text.length > 0 ) {
+                if ( ! $caption_text.includes( " '" + $tab_name + "'" ) ) {
+                    $caption_text = $caption_text + " '" + $tab_name + "'";
+                }
+            }
+            else {
+                $caption_text = "Section Name is required! Please fill in Section Name on tabs: '" + $tab_name + "'";
+            }
+            jQuery("div.buttons span.caption").text($caption_text);
+            jQuery("div.buttons span.caption").addClass("text-danger");
+        }
+        else {
+            jQuery($id).text("");
+            jQuery($id).removeClass("text-danger");
+
+            if ( $caption_text.length > 0 ) {
+                $caption_text = $caption_text.replace( " '" + $tab_name + "'", "" );
+                if ( $caption_text == "Section Name is required! Please fill in Section Name on tabs:" ) {
+                    $caption_text = "";
+                }
+            }
+            jQuery("div.buttons span.caption").text($caption_text);
+            if ( $caption_text.length == 0 ) {
+                jQuery("div.buttons span.caption").removeClass("text-danger");
+            }
+        }
+
+    });
+});
+
+  function RemoveSection ($name) {
+    jQuery( "#" + $name + "-nav" ).remove();
+    jQuery( "#" + $name + "-button" ).remove();
+    jQuery( "#" + $name + "-content" ).remove();
+    // trigger a click on the first remaining tab link
+    jQuery(".nav-link").first().trigger('click');
+  };
+
+  function RemoveCustomField ($div_id) {
+    jQuery( "#" + $div_id ).remove();
+  };
+
+  var $new_cf_count = 1;
+
+  function AddCustomField ($ticket_name) {
+    var $html = ' \
+      <div class="form-row" id="' + $ticket_name + '-CustomField-new-' + $new_cf_count.toString() + '"> \
+        <div class="col-5"> \
+          <select name="' + $ticket_name + '-CustomField-id" class="form-control selectpicker"> \
+% my $cfs = RT::CustomFields->new( $session{'CurrentUser'});
+% $cfs->LimitToGlobal;
+% if ( $QueueObj && $QueueObj->id ) {
+%     $cfs->LimitToQueue( $QueueObj->id );
+% }
+% $cfs->OrderBy( FIELD => 'Name', ORDER => 'ASC' );
+            <option value=""></option> \
+% while ( my $cf = $cfs->Next ) {
+            <option value="<% $cf->id %>"><% $cf->Name  %></option> \
+% }
+          </select> \
+        </div> \
+        <div class="col-5"> \
+          <input name="' + $ticket_name + '-CustomField-val" type="text" value="" class="form-control" /> \
+        </div> \
+        <div class="col-2"> \
+          <input type="submit" class="button btn btn-primary" name="' + $ticket_name + '-RemoveCustomField-' + $ticket_name + '" value=" - " onclick="RemoveCustomField(\'' + $ticket_name + '-CustomField-new-' + $new_cf_count.toString() + '\'); return false;"> \
+        </div> \
+      </div>';
+      $new_cf_count++;
+    jQuery( "#CustomFields-" + $ticket_name ).append($html);
+    jQuery('.selectpicker').selectpicker();
+  };
+</script>
+% }
+<%INIT>
+my ( @sections, $Template, $Error );
+if ( $TemplateObj && $TemplateObj->Id ) {
+    $Template = $TemplateObj->Name;
+
+    my ( $sections, $error ) = $TemplateObj->ParseContentAsCreateTicket;
+    if ( $sections ) {
+        @sections = @$sections;
+    }
+    else {
+        RT->Logger->error( "Unable to parse '$Template': $error" );
+        if ( $error =~ /too advanced/ ) {
+            $Error = "Unable to parse '$Template': This template has multiple Perl Code blocks and cannot be parsed. Please use the Advanced tab.";
+        }
+        else {
+            $Error = "Unable to parse '$Template': $error";
+        }
+    }
+
+    # add a blank section for new templates or for adding a new ticket section
+    push @sections, { name => 'ADD-NEW-SECTION', active => ( @sections ? 0 : 1 ) };
+}
+</%INIT>
+<%ARGS>
+$TemplateObj
+$QueueObj => undef
+</%ARGS>
\ No newline at end of file

commit 067118e1ff2896de9ac532978a2691faab4aebaa
Author: Brad Embree <brad at bestpractical.com>
Date:   Tue Dec 19 10:06:11 2023 -0800

    Add Elements/CreateTemplate/FieldInput

diff --git a/share/html/Elements/CreateTemplate/FieldInput b/share/html/Elements/CreateTemplate/FieldInput
new file mode 100644
index 0000000000..46577f5ba2
--- /dev/null
+++ b/share/html/Elements/CreateTemplate/FieldInput
@@ -0,0 +1,73 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2023 Best Practical Solutions, LLC
+%#                                          <sales at 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 }}}
+<&| /Elements/LabeledValue, Label => $Label, Class => 'edit-custom-field' &>
+  <div class="form-row">
+    <div class="col-12">
+      <input name="<% $Section %>-<% $Field %>" type="text" value="<% $Value %>" class="form-control" />
+    </div>
+  </div>
+</&>
+<%INIT>
+my %LabelForField = (
+    Members  => 'Members (Children)',
+    MemberOf => 'Member Of (Parents)',
+);
+
+my $Label = $LabelForField{$Field};
+if ( ! $Label ) {
+    $Label = $Field;
+    # split CamelCase to Camel Case
+    $Label =~ s/([A-Z][a-z]+)(?=[A-Z])/$1 /g;
+}
+$Label = loc($Label);
+</%INIT>
+<%ARGS>
+$Section
+$Field
+$Value
+</%ARGS>
\ No newline at end of file

commit ebcb0e64d89224615ef3255d166805f04cddb87d
Author: Brad Embree <brad at bestpractical.com>
Date:   Wed Dec 20 13:42:48 2023 -0800

    Add ParseContentAsCreateTicket method

diff --git a/lib/RT/Template.pm b/lib/RT/Template.pm
index 87ea9940a8..2d079604fd 100644
--- a/lib/RT/Template.pm
+++ b/lib/RT/Template.pm
@@ -1113,6 +1113,108 @@ sub PreInflate {
     return 1;
 }
 
+=head2 my ( $parsed, $error ) = ParseContentAsCreateTicket;
+
+Attempts to parse the value of the Content as a Create Ticket template.
+
+If successful it returns a list of an arrayref and an empty error
+message. The arrayref contains a hashref for each section in the
+template.
+
+If it cannot parse the Content it returns a list of undef and an error
+message.
+
+=cut
+
+sub ParseContentAsCreateTicket {
+    my $self = shift;
+
+    my $content = $self->Content || '';
+
+    # allow blank content for new templates
+    unless ( length($content) > 0 ) {
+        return ( [], '' );
+    }
+    unless ( $self->Type eq 'Create' ) {
+        return ( undef, 'Template is not Type Create Ticket' );
+    }
+    unless ( substr( $content, 0, 3 ) eq '===' ) {
+        return ( undef, 'Template content is not valid Create Ticket format' );
+    }
+
+    my @parsed = ();
+    my ( $current_ticket, %current_section );
+    my @lines = split /\n/, $content;
+    while ( my $line = shift @lines ) {
+        if ( $line =~ /^===(.*)-Ticket: (.*)$/ ) {
+            # TODO: do we need to do anything different for different ticket action?
+            #       Create vs Update vs Base
+            my $ticket_action = $1;
+            my $ticket_name   = $2;
+
+            if ( ! $current_ticket ) {
+                # first ticket template
+                $current_ticket          = $ticket_name;
+                $current_section{name}   = $ticket_name;
+                $current_section{action} = $ticket_action;
+                $current_section{active} = 1;
+            }
+            elsif ( $ticket_name ne $current_ticket ) {
+                # new ticket template
+                push @parsed, { %current_section };
+                %current_section         = ();
+                $current_ticket          = $ticket_name;
+                $current_section{name}   = $ticket_name;
+                $current_section{action} = $ticket_action;
+            }
+        }
+        elsif ( $line =~ /^===#.*$/ ) {    # a comment
+            next;
+        }
+        elsif ( $line =~ /^(.*?):(?:\s+)(.*?)(?:\s*)$/ ) {
+            my $field = $1;
+            my $val   = $2;
+
+            # fields can have dashes and mixed case so normalize to no dash and lowercase
+            $field =~ s/-//g;
+            $field = lc $field;
+
+            if ( $field eq 'content' ) {
+                while ( defined( my $l = shift @lines ) ) {
+                    last if ( $l =~ /^ENDOFCONTENT\s*$/ );
+                    $val .= "\n" . $l;
+                }
+                $current_section{$field} = $val;
+            }
+            elsif ( $field =~ /(CustomField|CF)(.*)/i ) {
+                $current_section{CustomFields} = []
+                    unless $current_section{CustomFields};
+                push @{ $current_section{CustomFields} }, [ $2, $val ];
+            }
+            else {
+                $current_section{$field} = $val;
+            }
+        }
+        else {
+            # if there is a line of perl code after the initial perl code block we cannot parse it correctly
+            # in that case we need to return an error that the template is "too advanced" for the GUI and
+            # they can edit it on the Advanced tab
+            $line =~ s/^\s+//g;
+            if ( exists( $current_section{perlcode} ) && ( $line =~ /^{/ ) ) {
+                # we have a line opening a perl code block but we already have our perlcode block
+                return ( undef, 'Template content is too advanced to parse correctly' );
+            }
+            else {
+                $current_section{perlcode} .= "$line\n";
+            }
+        }
+    }
+    # push the last template on to array
+    push @parsed, { %current_section };
+
+    return ( \@parsed, '' );
+}
+
 RT::Base->_ImportOverlays();
 
 1;

commit 242f2b7baccbc7463f366d1b2f0ee0811a030cd1
Author: Brad Embree <brad at bestpractical.com>
Date:   Sun Dec 17 16:19:38 2023 -0800

    Add ProcessTemplateUpdate function
    
    Added a new function to process updates to a template object so
    different template pages can share the same code.

diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index 7838f3e0a5..0cab1cede8 100644
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -3171,8 +3171,6 @@ sub ProcessCustomFieldUpdates {
     return (@results);
 }
 
-
-
 =head2 ProcessTicketBasics ( TicketObj => $Ticket, ARGSRef => \%ARGS );
 
 Returns an array of results messages.
@@ -5321,6 +5319,139 @@ sub ProcessAuthToken {
     return @results;
 }
 
+=head2 ProcessTemplateUpdate ( TemplateObj => $Template, ARGSRef => \%ARGS );
+
+Accepts a Template Object and a ref to %ARGS and processes any updates
+to the Template Object in %ARGS.
+
+Returns an array of results messages.
+
+=cut
+
+sub ProcessTemplateUpdate {
+    my %args = (
+        TemplateObj => undef,
+        ARGSRef     => undef,
+        @_
+    );
+
+    my @results;
+    my @FIELDS = qw(
+        PerlCode
+        Queue
+        Subject
+        Status
+        SLA
+        Due
+        Starts
+        Started
+        Resolved
+        Owner
+        Requestor
+        Cc
+        AdminCc
+        RequestorGroup
+        CcGroup
+        AdminCcGroup
+        TimeWorked
+        TimeEstimated
+        TimeLeft
+        InitialPriority
+        FinalPriority
+        Type
+        DependsOn
+        DependedOnBy
+        RefersTo
+        ReferredToBy
+        Members
+        MemberOf
+        CustomFields
+        Content
+        ContentType
+        UpdateType
+        SkipCreate
+    );
+
+    # ensure $args{ARGSRef}{CreateSectionName} is an array ref
+    # could be undefined (new template), scalar (single section), or an array ref (multiple sections)
+    if ( $args{ARGSRef}{CreateSectionName} ) {
+        $args{ARGSRef}{CreateSectionName} = [ $args{ARGSRef}{CreateSectionName} ]
+            unless ref $args{ARGSRef}{CreateSectionName};
+    }
+    else {
+        $args{ARGSRef}{CreateSectionName} = [];
+    }
+
+    # check if the user submitted a new section without filling in section name
+    # if so then set a section name, making sure to set it to a unique value
+    unless ( $args{ARGSRef}{AddNewSectionName} ) {
+        for my $field ( @FIELDS ) {
+            if ( defined( $args{ARGSRef}{"ADD-NEW-SECTION-$field"} ) && ( $args{ARGSRef}{"ADD-NEW-SECTION-$field"} ne '' ) ) {
+                my $new_section_name = 'new-section';
+                my $counter = 1;
+                while ( grep { $_ eq $new_section_name } @{ $args{ARGSRef}{CreateSectionName} } ) {
+                    $new_section_name = 'new-section-' . $counter++;
+                }
+                $args{ARGSRef}{AddNewSectionName} = $new_section_name;
+                push @results, "Section Name was not filled in for the new Section. Set Section Name to '$new_section_name'";
+                last;
+            }
+        }
+    }
+
+    push @{ $args{ARGSRef}{CreateSectionName} }, 'ADD-NEW-SECTION'
+        if $args{ARGSRef}{AddNewSectionName};
+
+    if ( @{ $args{ARGSRef}{CreateSectionName} } ) {
+        my $new_content = '';
+        for my $name ( @{ $args{ARGSRef}{CreateSectionName} } ) {
+            my $section_name = $name eq 'ADD-NEW-SECTION' ? $args{ARGSRef}{AddNewSectionName} : $name;
+            if ( my $new_name = $args{ARGSRef}{"$name-NewSectionName"} ) {
+                $section_name = $new_name;
+            }
+            $new_content .= "===Create-Ticket: $section_name\n";
+            for my $field ( @FIELDS ) {
+                if ( $field eq "CustomFields" ) {
+                    while ( my $cf_id = shift @{ $args{ARGSRef}{ $name . "-CustomField-id" } || [] } ) {
+                        my $cf_val = shift @{ $args{ARGSRef}{ $name . "-CustomField-val" } || [] };
+                            $new_content .= "CustomField-$cf_id: $cf_val\n";
+                    }
+                }
+                else {
+                    if ( my $val = $args{ARGSRef}{"$name-$field"} ) {
+                        if ( $field eq 'PerlCode' ) {
+                            # trim leading and trailing whitespace
+                            $val =~ s/^\s+//;
+                            $val =~ s/\s+$//;
+                            $new_content .= "{\n$val\n}\n";
+                        }
+                        elsif ( $field eq 'Content' ) {
+                            $new_content .= "Content: $val\nENDOFCONTENT\n"
+                        }
+                        else {
+                            $new_content .= "$field: $val\n";
+                        }
+                    }
+                }
+            }
+        }
+        $args{ARGSRef}{Content} = $new_content;
+    }
+
+    my @attribs = qw( Name Description Queue Type Content );
+    my @aresults = UpdateRecordObject(
+        AttributesRef => \@attribs,
+        Object        => $args{TemplateObj},
+        ARGSRef       => $args{ARGSRef}
+    );
+    push @results, @aresults;
+
+    my ( $ok, $msg ) = $args{TemplateObj}->CompileCheck;
+    push @results, $msg if !$ok;
+
+    return ( @results );
+}
+
 =head3 CachedCustomFieldValues FIELD
 
 Similar to FIELD->Values, but caches the return value of FIELD->Values

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


hooks/post-receive
-- 
rt


More information about the rt-commit mailing list