[Rt-commit] rt branch, 4.6/configindatabase-themed, repushed

? sunnavy sunnavy at bestpractical.com
Tue Nov 19 17:57:22 EST 2019


The branch 4.6/configindatabase-themed was deleted and repushed:
       was 9e63e304aab2ea7ac084ab6a6caa766771a69aee
       now 165ca1445fd4beb962b334471ac8dc34c91cde4b

 1: c9a5e3f654 =  1: b28dc30467 Allow specifying size for Integer and String widgets
 2: e48aa8f6cc =  2: 94744da2c6 Allow String widget to have a value of "0"
 3: 12f9dcbca0 =  3: 59334314c9 Add RadioStyle option to Boolean widget
 4: f2cd149e74 =  4: 534bba3102 Make booleans with RadioStyle use true/false logic
 5: 46185f9e0a !  5: baf23200cd DatabaseSetting schema updates
    @@ -112,7 +112,7 @@
     +) ENGINE=InnoDB DEFAULT CHARSET=utf8;
     +
     +CREATE UNIQUE INDEX DatabaseSettings1 ON DatabaseSettings (Name);
    -+CREATE UNIQUE INDEX DatabaseSettings2 ON DatabaseSettings (Disabled);
    ++CREATE INDEX DatabaseSettings2 ON DatabaseSettings (Disabled);
     +
     
     diff --git a/etc/upgrade/4.5.0/acl.Pg b/etc/upgrade/4.5.0/acl.Pg
    @@ -234,5 +234,5 @@
     +) ENGINE=InnoDB DEFAULT CHARSET=utf8;
     +
     +CREATE UNIQUE INDEX DatabaseSettings1 ON DatabaseSettings (Name);
    -+CREATE UNIQUE INDEX DatabaseSettings2 ON DatabaseSettings (Disabled);
    -
    ++CREATE INDEX DatabaseSettings2 ON DatabaseSettings (Disabled);
    +
 6: 44d5d96568 !  6: a888aa6cb0 Add ORM classes for DatabaseSettings
    @@ -155,7 +155,7 @@
     +
     +    if (!ref($content) && !ref($old_value)) {
     +        RT->Logger->info($self->CurrentUser->Name . " changed " . $self->Name . " from " . $old_value . " to " . $content);
    -+        return ($id, $self->loc("[_1] changed from [_2] to [_3]", $self->Name, $old_value, $content));
    ++        return ($id, $self->loc('[_1] changed from "[_2]" to "[_3]"', $self->Name, $old_value, $content));
     +    }
     +    else {
     +        RT->Logger->info($self->CurrentUser->Name . " changed " . $self->Name);
    @@ -319,7 +319,7 @@
     +
     +    if (!ref($value) && !ref($old_value)) {
     +        RT->Logger->info($self->CurrentUser->Name . " changed " . $self->Name . " from " . $old_value . " to " . $value);
    -+        return ($ok, $self->loc("[_1] changed from [_2] to [_3]", $self->Name, $old_value, $value));
    ++        return ($ok, $self->loc('[_1] changed from "[_2]" to "[_3]"', $self->Name, $old_value, $value));
     +    } else {
     +        RT->Logger->info($self->CurrentUser->Name . " changed " . $self->Name);
     +        return ($ok, $self->loc("[_1] changed", $self->Name));
 7: 04e7c94870 !  7: 05db0b9b37 Port database config loading and refreshing from extension
    @@ -108,7 +108,7 @@
     +        if ($meta->{'Source'}) {
     +            my %source = %{ $meta->{'Source'} };
     +            if ($source{'SiteConfig'} && $source{'File'} ne 'database') {
    -+                RT->Logger->warning("Change of config option '$name' at $source{File} line $source{Line} has been overridden by the config setting from the database. Please remove it from $source{File} or from the database to avoid confusion.");
    ++                warn("Change of config option '$name' at $source{File} line $source{Line} has been overridden by the config setting from the database. Please remove it from $source{File} or from the database to avoid confusion.");
     +            }
     +        }
     +
 8: 55a4dac8c0 =  8: 7648dd10f1 Add Code and MultilineString widgets
 9: d967bbbc93 !  9: 21f6abfb8c Port EditConfig page from extension
    @@ -294,3 +294,31 @@
     +</form>
     +
     
    +diff --git a/share/static/css/elevator-light/forms.css b/share/static/css/elevator-light/forms.css
    +--- a/share/static/css/elevator-light/forms.css
    ++++ b/share/static/css/elevator-light/forms.css
    +@@
    + ul li .dropdown-item:active span {
    +   color: #fff;
    + }
    ++
    ++/* remove unnecessary left padding for radio options */
    ++#EditConfig div.widget .label {
    ++    width: auto;
    ++    float: none;
    ++}
    ++
    ++#EditConfig textarea:disabled,
    ++#EditConfig input:disabled {
    ++    background-color: #EEE;
    ++}
    ++
    ++.widget.code textarea,
    ++textarea.code {
    ++    font-family: Consolas, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
    ++}
    ++
    ++#EditConfig ul.plugins {
    ++    margin: 0;
    ++}
    +
