diff --git a/lib/RT/Interface/Web.pm b/lib/RT/Interface/Web.pm index bf9639bcbb8..1b185c53ac0 100644 --- a/lib/RT/Interface/Web.pm +++ b/lib/RT/Interface/Web.pm @@ -6479,6 +6479,38 @@ sub GetDefaultDashboard { return $dashboard; } +=head2 GetInvalidFields Object => $Object + +Returns a list of fields that are marked as invalid by server. + +=cut + +sub GetInvalidFields { + my %args = @_; + my @fields; + foreach my $note ( keys %{$m->notes} ) { + if ( $note =~ /^InvalidField\-(\d+)(?:-(.+))?/ ) { + my $cf_id = $1; + my $grouping = $2; + my $cf = RT::CustomField->new($session{'CurrentUser'}); + my ($ok, $msg) = $cf->Load($cf_id); + if ( $cf->Id ) { + push @fields, + GetCustomFieldInputName( + CustomField => $cf, + Grouping => $grouping, + # Do not pass misleading ticket object in case it's a txn cf. + $cf->ObjectTypeFromLookupType eq ref $args{Object} ? ( Object => $args{Object} ) : (), + ); + } + else { + RT->Logger->error("Unable to load custom field $cf_id: $msg") unless $ok; + } + } + } + return @fields; +} + package RT::Interface::Web; RT::Base->_ImportOverlays(); diff --git a/share/html/Asset/Create.html b/share/html/Asset/Create.html index f439df7fb89..b43b7aa6b4f 100644 --- a/share/html/Asset/Create.html +++ b/share/html/Asset/Create.html @@ -155,6 +155,17 @@ } } else { push @results, @cf_errors; + + if ( !$cf_ok && RT::Interface::Web::RequestENV('HTTP_HX_BOOSTED') ) { + $r->headers_out->{'HX-Trigger'} = JSON( + { + actionsChanged => { messages => \@results, isWarning => 1 }, + validationFailed => [ GetInvalidFields( Object => RT::Asset->new( $session{CurrentUser} ) ) ], + }, + ascii => 1, + ); + Abort( loc("Validation error"), Code => HTTP::Status::HTTP_UNPROCESSABLE_CONTENT ); + } } } diff --git a/share/html/Elements/EditCustomField b/share/html/Elements/EditCustomField index 38eec673c07..32323a9be04 100644 --- a/share/html/Elements/EditCustomField +++ b/share/html/Elements/EditCustomField @@ -63,13 +63,15 @@ $m->comp( CustomField => $CustomField, Name => $Name, $CustomField->BasedOn && $Name ? ( BasedOnName => GetCustomFieldInputName(Object => $Object, CustomField => $CustomField->BasedOnObj, Grouping => $Grouping) ) : (), + DescribedBy => $CFHintId, + AddClass => $AddClass, ); -if (my $msg = $m->notes('InvalidField-' . $CustomField->Id)) { +if ( $error_msg ) { - <% $msg %> + <% $error_msg %> % } elsif ($ShowHints and $CustomField->FriendlyPattern) { - + <% $CustomField->FriendlyPattern %> % } @@ -106,6 +108,13 @@ if ( !$NamePrefix ) { $Name = GetCustomFieldInputName(Object => $Object, CustomField => $CustomField, Grouping => $Grouping ); } +my $CFHintId; +my $cf_name_prefix = GetCustomFieldInputNamePrefix(Object => $Object, CustomField => $CustomField, Grouping => $Grouping ); + +if ($ShowHints and $CustomField->FriendlyPattern) { + $CFHintId = $cf_name_prefix . 'Hint'; +} + # Always fill $Default with submited values if it's empty if ( ( !defined $Default || !length $Default ) && $DefaultsFromTopArguments ) { my %TOP = %$DECODED_ARGS; @@ -116,8 +125,7 @@ if ( ( !defined $Default || !length $Default ) && $DefaultsFromTopArguments ) { // $TOP{ $NamePrefix . $CustomField->Id . '-Value' }; } else { - my $prefix = GetCustomFieldInputNamePrefix(Object => $Object, CustomField => $CustomField, Grouping => $Grouping ); - $Default //= $TOP{ $prefix . 'Values' } // $TOP{ $prefix . 'Value' }; + $Default //= $TOP{ $cf_name_prefix . 'Values' } // $TOP{ $cf_name_prefix . 'Value' }; } } @@ -164,6 +172,12 @@ if ( RT->Config->Get('ExternalInfoPriority') && $Object && $Object->isa('RT::Use } } +my ($error_msg, $AddClass); +if ( $m->notes('InvalidField-' . $CustomField->Id . ($Grouping ? "-$Grouping" : '') ) ) { + $error_msg = $m->notes( 'InvalidField-' . $CustomField->Id . ($Grouping ? "-$Grouping" : '') ); + $AddClass = 'is-invalid'; +} + my $EditComponent = "EditCustomField$Type"; $m->callback( %ARGS, CallbackName => 'EditComponentName', Name => \$EditComponent, CustomField => $CustomField, Object => $Object, Rows => \$Rows, Cols => \$Cols); $EditComponent = "EditCustomField$Type" unless $m->comp_exists($EditComponent); diff --git a/share/html/Elements/EditCustomFieldAutocomplete b/share/html/Elements/EditCustomFieldAutocomplete index 78e6baa46a3..998ae48d994 100644 --- a/share/html/Elements/EditCustomFieldAutocomplete +++ b/share/html/Elements/EditCustomFieldAutocomplete @@ -53,7 +53,10 @@ cols="<% $Cols %>" \ % if ( defined $Rows ) { rows="<% $Rows %>" \ % } -name="<% $name %>" id="<% $name %>" class="CF-<%$CustomField->id%>-Edit form-control"><% $Default || '' %> +% if ( defined $DescribedBy ) { +aria-describedby="<% $DescribedBy %>" \ +% } +name="<% $name %>" id="<% $name %>" class="CF-<%$CustomField->id%>-Edit form-control <% $AddClass // '' %>"><% $Default || '' %>