%# BEGIN BPS TAGGED BLOCK {{{
%#
%# COPYRIGHT:
%#
%# This software is Copyright (c) 1996-2026 Best Practical Solutions, LLC
%#                                          <sales@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 }}}
% $m->callback( %ARGS, CallbackName => 'BeforeWidget' );

% $m->callback( %ARGS, CallbackName => 'LinksExtra', extra => \@extra );
<&| /Widgets/TitleBox, title => loc('Links'),
    class => (join " ", 'ticket-info-links', 'links-widget', ($modify_behavior eq 'always' ? 'editing' : ())),
    data => { 'inline-edit-behavior' => $modify_behavior },
    @extra,
&>
% if ($modify_behavior eq 'hide') {
  <div class="inline-edit-display">
    <div class="links-display-target" id="links-display-target-<% $TicketObj->id %>" hx-trigger="ticketLinksChanged from:body, ticketCustomFieldsChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/ShowLinks?ObjectType=RT::Ticket&ObjectId=<% $TicketObj->id %><% $edit_default_qs |n %>" hx-swap="innerHTML">
      <& /Elements/ShowLinks, Object => $TicketObj, @filter_args, ListCount => $ListCount &>
    </div>
  </div>
% } else {
  <form class="inline-edit" hx-post="<% RT->Config->Get('WebPath') %>/Helpers/TicketUpdate" hx-swap="none" enctype="multipart/form-data">
    <input type="hidden" class="hidden" name="id" value="<% $TicketObj->id %>" />
    <div class="links-edit-container" hx-trigger="ticketLinksChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/EditLinks?ObjectType=RT::Ticket&ObjectId=<% $TicketObj->id %>&DualMode=1<% $edit_default_qs |n %><% $add_default_qs |n %><% $empty_hint ? '&EmptyHint=1' : '' %>" hx-swap="innerHTML">
      <& /Elements/EditLinks, Object => $TicketObj, DualMode => 1, @filter_args, ListCount => $ListCount, DefaultType => $DefaultType, EmptyHint => $empty_hint &>
    </div>
    <& /Widgets/Spinner &>
  </form>
%# Its native-submit <form> must sit OUTSIDE the inline-edit <form> above (a nested <form> is dropped).
  <& /Elements/CreateLinkedTicket, Object => $TicketObj, DefaultType => $DefaultType &>
% }
</&>
<& /Elements/LinksInfoModal, Object => $TicketObj &>

% $m->callback( %ARGS, CallbackName => 'AfterWidget' );

<%INIT>
my %inline_edit_behavior;
if ( RT->Config->Get('InlineEditPanelBehavior') ) {
    %inline_edit_behavior = %{ RT->Config->Get('InlineEditPanelBehavior')->{'RT::Ticket'} || {} };
}
my $modify_behavior
    = RT->Config->Get( 'InlineEdit', $session{CurrentUser} ) ? ( $inline_edit_behavior{Links} || $inline_edit_behavior{_default} || 'link' ) : 'hide';
my $can_modify = $TicketObj->CurrentUserHasRight('ModifyTicket');

# The hint points at the pencil, so show it only when the pencil is there and can add links.
my $empty_hint = ( $can_modify && $modify_behavior =~ /^(link|click)$/ ) ? 1 : 0;

my $has_links = RT::Links->LinkListingCount( CurrentUser => $session{CurrentUser}, Object => $TicketObj );

my @all_rels = qw(DependsOn DependedOnBy MemberOf Members RefersTo ReferredToBy);
my @all_objs = qw(Ticket Transaction Asset Article User Group URL);
my %valid_rel  = map { $_ => 1 } @all_rels;
my %valid_obj  = map { $_ => 1 } @all_objs;
my @show_rels  = grep { $valid_rel{$_} } @ShowRelationship;
my @show_objs  = grep { $valid_obj{$_} } @ShowObjectType;
my @rel_default = ( @show_rels && @show_rels < @all_rels ) ? @show_rels : ();
my @obj_default = ( @show_objs && @show_objs < @all_objs ) ? @show_objs : ();
my $default_active = ( $HideInactive || @rel_default || @obj_default ) ? 1 : 0;

my @filter_args = (
    ShowRelationship => \@rel_default,
    ShowObjectType   => \@obj_default,
    HideInactive     => $HideInactive,
);
my $edit_default_qs = '';
if ($default_active) {
    my @parts;
    push @parts, 'HideInactive=1' if $HideInactive;
    push @parts, 'ShowRelationship=' . $m->interp->apply_escapes( $_, 'u' ) for @rel_default;
    push @parts, 'ShowObjectType=' . $m->interp->apply_escapes( $_, 'u' )   for @obj_default;
    $edit_default_qs = '&' . join '&', @parts;
}
$edit_default_qs .= '&ListCount=' . $m->interp->apply_escapes( $ListCount, 'u' ) if defined $ListCount;
my $add_default_qs = ( defined $DefaultType && length $DefaultType ) ? '&DefaultType=' . $m->interp->apply_escapes( $DefaultType, 'u' ) : '';

my @extra;
my $graph_label = $m->interp->apply_escapes( loc('Graph ticket links'), 'h' );
my $links_graph = '<span class="rt-inline-icon border rounded"><a class="menu-item" href="' . RT->Config->Get('WebPath') . '/Ticket/Graphs/index.html?id=' . $TicketObj->id . qq{" aria-label="$graph_label" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-title="$graph_label">} . GetSVGImage( Name => 'diagram' ) . '</a></span>';

my $links_info = $m->scomp('/Elements/LinksInfoIcon');

# Search + filter live in the title bar (like History) to save vertical space. It targets whichever
# body the current mode renders: the edit body in editable modes, else the read-only display body.
my $links_filter = $m->scomp(
    '/Elements/LinksFilter',
    Object => $TicketObj,
    Target => ( $modify_behavior eq 'hide' ? '#links-display-target-' : '#links-edit-target-' ) . $TicketObj->id,
    Mode   => ( $modify_behavior eq 'hide' ? 'display' : 'edit' ),
    Class  => ( $has_links ? '' : 'd-none' ),
    @filter_args,
);

my $links_titleright = join ' ',
    $links_filter,
    $links_info,
    (RT->Config->Get('DisableGraphViz') ? () : $links_graph),
    ($can_modify && $modify_behavior =~ /^(link|click)$/ ? ($m->scomp('/Elements/InlineEditLink')) : ());
push @extra, (titleright_raw => $links_titleright) if $links_titleright;
</%INIT>

<%ARGS>
$TicketObj
@ShowRelationship => ()
@ShowObjectType   => ()
$HideInactive     => 0
$ListCount        => undef
$DefaultType      => undef
</%ARGS>