10: 9f34fb6d5c = 10: 165422a396 Annotate Immutable options
11: a85c0c08b3 ! 11: f2f0b772d7 Add widget metadata for config options
    @@ -325,6 +325,16 @@
     +    ValidateUserEmailAddresses => {
     +        Widget => '/Widgets/Form/Boolean',
     +    },
    ++    VERPPrefix => {
    ++        Widget => '/Widgets/Form/String',
    ++        WidgetArguments => { Hints  => 'rt-', },
    ++    },
    ++    VERPDomain => {
    ++        Widget => '/Widgets/Form/String',
    ++        WidgetArguments => {
    ++            Callback => sub {  return { Hints => RT->Config->Get( 'Organization') } },
    ++        },
    ++    },
     +    WebFallbackToRTLogin => {
     +        Widget => '/Widgets/Form/Boolean',
     +    },
12: 6d61a93a18 = 12: 5803325e5f Hide deprecated options
13: 1e69c96f2c = 13: b878fb9786 List Database as source of configuration on Sys Config page
14: 0bf9dcf301 < --:  ------- Port EditConfig page from extension
15: b8b29e09ca = 14: 02b6a1a9fb Render config with EditLink as readonly
16: d5c0a25803 = 15: 94cbaf03d2 Switch from Storable::dclone to Clone::clone to handle code/regex
17: 039215d04d < --:  ------- Fix index of "Disabled" for mysql
18: 422eef91a4 < --:  ------- Fixes the Callback argument, it is an argument of the widget, not the option.
19: 31c5088a7c < --:  ------- Updates config edit widgets (bootstrap+defaults)
--:  ------- > 16: c0d5683bfb Migrate MultilineString to new themes
--:  ------- > 17: 9fcde4980a Add LabelLink support for form widgets
--:  ------- > 18: 1eee9b8f55 Vertically align boolean label/value
20: 0ba0e1932c ! 19: fb5f04660a Add tabs to the Configuration in DB feature
    @@ -11,13 +11,13 @@
     --- a/lib/RT/Config.pm
     +++ b/lib/RT/Config.pm
     @@
    - use Symbol::Global::Name;
    - use List::MoreUtils 'uniq';
    - use Clone ();
    -+use Pod::Simple::HTML;
    - 
    - # Store log messages generated before RT::Logger is available
    - our @PreInitLoggerMessages;
    +         Widget          => '/Widgets/Form/Select',
    +         WidgetArguments => {
    +             Description => 'Default queue',    #loc
    ++            Default     => 1, # allow user to unset it on EditConfig.html
    +             Callback    => sub {
    +                 my $ret = { Values => [], ValuesLabel => {}};
    +                 my $q = RT::Queues->new($HTML::Mason::Commands::session{'CurrentUser'});
     @@
          }
      }
    @@ -69,132 +69,84 @@
     +    },
     +];
     +
    -+our $SectionMapLoaded=0; # so we only load it once
    ++our $SectionMapLoaded = 0;    # so we only load it once
     +
     +sub LoadSectionMap {
     +    my $self = shift;
     +
    -+    if( $SectionMapLoaded) {
    ++    if ($SectionMapLoaded) {
     +        return $SectionMap;
     +    }
     +
     +    # create a hash <section> => <tab> / Content so we know in which tab to look for a section
     +    my %SectionIndex;
     +    foreach my $Tab (@$SectionMap) {
    -+        my $TabName= $Tab->{Name};
    -+        foreach my $section ( @{$Tab->{Content}}) {
    ++        my $TabName = $Tab->{Name};
    ++        foreach my $section ( @{ $Tab->{Content} } ) {
     +            $section->{Content} = [];
    -+            $SectionIndex{$section->{Name}} = { Tab => $TabName, Content => $section->{Content} };
    ++            $SectionIndex{ $section->{Name} } = { Tab => $TabName, Content => $section->{Content} };
     +        }
     +    }
     +
    -+    my $ConfigFile= "$RT::EtcPath/RT_Config.pm";
    -+    my $PodParser = Pod::Simple::HTML->new();
    ++    my $ConfigFile = "$RT::EtcPath/RT_Config.pm";
    ++    require Pod::Simple::HTML;
    ++    my $PodParser  = Pod::Simple::HTML->new();
     +
     +    my $html;
    -+    $PodParser->output_string(\$html);
    -+    $PodParser->parse_file( $ConfigFile);
    ++    $PodParser->output_string( \$html );
    ++    $PodParser->parse_file($ConfigFile);
     +
     +    my $CurrentTabName;
     +    my $CurrentSectionName;
     +    my $CurrentSubSectionName;
     +    my $CurrentSectionContent;
     +
    -+    while( $html=~ m{<(h[12]|dt)\b[^>]*>(.*?)</\1>}sg) {
    -+        my( $tag, $content)= ($1, $2);
    -+        if( $tag eq 'h1') {
    -+            my ( $id, $title)= $content=~ m{<a class='u'\s*name="([^"]*)"\s*>([^<]*)</a>};
    ++    while ( $html =~ m{<(h[12]|dt)\b[^>]*>(.*?)</\1>}sg ) {
    ++        my ( $tag, $content ) = ( $1, $2 );
    ++        if ( $tag eq 'h1' ) {
    ++            my ( $id, $title ) = $content =~ m{<a class='u'\s*name="([^"]*)"\s*>([^<]*)</a>};
     +            next if $title eq 'NAME';
     +            $CurrentSectionName = $title;
    -+            if( $SectionIndex{$CurrentSectionName}->{Tab} ) {
    ++            if ( $SectionIndex{$CurrentSectionName}->{Tab} ) {
     +                $CurrentTabName = $SectionIndex{$CurrentSectionName}->{Tab};
    ++
     +                # create a sub section with no name, for section level options
    -+                push @{$SectionIndex{$CurrentSectionName}->{Content}}, { Name => '', Content => [] };
    ++                push @{ $SectionIndex{$CurrentSectionName}->{Content} }, { Name => '', Content => [] };
     +                $CurrentSectionContent = $SectionIndex{$CurrentSectionName}->{Content};
    -+                $CurrentSubSectionName='';
    ++                $CurrentSubSectionName = '';
     +            }
     +            else {
    -+                RT->Logger->debug( "section $CurrentSectionName not found in SectionMap\n");
    ++                RT->Logger->debug("section $CurrentSectionName not found in SectionMap");
     +            }
     +        }
    -+        elsif( $tag eq 'h2') {
    -+            my ( $id, $title)= $content=~ m{<a class='u'\s*name="([^"]*)"\s*>([^<]*)</a>};
    -+            $CurrentSubSectionName= $title;
    -+            push  @$CurrentSectionContent, { Name => $CurrentSubSectionName, Content => [] };
    ++        elsif ( $tag eq 'h2' ) {
    ++            my ( $id, $title ) = $content =~ m{<a class='u'\s*name="([^"]*)"\s*>([^<]*)</a>};
    ++            $CurrentSubSectionName = $title;
    ++            push @$CurrentSectionContent, { Name => $CurrentSubSectionName, Content => [] };
     +        }
     +        else {
     +            # tag is 'dt'
     +            my @options;
    ++
     +            # a single item (dt) can document several options, in separate <code> elements
    -+            my( $name)= $content=~ m{name=".([^"]*)"};
    -+            $name=~ s{,_.}{-}g;
    -+            while( $content=~ m{<code>(.)([^<]*)</code>}sg) {
    -+                my( $sigil, $option)= ($1, $2);
    -+                next unless $sigil=~ m{[\@\%\$]}; # no sigil => this is a value for a select option
    -+                if( $META{$option}) {
    ++            my ($name) = $content =~ m{name=".([^"]*)"};
    ++            $name =~ s{,_.}{-}g;
    ++            while ( $content =~ m{<code>(.)([^<]*)</code>}sg ) {
    ++                my ( $sigil, $option ) = ( $1, $2 );
    ++                next unless $sigil =~ m{[\@\%\$]};    # no sigil => this is a value for a select option
    ++                if ( $META{$option} ) {
     +                    my $LastSubSectionContent = $CurrentSectionContent->[-1]->{Content};
     +                    push @$LastSubSectionContent, { Name => $option, Help => $name };
     +                }
     +                else {
    -+                    my $TabName= $SectionIndex{$CurrentSectionName}->{Name};
    -+                    RT->Logger->debug( "missing META info for option [$option]\n");
    ++                    my $TabName = $SectionIndex{$CurrentSectionName}->{Name};
    ++                    RT->Logger->debug("missing META info for option [$option]");
     +                }
     +            }
     +        }
     +    }
     +    $SectionMapLoaded = 1;
     +    return $SectionMap;
    -+}
    -+
    -+sub name_to_id {
    -+    my $self = shift;
    -+    my $name = shift;
    -+    my $id = lc( $name);
    -+    $id =~ s{[^a-z0-9]+}{-}g;
    -+    return $id;
    -+}
    -+
    -+# returns an id in the EditConfig.html page
    -+# args are
    -+# type    => ['nav' || 'content' || 'form' ] id for nav links or content respectively
    -+# level   => ['tab' || 'section' || 'subsection' ]
    -+# context => { tab => <tab_id>, section => <section_id>, subsection => <subsection_id> }
    -+sub edit_config_id {
    -+    my $self = shift;
    -+    my %args = @_;
    -+    my $context = $args{context};
    -+    my @id_components = ($args{type}, $context->{tab});
    -+    if( $args{level} eq 'section') {
    -+        push @id_components, $context->{section};
    -+    }
    -+    elsif( $args{level} eq 'subsection') {
    -+        push @id_components, $context->{section}, $context->{subsection};
    -+    }
    -+    return join '-', @id_components;
    -+}
    -+
    -+# returns whether a section is active (ie it's displayed when you open its tab) or not
    -+# if the current tab is active then the section is active if it is the active one
    -+# otherwise (the current tab is not the active one), the section is active if it is
    -+# the first one
    -+# this is abstracted as a method because it needs to be called for each menu item  and
    -+# for each tab content, so this avoids duplicating code
    -+# first-section still needs to be managed by the calling code though
    -+sub section_is_active {
    -+    my $self= shift;
    -+    my %args = @_;
    -+    my $first_section = $args{first_section};
    -+    my $active_context = $args{active_context};
    -+    my $current_context = $args{current_context};
    -+
    -+    my $active = 0;
    -+    if( $current_context->{tab} eq $active_context->{tab} ) {
    -+        $active = 1 if $current_context->{section} eq $active_context->{section};
    -+     }
    -+     else {
    -+        $active = 1 if $first_section;
    -+    }
    -+    return $active;
     +}
     +
      =head2 Configs
    @@ -278,7 +230,6 @@
     +};
     +
     +my $doc_version = $RT::VERSION;
    -+$doc_version =~ s/rc\d+//; # 4.4.2rc1 -> 4.4.2
     +$doc_version =~ s/\.\d+-\d+-g\w+$//;  # 4.4.3-1-g123 -> 4.4
     +
     +my $name = $option->{Name};
    @@ -302,7 +253,6 @@
     +my $args   = $meta->{'WidgetArguments'} || {};
     +if ($widget eq '/Widgets/Form/Boolean') {
     +    %$args = (
    -+        Default => 0,
     +        RadioStyle => 1,
     +        %$args,
     +    );
    @@ -313,20 +263,26 @@
     +        %$args,
     +    );
     +}
    ++elsif ($widget eq '/Widgets/Form/Select') {
    ++    %$args = (
    ++        $args->{Default} ? ( DefaultLabel => loc('(no value)') ) : (),
    ++        %$args,
    ++    );
    ++}
     +my $row_start = qq{<div class="widget form-row">
    -+  <span class="col-md-3 label"><a href="$doc_url" target="_blank">$name</a></span>
    -+  <span class="col-md-9 value">
    ++  <div class="col-md-3 label"><a href="$doc_url" target="_blank">$name</a></div>
    ++  <div class="col-md-9 value">
     +};
    -+my $row_end = qq{</span></div>};
    ++my $row_end = qq{</div></div>};
     +
     +</%PERL>
     +
     +<!-- start option <% $name %> -->
     +% if ( $meta->{EditLink} ) {
     +% if ($widget eq '/Widgets/Form/MultilineString' || $widget eq '/Widgets/Form/Code') {
    -+<% $row_start |n %><textarea disabled class="<% $is_code ? 'code' : '' %>" rows="6" cols="80"><% $current_value %></textarea><br />
    ++<% $row_start |n %><textarea disabled class="<% $is_code ? 'code' : '' %> form-control" rows="6" cols="80"><% $current_value %></textarea><br />
     +% } else {
    -+<% $row_start |n %><input type="text" disabled width="80" value="<% $current_value %>" /><br/>
    ++<% $row_start |n %><input type="text" disabled width="80" value="<% $current_value %>" class="form-control" /><br/>
     +% }
     +<&|/l_unsafe, "<a href=\"$meta->{EditLink}\">", loc($meta->{EditLinkLabel}), "</a>" &>Visit [_1][_2][_3] to manage this setting</&>
     +% } elsif ( $name =~ /Plugins/) {
    @@ -334,28 +290,28 @@
     +% for my $plugin (RT->Config->Get($name)) {
     +<li><a href="https://metacpan.org/search?q=<% $plugin |u %>" target="_blank"><% $plugin %></a></li>
     +% }
    -+</ul><% $row_end |n%>
    ++</ul>
     +<br /><em><% loc('Must modify in config file' ) %></em>
    ++<% $row_end |n%>
     +% } elsif ( $is_password ) {
     +<em><% loc('Must modify in config file' ) %></em><br />
     +% } elsif ( $is_immutable ) {
     +% if ($widget eq '/Widgets/Form/MultilineString' || $widget eq '/Widgets/Form/Code') {
    -+<% $row_start |n %><textarea disabled class="<% $is_code ? 'code' : '' %>" rows="6" cols="80"><% $current_value %></textarea>
    ++<% $row_start |n %><textarea disabled class="<% $is_code ? 'code' : '' %> form-control" rows="6" cols="80"><% $current_value %></textarea>
     +% } else {
    -+<% $row_start |n %><input type="text" disabled width="80" value="<% $current_value %>" />
    ++<% $row_start |n %><input type="text" disabled width="80" value="<% $current_value %>" class="form-control" />
     +% }
     +<br /><em><% loc('Must modify in config file' ) %></em>
     +<% $row_end |n %>
    -+% } else { 
    ++% } else {
     +  <& $widget,
    -+    Default      => 1,
    -+    DefaultValue => '',
    -+    DefaultLabel => '(no value)',
    ++    Default      => 0,
     +    Name         => $name,
     +    LabelLink    => $doc_url,
     +    CurrentValue => $current_value,
     +    Description  => $name,
     +    Hints        => $meta->{WidgetArguments}->{Hints} || '',
    ++    %$args,
     +    %{ $m->comp('/Widgets/FinalizeWidgetArguments', WidgetArguments =>
     +            $meta->{'WidgetArguments'} ) },
     +  &>
    @@ -419,10 +375,10 @@
     +%#
     +%# END BPS TAGGED BLOCK }}}
     +
    -+% my $section_id= RT->Config->name_to_id( $section->{Name} );
    ++% my $section_id = CSSClass( $section->{Name} );
     +
     +% foreach my $subsection ( @{$section->{Content}} ) {
    -+%     $current_context->{subsection}= RT->Config->name_to_id( $subsection->{Name});
    ++%     $current_context->{subsection} = CSSClass( $subsection->{Name});
     +  <& /Admin/Tools/Config/Elements/SubSection, subsection => $subsection, active_context => $active_context, current_context => $current_context &>
     +  <!-- end subsection <% $subsection->{Name} %> -->
     +% }
    @@ -486,11 +442,11 @@
     +%# END BPS TAGGED BLOCK }}}
     +
     +% if( @{$subsection->{Content}}) {
    -+% my $id = RT->Config->edit_config_id( type => 'form', level => 'subsection', context => $current_context);
    ++% my $id = join '-', 'form', $current_context->{tab}, $current_context->{section}, $current_context->{subsection} || ();
     +<form id="<% $id %>" name="EditConfig" method="post" action="EditConfig.html#<% $id %>">
     +    <input type="hidden" name="Update" value="1" />
    -+% my $complete_title = 
    -+%     join ' - ', map { s{-}{ }g; loc( ucfirst $_ ) } 
    ++% my $complete_title =
    ++%     join ' - ', map { s{_}{ }g; loc( $_ ) }
     +%     grep { $_ }
     +%     map { $current_context->{$_} }
     +%     (qw( tab section subsection ) );
    @@ -569,24 +525,21 @@
     +%# END BPS TAGGED BLOCK }}}
     +
     +% my $nav_type = 'pill'; # 'tab' or 'pill'
    -+% my $tab_id= RT->Config->name_to_id( $tab->{Name} );
    ++% my $tab_id = CSSClass( $tab->{Name} );
     +<div class="row">
     +  <div class="col-3">
     +% my @section_names = map { $_->{Name} } @{$tab->{Content}};
     +    <ul class="nav nav-<% $nav_type %>s flex-column navbar-fixed-top" id="config-sections-<% $tab_id %>" aria-orientation="vertical">
     +% my $first_section = 1;
     +% foreach my $section_name (@section_names) {
    -+%     my $section_id= RT->Config->name_to_id( $section_name );
    -+%     $current_context->{section}= $section_id;
    -+%     my $active = RT->Config->section_is_active( 
    -+%         first_section => $first_section,
    -+%         active_context => $active_context,
    -+%         current_context => $current_context,
    -+%     );
    ++%     $current_context->{section} = CSSClass( $section_name );
    ++%     my $active = $current_context->{tab} eq $active_context->{tab} ?
    ++%       $current_context->{section} eq $active_context->{section} :
    ++%       $first_section;
     +%     $first_section = 0;
     +%     my( $active_class, $aria_selected) = $active ? ('active', 'true') : ('', 'false');
    -+%     my $nav_id = RT->Config->edit_config_id( type => 'nav', level => 'section', context => $current_context); 
    -+%     my $content_id = RT->Config->edit_config_id( type => 'content', level => 'section', context => $current_context); 
    ++%     my $nav_id = join '-', 'nav', $current_context->{tab}, $current_context->{section};
    ++%     my $content_id = join '-', 'content', $current_context->{tab}, $current_context->{section};
     +      <li class="nav-item">
     +        <a class="nav-link <% $active_class %>" id="<% $nav_id %>" data-toggle="<% $nav_type %>" href="#<% $content_id %>" role="<% $nav_type %>" aria-controls="<% $nav_id %>" aria-selected="<% $aria_selected %>"><% $section_name %></a>
     +      </li>
    @@ -598,17 +551,14 @@
     +
     +% $first_section = 1;
     +% foreach my $section ( @{$tab->{Content}} ) {
    -+%     my $section_id= RT->Config->name_to_id( $section->{Name} );
    -+%     $current_context->{section}= $section_id;
    -+%     my $active = RT->Config->section_is_active( 
    -+%         first_section => $first_section,
    -+%         active_context => $active_context,
    -+%         current_context => $current_context,
    -+%     );
    ++%     $current_context->{section} = CSSClass( $section->{Name} );
    ++%     my $active = $current_context->{tab} eq $active_context->{tab} ?
    ++%       $current_context->{section} eq $active_context->{section} :
    ++%       $first_section;
     +%     my $active_class = $active ? 'active show' : '';
     +%     $first_section = 0;
    -+%     my $nav_id = RT->Config->edit_config_id( type => 'nav', level => 'section', context => $current_context); 
    -+%     my $content_id = RT->Config->edit_config_id( type => 'content', level => 'section', context => $current_context); 
    ++%     my $nav_id = join '-', 'nav', $current_context->{tab}, $current_context->{section};
    ++%     my $content_id = join '-', 'content', $current_context->{tab}, $current_context->{section};
     +      <div class="tab-pane fade <% $active_class %>" role="tabpanel" id="<% $content_id %>" aria-labelledby="<% $nav_id %>">
     +        <& /Admin/Tools/Config/Elements/Section, section => $section, current_context => $current_context, active_context => $active_context &>
     +      </div><!-- end section <% $content_id %> -->
    @@ -629,16 +579,21 @@
      
      my $has_execute_code = $session{CurrentUser}->HasRight(Right => 'ExecuteCode', Object => RT->System);
      
    +-my @results;
     +my $options = RT->Config->LoadSectionMap();
    -+my $active_context = { 
    -+    tab        => RT->Config->name_to_id( $ARGS{tab}        || $options->[0]->{Name}) ,
    -+    section    => RT->Config->name_to_id( $ARGS{section}    || $options->[0]->{Content}->[0]->{Name}) ,
    -+    subsection => RT->Config->name_to_id( $ARGS{subsection} || $options->[0]->{Content}->[0]->{Content}->[0]->{Name}) ,
    ++my $active_context = {
    ++    tab        => CSSClass( $ARGS{tab}        || $options->[0]->{Name}) ,
    ++    section    => CSSClass( $ARGS{section}    || $options->[0]->{Content}->[0]->{Name}) ,
    ++    subsection => CSSClass( $ARGS{subsection} || $options->[0]->{Content}->[0]->{Content}->[0]->{Name}) ,
     +};
    -+
    - my @results;
    - 
    - my $doc_version = $RT::VERSION;
    + 
    +-my $doc_version = $RT::VERSION;
    +-$doc_version =~ s/rc\d+//; # 4.4.2rc1 -> 4.4.2
    +-$doc_version =~ s/\.\d+-\d+-g\w+$//;  # 4.4.3-1-g123 -> 4.4
    ++my @results;
    + 
    + use Data::Dumper;
    + my $stringify = sub {
     @@
          eval {
              for my $key (keys %ARGS) {
    @@ -647,6 +602,19 @@
      
                  my $meta = RT->Config->Meta( $key );
                  my $widget = $meta->{Widget} || '/Widgets/Form/Code';
    +@@
    +             $setting->Load($key);
    +             if ($setting->Id) {
    +                 if ($setting->Disabled) {
    +-                    $setting->SetDisabled(0);
    ++                    my ($ok, $msg) = $setting->SetDisabled(0);
    ++                    if (!$ok) {
    ++                        push @results, $msg;
    ++                        $has_error++;
    ++                    }
    +                 }
    + 
    +                 my ($ok, $msg) = $setting->SetContent($val);
     @@
          RT->Config->EndDatabaseConfigChanges;
      }
    @@ -716,27 +684,38 @@
     -<textarea disabled class="<% $is_code ? 'code' : '' %>" rows="6" cols="80"><% $current_value %></textarea><br>
     -% } else {
     -<input type="text" disabled width="80" value="<% $current_value %>"></input><br>
    --% }
    ++<div class="titlebox-content">
    ++% my @tab_names = map { $_->{Name} } @$options;
    ++  <ul class="nav nav-<% $nav_type %>s" id="config-tabs">
    ++% my $current_context = {};
    ++% foreach my $tab_name (@tab_names) {
    ++%     my $tab_id = CSSClass( $tab_name );
    ++%     $current_context->{tab} = $tab_id;
    ++%     my( $active, $aria_selected) = $tab_id eq $active_context->{tab} ? ('active', 'true') : ('', 'false');
    ++%     my $nav_id = join '-', 'nav', $current_context->{tab};
    ++%     my $content_id = join '-', 'content', $current_context->{tab};
    ++    <li class="nav-item">
    ++      <a class="nav-link <% $active %>" id="<% $nav_id %>" data-toggle="<% $nav_type %>" href="#<% $content_id %>" role="<% $nav_type %>" aria-controls="<% $content_id %>" aria-selected="<% $aria_selected %>"><% $tab_name %></a>
    ++    </li>
    + % }
     -<&|/l_unsafe, "<a href=\"$meta->{EditLink}\">", loc($meta->{EditLinkLabel}), "</a>" &>Visit [_1][_2][_3] to manage this setting</&>
     -% } elsif ( $key =~ /Plugins/) {
     -<ul class="plugins">
     -% for my $plugin (RT->Config->Get($key)) {
     -<li><a href="https://metacpan.org/search?q=<% $plugin |u %>" target="_blank"><% $plugin %></a></li>
    -+<div class="titlebox-content">
    -+% my @tab_names = map { $_->{Name} } @$options;
    -+<ul class="nav nav-<% $nav_type %>s" id="config-tabs">
    -+% my $current_context = {};
    -+% foreach my $tab_name (@tab_names) {
    -+%     my $tab_id= RT->Config->name_to_id( $tab_name );
    -+%     $current_context->{tab}= $tab_id;
    -+%     my( $active, $aria_selected) = $tab_id eq $active_context->{tab} ? ('active', 'true') : ('', 'false');
    -+%     my $nav_id = RT->Config->edit_config_id( type => 'nav', level => 'tab', context => $current_context); 
    -+%     my $content_id = RT->Config->edit_config_id( type => 'content', level => 'tab', context => $current_context); 
    -+  <li class="nav-item">
    -+    <a class="nav-link <% $active %>" id="<% $nav_id %>" data-toggle="<% $nav_type %>" href="#<% $content_id %>" role="<% $nav_type %>" aria-controls="<% $content_id %>" aria-selected="<% $aria_selected %>"><% $tab_name %></a>
    -+  </li>
    ++  </ul>
    ++  <div class="tab-content" id="content-all" >
    ++% foreach my $tab ( @$options) {
    ++%     my $tab_id = CSSClass( $tab->{Name} );
    ++%     $current_context->{tab} = $tab_id;
    ++%     my $active = $tab_id eq $active_context->{tab} ? ' show active' : '';
    ++%     my $nav_id = join '-', 'nav', $current_context->{tab};
    ++%     my $content_id = join '-', 'content', $current_context->{tab};
    ++    <div class="tab-pane fade<% $active %>" role="tabpanel" id="<% $content_id %>" aria-labelledby="<% $nav_id %>">
    ++      <& /Admin/Tools/Config/Elements/Tab, tab => $tab, active_context => $active_context, current_context => $current_context &>
    ++    </div><!-- <% $content_id %> -->
      % }
    - </ul>
    +-</ul>
     -<br><em><% loc('Must modify in config file' ) %></em>
     -% } elsif ( $is_password ) {
     -<em><% loc('Must modify in config file' ) %></em>
    @@ -760,17 +739,7 @@
     -    Hints        => '',
     -  &>
     -<textarea class="hidden" name="<% $key %>-Current"><% $current_value %></textarea>
    -+<div class="tab-content" id="content-all" >
    -+% foreach my $tab ( @$options) {
    -+%     my $tab_id= RT->Config->name_to_id( $tab->{Name} );
    -+%     $current_context->{tab}= $tab_id;
    -+%     my $active = $tab_id eq $active_context->{tab} ? ' show active' : '';
    -+%     my $nav_id = RT->Config->edit_config_id( type => 'nav', level => 'tab', context => $current_context); 
    -+%     my $content_id = RT->Config->edit_config_id( type => 'content', level => 'tab', context => $current_context); 
    -+<div class="tab-pane fade<% $active %>" role="tabpanel" id="<% $content_id %>" aria-labelledby="<% $nav_id %>">
    -+  <& /Admin/Tools/Config/Elements/Tab, tab => $tab, active_context => $active_context, current_context => $current_context &>
    -+</div><!-- <% $content_id %> -->
    - % }
    +-% }
     -</td>
     -</tr>
     -% }
    @@ -779,44 +748,6 @@
     -<& /Elements/Submit, Label => loc('Save Changes') &>
     -</form>
     -
    -+</div><!-- content-all -->
    ++  </div><!-- content-all -->
    ++</div><!-- titlebox-content -->
     
    -diff --git a/share/html/Widgets/FinalizeWidgetArguments b/share/html/Widgets/FinalizeWidgetArguments
    ---- a/share/html/Widgets/FinalizeWidgetArguments
    -+++ b/share/html/Widgets/FinalizeWidgetArguments
    -@@
    - %#
    - %# END BPS TAGGED BLOCK }}}
    - <%init>
    --    my %args = %$WidgetArguments;
    -+    my %args = $WidgetArguments ? %$WidgetArguments : ();
    - 
    -     %args = (%args, %{ $args{Callback}->() }) if $args{Callback};
    -     $args{'Description'} = loc( $args{'Description'} ) if $args{'Description'};
    -
    -diff --git a/share/html/Widgets/Form/Boolean b/share/html/Widgets/Form/Boolean
    ---- a/share/html/Widgets/Form/Boolean
    -+++ b/share/html/Widgets/Form/Boolean
    -@@
    -     <% $Description %>
    - % }
    -   </span>
    --  <span class="col-md-9 value">
    -+  <span class="col-md-9">
    -     <& SELF:InputOnly, %ARGS &>
    -     <span class="hints"><% $Hints %></span>
    -   </span>
    -
    -diff --git a/share/html/Widgets/Form/MultilineString b/share/html/Widgets/Form/MultilineString
    ---- a/share/html/Widgets/Form/MultilineString
    -+++ b/share/html/Widgets/Form/MultilineString
    -@@
    - </%ARGS>
    - 
    - <%METHOD InputOnly>
    --<textarea name="<% $Name %>" cols="<% $Cols %>" rows="<% $Rows %>"><% $CurrentValue %></textarea>
    -+<textarea name="<% $Name %>" class="form-control" cols="<% $Cols %>" rows="<% $Rows %>"><% $CurrentValue %></textarea>
    - <%ARGS>
    - $Name
    - $Cols => 80
    -
21: 9e63e304aa ! 20: 21ff2fa0c2 Add missing config options to %META
    @@ -15,19 +15,16 @@
     +    CanonicalizeEmailAddressMatch => {
     +        Section         => 'Mail',                                     #loc
     +        Type            => 'SCALAR',
    -+        Overridable     => 1,
     +        Widget          => '/Widgets/Form/String',
     +    },
     +    CanonicalizeEmailAddressReplace => {
     +        Section         => 'Mail',                                     #loc
     +        Type            => 'SCALAR',
    -+        Overridable     => 1,
     +        Widget          => '/Widgets/Form/String',
     +    },
     +    EmailSubjectTagRegex => {
     +        Section         => 'Mail',                                     #loc
     +        Type            => 'SCALAR',
    -+        Overridable     => 1,
     +        Widget          => '/Widgets/Form/String',
     +    },
          # User overridable mail options
    @@ -66,3 +63,4 @@
          AssetSearchFormat => {
              Widget => '/Widgets/Form/MultilineString',
          },
    +
--:  ------- > 21: 5523105073 Rename DatabaseSetting to Configuration
--:  ------- > 22: d80765bfaf Validate Content of Configurations
--:  ------- > 23: 1ada6c8511 Use Data::Dumper instead in Configuration to support regex
--:  ------- > 24: 165ca1445f Note RT::Extension::ConfigInDatabase is cored and the main backend change



More information about the rt-commit mailing list