[Rt-commit] rt branch 5.0/add-boolean-cf-render-type created. rt-5.0.3-166-g3e55368030
BPS Git Server
git at git.bestpractical.com
Fri Dec 23 16:49:50 UTC 2022
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-boolean-cf-render-type has been created
at 3e55368030dd3afd54701c3348ddcf15906e70d4 (commit)
- Log -----------------------------------------------------------------
commit 3e55368030dd3afd54701c3348ddcf15906e70d4
Author: Brian Conry <bconry at bestpractical.com>
Date: Mon Jul 11 16:17:56 2022 -0500
Add a Checkbox RenderType for select type custom fields
This provides a single checkbox for "Yes/No" type CFs.
A single box is a nicer display option than the previous
approach of showing radio buttons or a dropdown with
Yes/No options.
diff --git a/docs/initialdata.pod b/docs/initialdata.pod
index d2343349b0..b4ef04e7f3 100644
--- a/docs/initialdata.pod
+++ b/docs/initialdata.pod
@@ -217,10 +217,9 @@ common C<LookupType>.
=item C<RenderType>
Only valid when C<Type> is "Select". Controls how the CF is displayed when
-editing it. Valid values are: C<Select box>, C<List>, and C<Dropdown>.
+editing it. Valid values are: C<Select box>, C<List>, C<Dropdown>, and C<Checkbox>.
-C<List> is either a list of radio buttons or a list of checkboxes depending on
-C<MaxValues>.
+See L<RT::CustomField/SetRenderType> for details.
=item C<MaxValues>
diff --git a/lib/RT/CustomField.pm b/lib/RT/CustomField.pm
index ac7b6d89e4..d979a529eb 100644
--- a/lib/RT/CustomField.pm
+++ b/lib/RT/CustomField.pm
@@ -88,6 +88,7 @@ our %FieldTypes = (
single => [ 'Dropdown', # loc
'Select box', # loc
'List', # loc
+ 'Checkbox', # loc
]
},
@@ -1348,6 +1349,12 @@ sub SetRenderType {
$self->FriendlyType));
}
+ if ( $type eq 'Checkbox' ) {
+ if ( $self->Values->Count < 2 ) {
+ return (0, $self->loc("Must have two values for Render Type Checkbox"));
+ }
+ }
+
return $self->_Set( Field => 'RenderType', Value => $type, @_ );
}
@@ -2104,6 +2111,9 @@ sub SetBasedOn {
if ( $self->RenderType =~ /List/ ) {
return (0, $self->loc("We can't currently render as a List when basing categories on another custom field. Please use another render type."));
}
+ elsif ( $self->RenderType eq 'Checkbox' ) {
+ return (0, $self->loc("We can't currently render as a Checkbox when basing categories on another custom field. Please use another render type."));
+ }
return $self->_Set( Field => 'BasedOn', Value => $value, @_ )
}
@@ -2353,6 +2363,15 @@ Set RenderType to VALUE.
Returns (1, 'Status message') on success and (0, 'Error Message') on failure.
(In the database, RenderType will be stored as a varchar(64).)
+Only valid when C<Type> is "Select". Controls how the CF is displayed when
+editing it. Valid values are: C<Select box>, C<List>, C<Dropdown>, and C<Checkbox>.
+
+C<List> is rendered as radio buttons when MaxValues is 1 (accepts
+one value) or as checkboxes when MaxValues is 0 (accepts multiple
+values).
+
+C<Checkbox> renders as a single checkbox and expects two values, one for
+checked and one for unchecked.
=cut
diff --git a/lib/RT/CustomFieldValue.pm b/lib/RT/CustomFieldValue.pm
index 2c991f2b1e..b066e374ea 100644
--- a/lib/RT/CustomFieldValue.pm
+++ b/lib/RT/CustomFieldValue.pm
@@ -102,6 +102,7 @@ sub ValidateName {
sub Delete {
my $self = shift;
+
my ( $ret, $msg ) = $self->SUPER::Delete;
$self->CustomFieldObj->CleanupDefaultValues;
return ( $ret, $msg );
diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm
index da6382ec27..e7327e1d93 100644
--- a/lib/RT/Interface/Web.pm
+++ b/lib/RT/Interface/Web.pm
@@ -3453,6 +3453,28 @@ sub _ProcessObjectCustomFieldUpdates {
Value => $value,
);
+ # The specification we've implemented for the checkbox render type
+ # is that an unset custom field is logically considered the same as
+ # having the explicit "unchecked" value (the first value), and that
+ # it is preferred to store the explicit "unchecked" value rather than
+ # leaving the field unset.
+ # Therefore this condition here, where the field didn't have a value
+ # and now is being set to the "unchecked" value, does not represent
+ # a logical change in the state of the field and should not show in
+ # the transaction history.
+ if (
+ $cf_type eq 'Select' and
+ $cf->RenderType eq 'Checkbox' and
+ not defined $cf_values->First and
+ lc $value eq lc $cf_values->First->Name
+ ) {
+ my ( $val, $msg ) = $args{'Object'}->AddCustomFieldValue(
+ Field => $cf,
+ Value => $value,
+ RecordTransaction => 0,
+ );
+ }
+
my ( $val, $msg ) = $args{'Object'}->AddCustomFieldValue(
Field => $cf,
Value => $value
diff --git a/share/html/Admin/CustomFields/Modify.html b/share/html/Admin/CustomFields/Modify.html
index daef955a53..a8bd1fbfd2 100644
--- a/share/html/Admin/CustomFields/Modify.html
+++ b/share/html/Admin/CustomFields/Modify.html
@@ -135,7 +135,8 @@ jQuery( function() {
</&>
% if ( $CustomFieldObj->SupportDefaultValues ) {
-<&| /Elements/LabeledValue, Label => loc("Default [numerate,_1,value,values]", $CustomFieldObj->MaxValues) &>
+<&| /Elements/LabeledValue, Label => loc("Default [numerate,_1,value,values]", $CustomFieldObj->MaxValues),
+ Class => $default_value_class &>
<& /Elements/EditCustomField, NamePrefix => 'Default-', CustomField => $CustomFieldObj, ShowEmptyOption => 1 &>
</&>
% }
@@ -252,6 +253,7 @@ jQuery( function() {
my ($title, @results, $added_cfv);
my $CustomFieldObj = RT::CustomField->new( $session{'CurrentUser'} );
+my $default_value_class = ''; # Extra classes for default CF value input
$m->callback(CallbackName => 'Initial', Pattern => \$Pattern, Results => \@results, ARGSRef => \%ARGS);
@@ -453,6 +455,14 @@ MaybeRedirectForResults(
Arguments => { id => $id },
) if $CustomFieldObj->id;
+if ( $CustomFieldObj->RenderType eq 'Checkbox' ) {
+ $default_value_class = 'cfrendertype-Checkbox';
+
+ if ( $CustomFieldObj->Values->Count < 2 ) {
+ # Remind users a Checkbox should have two values
+ push @results, 'Checkbox custom fields require two values, one for checked and one for unchecked.';
+ }
+}
my $EnabledChecked = qq[checked="checked"];
$EnabledChecked = '' if $CustomFieldObj->Disabled;
diff --git a/share/html/Admin/Elements/EditCustomFieldValues b/share/html/Admin/Elements/EditCustomFieldValues
index 915b471b80..045ee30593 100644
--- a/share/html/Admin/Elements/EditCustomFieldValues
+++ b/share/html/Admin/Elements/EditCustomFieldValues
@@ -50,9 +50,13 @@
% return;
% }
-% # we need to allow for an extra col-2 if not combobox and categories are enabled
-% # if so, make the description cols -2 smaller to allow for categories
-% my $description_col_size = ( $CustomField->Type ne 'Combobox' && $Categories ? 4 : 6 );
+% # we need to allow for an extra col-2 for:
+% # a) Any CF with categories
+% # The extra space is used to set the category for each value
+% # b) Any CF with the Checkbox render type
+% # The extra space is used for the "Unchecked"/"Checked" descriptive text
+% # Note that the Combobox CF Type and Checkbox RenderType both preclude having categories,
+% my $description_col_size = ( ( $CustomField->Type ne 'Combobox' && $Categories ) || $renderType eq "Checkbox" ? 4 : 6 );
<div class="form-row">
<div class="label col-auto">
@@ -75,8 +79,14 @@
<&|/l&>Category</&>
</div>
% }
+% elsif ( $renderType eq 'Checkbox' ) {
+ <div class="label categoryheader col-2 text-left">
+ <&|/l&>Checkbox Type</&>
+ </div>
+% }
</div>
+% my $firstValue = 1;
% while ( my $value = $values->Next ) {
% my $paramtag = "CustomField-". $CustomField->Id ."-Value-". $value->Id;
<div class="form-row">
@@ -106,6 +116,12 @@
% }
</select>
</div>
+% }
+% if ( $renderType eq 'Checkbox' ) {
+ <div class="col-2">
+ <% $firstValue ? loc('Unchecked') : loc('Checked') %>
+% $firstValue = 0;
+ </div>
% }
<div class="col-1">
<input type="button" class="delete_custom_field_value button btn btn-primary" data-cfv-id="<% $value->id %>" value="<&|/l&>Delete</&>" onclick="delete_custom_field_value(<% $value->id %>)" />
@@ -139,6 +155,9 @@ my $Categories;
if ($BasedOnObj and $BasedOnObj->Id) {
$Categories = $BasedOnObj->Values;
}
+
+my $renderType = $CustomField->RenderType;
+
</%init>
<%args>
$CustomField => undef
diff --git a/share/html/Elements/EditCustomFieldSelect b/share/html/Elements/EditCustomFieldSelect
index acc8e9e5f3..5f7ff72d82 100644
--- a/share/html/Elements/EditCustomFieldSelect
+++ b/share/html/Elements/EditCustomFieldSelect
@@ -78,6 +78,17 @@
% }
</div>
</fieldset>
+% } elsif ( $RenderType eq 'Checkbox' ) {
+% my $CFVs = CachedCustomFieldValues($CustomField);
+% my $checkbox_value;
+% my $FalseValue = lc ( ($checkbox_value = $CFVs->First) ? $checkbox_value->Name : 'false');
+% my $TrueValue = lc ( ($checkbox_value = $CFVs->Next) ? $checkbox_value->Name : 'true');
+% my $isChecked = (scalar keys %default) && (not exists $default{$FalseValue});
+ <div class="custom-control custom-checkbox">
+ <input id="<% $name . '-Display' %>" type="checkbox" class="custom-control-input" <% $isChecked ? "checked" : "" %> onclick="document.getElementById('<% $name |n%>').value = this.checked ? '<% $TrueValue %>' : '<% $FalseValue %>'" />
+ <label class="custom-control-label" for="<% $name . '-Display' %>"></label><br />
+ <input type="hidden" id="<% $name %>" name="<% $name %>" class="custom-control" value="<% $isChecked ? $TrueValue : $FalseValue %>" />
+ </div>
% } else {
% if (@category) {
%# this hidden select is to supply a full list of values,
diff --git a/share/html/Elements/EditCustomFields b/share/html/Elements/EditCustomFields
index 02a8949418..36aa11c451 100644
--- a/share/html/Elements/EditCustomFields
+++ b/share/html/Elements/EditCustomFields
@@ -53,10 +53,12 @@
% }
% for my $CustomField ( @CustomFields ) {
% my $Type = $CustomField->Type || 'Unknown';
+% my $RenderType = $CustomField->RenderType || 'Unknown';
% my @classes = (
% 'form-row',
% 'edit-custom-field',
% "cftype-$Type",
+% "cfrendertype-$RenderType",
% );
% $m->callback( CallbackName => 'ModifyFieldClasses', CustomField => $CustomField,
% Object => $Object, Classes => \@classes, Grouping => $Grouping );
diff --git a/share/html/Elements/ShowCustomFieldSelect b/share/html/Elements/ShowCustomFieldSelect
new file mode 100644
index 0000000000..e04aa6afb7
--- /dev/null
+++ b/share/html/Elements/ShowCustomFieldSelect
@@ -0,0 +1,60 @@
+%# BEGIN BPS TAGGED BLOCK {{{
+%#
+%# COPYRIGHT:
+%#
+%# This software is Copyright (c) 1996-2022 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 }}}
+<%INIT>
+my $cf = $Object->CustomFieldObj;
+my $content = $Object->Content;
+</%INIT>
+% if ( $cf->RenderType eq 'Checkbox' ) {
+ <input type="checkbox" disabled="disabled" class="custom-control" <% ( defined $content and lc $content ne lc CachedCustomFieldValues($cf)->First->Name ) ? "checked" : "" %> />
+% }
+% else {
+ <% $content |h %>
+% }
+<%ARGS>
+$Object => undef
+</%ARGS>
diff --git a/share/static/css/elevator-light/forms.css b/share/static/css/elevator-light/forms.css
index 2bfcc777f8..6d53011e94 100644
--- a/share/static/css/elevator-light/forms.css
+++ b/share/static/css/elevator-light/forms.css
@@ -296,7 +296,10 @@ div[id^="TitleBox--_Ticket_ModifyPeople_html"] .list-group-item {
padding-bottom: 0.25em;
}
-.form-row.boolean > .value .form-row {
+/* These move horizontal radio buttons and a single checkbox down
+ to be centered next to the label, which is also pushed down */
+.form-row.boolean > .value .form-row,
+.form-row.cfrendertype-Checkbox > .value {
margin-top: 5px;
}
-----------------------------------------------------------------------
hooks/post-receive
--
rt
More information about the rt-commit
mailing list