Skip to content

Commit

Permalink
Convert inline edit to htmx on ticket display
Browse files Browse the repository at this point in the history
As only related widgets will be refreshed, this commit removes js code that
submits data of all inline-edit forms instead of just current form.
  • Loading branch information
sunnavy committed Mar 26, 2024
1 parent 7391b99 commit e6978b8
Show file tree
Hide file tree
Showing 18 changed files with 302 additions and 80 deletions.
2 changes: 2 additions & 0 deletions share/html/Elements/AddLinks
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ foreach my $exclude_type ( keys %exclude_links ) {
<input type="text" class="form-control" name="RefersTo-<%$id%>" value="<% $ARGSRef->{"RefersTo-$id"} || '' %>" <% $exclude_links{Refer} |n%>/>
</&>

<div class="edit-custom-fields-container" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/EditCustomFields?ObjectType=<% ref $Object %>&ObjectId=<% $Object->Id %>&Grouping=Links&InTable=1" hx-swap="innerHTML">
<& /Elements/EditCustomFields,
Object => $Object,
Grouping => 'Links',
Expand All @@ -148,5 +149,6 @@ foreach my $exclude_type ( keys %exclude_links ) {
? (CustomFields => $CustomFields)
: ()),
&>
</div>
% $m->callback( CallbackName => 'NewLink' );
</div>
4 changes: 3 additions & 1 deletion share/html/Elements/Header
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
</div>
% }
% if ($ShowTitle) {
<div id="header"><h1><% $Title %></h1></div>
<div id="header"><h1 <% $TitleTrigger ? qq{hx-trigger="$TitleTrigger"} : '' |n %> <% $TitleSource ? qq{hx-get="$TitleSource"} : '' |n %>><% $Title %></h1></div>
% }

<div id="hx-boost-spinner" class="d-none">
Expand Down Expand Up @@ -201,4 +201,6 @@ $LinkRel => undef
$SkipDoctype => 0
$RichText => 1
$BodyClass => undef
$TitleTrigger => ''
$TitleSource => ''
</%ARGS>
10 changes: 6 additions & 4 deletions share/html/Elements/ShowCustomFieldCustomGroupings
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,16 @@ for my $group ( @Groupings ) {

<&| /Widgets/TitleBox, %grouping_args &>
% unless ($modify_behavior eq 'always') {
<div class="inline-edit-display">
<div class="inline-edit-display show-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/ShowCustomFields?ObjectType=<% ref $Object %>&ObjectId=<% $Object->Id %>&Grouping=<% $group %>">
<& ShowCustomFields, %ARGS, Object => $Object, Grouping => $group &>
</div>
% }
% if ($modify_behavior ne 'hide') {
<form class="inline-edit" action="<% $ActionURL %>" method="post" enctype="multipart/form-data">
<form class="inline-edit" hx-post="<% $ActionURL %>" hx-swap="none" enctype="multipart/form-data">
<input type="hidden" class="hidden" name="id" value="<% $Object->id %>" />
<& /Elements/EditCustomFields, Object => $Object, Grouping => $group, InTable => 0 &>
<div class="edit-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/EditCustomFields?ObjectType=<% ref $Object %>&ObjectId=<% $Object->Id %>&Grouping=<% $group %>&InTable=0" hx-swap="innerHTML">
<& /Elements/EditCustomFields, Object => $Object, Grouping => $group, InTable => 0 &>
</div>
<div class="row mt-2">
<div class="col-12 text-end">
<input type="submit" class="button btn btn-primary" value="<&|/l&>Save</&>" />
Expand All @@ -113,7 +115,7 @@ $Object
$title_href => ""
$InlineEdit => 0
@Groupings => ()
$ActionURL => RT->Config->Get('WebPath')."/Ticket/Display.html"
$ActionURL => RT->Config->Get('WebPath') . '/Helpers/TicketUpdate'
</%ARGS>
<%INIT>
my $css_class = lc(ref($Object)||$Object);
Expand Down
68 changes: 59 additions & 9 deletions share/html/Helpers/TicketUpdate
Original file line number Diff line number Diff line change
Expand Up @@ -61,27 +61,77 @@ my $TicketObj = LoadTicket($id);
# fill ACL cache
$TicketObj->CurrentUser->PrincipalObj->HasRights( Object => $TicketObj );

my @events;

$m->callback(CallbackName => 'ProcessArguments',
Ticket => $TicketObj,
ARGSRef => \%ARGS,
Actions => \@Actions);
Actions => \@Actions,
Events => \@events,
);

# It's common to change owner and add a reply/comment in the same
# update. Process the owner change before the message update so the
# new owner will see the message if they only see notifications when
# they are the owner.
push @Actions, ProcessTicketOwnerUpdate(ARGSRef => \%ARGS, TicketObj => $TicketObj );
my @owner_changes = ProcessTicketOwnerUpdate(ARGSRef => \%ARGS, TicketObj => $TicketObj );

push @Actions, ProcessUpdateMessage(
my @message_changes = ProcessUpdateMessage(
ARGSRef => \%ARGS,
Actions => \@Actions,
TicketObj => $TicketObj,
);

push @Actions, ProcessTicketWatchers(ARGSRef => \%ARGS, TicketObj => $TicketObj );
push @Actions, ProcessTicketBasics( ARGSRef => \%ARGS, TicketObj => $TicketObj );
push @Actions, ProcessTicketLinks( ARGSRef => \%ARGS, TicketObj => $TicketObj );
push @Actions, ProcessTicketDates( ARGSRef => \%ARGS, TicketObj => $TicketObj );
push @Actions, ProcessObjectCustomFieldUpdates(ARGSRef => \%ARGS, Object => $TicketObj );
push @Actions, ProcessTicketReminders( ARGSRef => \%ARGS, TicketObj => $TicketObj );
my @watchers_changes = ProcessTicketWatchers( ARGSRef => \%ARGS, TicketObj => $TicketObj );
my @basics_changes = ProcessTicketBasics( ARGSRef => \%ARGS, TicketObj => $TicketObj );
my @links_changes = ProcessTicketLinks( ARGSRef => \%ARGS, TicketObj => $TicketObj );
my @dates_changes = ProcessTicketDates( ARGSRef => \%ARGS, TicketObj => $TicketObj );
my @cfs_changes = ProcessObjectCustomFieldUpdates( ARGSRef => \%ARGS, Object => $TicketObj );
my @reminders_changes = ProcessTicketReminders( ARGSRef => \%ARGS, TicketObj => $TicketObj );

push @events, 'ticketOwnerChanged' if @owner_changes;
push @events, 'ticketMessageChanged' if @message_changes;
push @events, 'ticketWatchersChanged' if @watchers_changes;
push @events, 'ticketBasicsChanged' if @basics_changes;
push @events, 'ticketLinksChanged' if @links_changes;
push @events, 'ticketDatesChanged' if @dates_changes;
push @events, 'ticketCustomFieldsChanged' if @cfs_changes;
push @events, 'ticketRemindersChanged' if @reminders_changes;

push @Actions, @owner_changes, @message_changes, @watchers_changes, @basics_changes, @links_changes, @dates_changes,
@cfs_changes, @reminders_changes;

for my $txn (@{ $TicketObj->{_TransactionBatch} || [] }) {
if ( $txn->Type eq 'Set' ) {
push @events, 'ticket' . $txn->Field . 'Changed';
if ( $txn->Field eq 'Queue' ) {
push @events, 'reloadRequired';
}
}
elsif ( $txn->Type eq 'CustomField' ) {
push @events, 'customField-' . $txn->Field . 'Changed';
}
elsif ( $txn->Type eq 'AddLink' ) {
if ( $txn->Field eq 'MergedInto' ) {
push @events, 'reloadRequired';
}
}
}

$m->callback(
CallbackName => 'AfterProcessArguments',
Ticket => $TicketObj,
ARGSRef => \%ARGS,
Actions => \@Actions,
Events => \@events,
);

$r->headers_out->{'HX-Trigger'} = JSON(
{
actionsChanged => \@Actions,
map { $_ => '' } @events
},
utf8 => 1,
) if @events || @Actions;

</%INIT>
6 changes: 5 additions & 1 deletion share/html/Ticket/Display.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,18 @@
%# END BPS TAGGED BLOCK }}}
<& /Elements/Header,
Title => $title,
TitleTrigger => 'ticketSubjectChanged from:body',
TitleSource => RT->Config->Get('WebPath') . '/Views/Ticket/Title?id=' . $TicketObj->Id,
LinkRel => \%link_rel &>
<& /Elements/Tabs &>

% $m->callback(CallbackName => 'BeforeActionList', %ARGS, Actions => \@Actions, ARGSRef => \%ARGS, Ticket => $TicketObj);

<& /Elements/ListActions, actions => \@Actions &>
<& Elements/ShowUpdateStatus, Ticket => $TicketObj &>
<& Elements/ShowDependencyStatus, Ticket => $TicketObj &>
<div hx-trigger="ticketLinksChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Ticket/ShowDependencyStatus?id=<% $TicketObj->id %>">
<& Elements/ShowDependencyStatus, Ticket => $TicketObj &>
</div>

% $m->callback( %ARGS, Ticket => $TicketObj, Transactions => $transactions, Attachments => $attachments, CallbackName => 'BeforeShowSummary' );

Expand Down
4 changes: 3 additions & 1 deletion share/html/Ticket/Elements/EditDates
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@
</div>
</div>
</&>
<& /Elements/EditCustomFields, Object => $TicketObj, Grouping => 'Dates', InTable => 1 &>
<div class="edit-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/EditCustomFields?ObjectType=RT::Ticket&ObjectId=<% $TicketObj->Id %>&Grouping=Dates&InTable=1" hx-swap="innerHTML">
<& /Elements/EditCustomFields, Object => $TicketObj, Grouping => 'Dates', InTable => 1 &>
</div>
% $m->callback( %ARGS, CallbackName => 'EndOfList', Ticket => $TicketObj );
</div>
<%ARGS>
Expand Down
4 changes: 3 additions & 1 deletion share/html/Ticket/Elements/EditPeopleInline
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,9 @@

<& AddWatchers, Ticket => $Ticket, ShowLabel => 0 &>

<& /Elements/EditCustomFields, Object => $Ticket, Grouping => 'People', InTable => 1 &>
<div class="edit-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/EditCustomFields?ObjectType=RT::Ticket&ObjectId=<% $Ticket->Id %>&Grouping=People&InTable=1" hx-swap="innerHTML">
<& /Elements/EditCustomFields, Object => $Ticket, Grouping => 'People', InTable => 1 &>
</div>

<%ARGS>
$Ticket => undef
Expand Down
9 changes: 6 additions & 3 deletions share/html/Ticket/Elements/ShowAssets
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ $m->callback(
title_class => "inverse",
&>

<form action="<% RT->Config->Get("WebPath") %>/Ticket/Display.html" method="POST" enctype="multipart/form-data">
<div hx-trigger="ticketLinksChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Ticket/ShowAssets?id=<% $Ticket->id %>" hx-swap="innerHTML">

<form hx-post="<% RT->Config->Get("WebPath") %>/Helpers/TicketUpdate" hx-swap="none" enctype="multipart/form-data">
<input type="hidden" name="id" value="<% $Ticket->id %>">

% $m->callback( CallbackName => "Start", Ticket => $Ticket, Assets => $assets );
Expand Down Expand Up @@ -153,12 +155,12 @@ if ($Ticket->CurrentUserHasRight("ModifyTicket")) {
for @{ $bases->ItemsArrayRef };

my $delete_url = RT->Config->Get("WebPath")
. "/Ticket/Display.html?"
. "/Helpers/TicketUpdate?"
. $m->comp("/Elements/QueryString", id => $Ticket->id, %params);
</%perl>

<div class="unlink-asset">
<a href="<% $delete_url %>" class="unlink-asset button btn btn-primary"><% loc('Unlink') %></a>
<a href="#" hx-post="<% $delete_url %>" hx-trigger="click" hx-swap="none" class="unlink-asset button btn btn-primary"><% loc('Unlink') %></a>
</div>

% }
Expand Down Expand Up @@ -229,4 +231,5 @@ if ($ShowRelatedTickets) {

</form>

</div>
</&>
5 changes: 5 additions & 0 deletions share/html/Ticket/Elements/ShowBasics
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,14 @@
<& /Elements/LabeledValue, Class =>"queue",Label => loc("Queue"), ValueSpanClass => "current-value", RawValue => $m->scomp("ShowQueue", Ticket => $Ticket, QueueObj => $Ticket->QueueObj) &>
% }
% $m->callback( %ARGS, CallbackName => 'AfterQueue', TicketObj => $Ticket );

<div class="show-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/ShowCustomFields?ObjectType=RT::Ticket&ObjectId=<% $Ticket->Id %>&Grouping=Basics">
<& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Grouping => 'Basics', Table => 0 &>
</div>
% if ($UngroupedCFs) {
<div class="show-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/ShowCustomFields?ObjectType=RT::Ticket&ObjectId=<% $Ticket->Id %>&Grouping=">
<& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Grouping => '', Table => 0 &>
</div>
% }
% $m->callback( %ARGS, CallbackName => 'EndOfList', TicketObj => $Ticket );
</div>
Expand Down
6 changes: 5 additions & 1 deletion share/html/Ticket/Elements/ShowDates
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@
% }
</div>
% $m->callback( %ARGS, CallbackName => 'AfterUpdated', TicketObj => $Ticket );
<& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Grouping => 'Dates', Table => 0 &>

<div class="show-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/ShowCustomFields?ObjectType=RT::Ticket&ObjectId=<% $Ticket->Id %>&Grouping=Dates&Table=0">
<& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Grouping => 'Dates', Table => 0 &>
</div>

% $m->callback( %ARGS, CallbackName => 'EndOfList', TicketObj => $Ticket );
</div>
<%ARGS>
Expand Down
4 changes: 3 additions & 1 deletion share/html/Ticket/Elements/ShowPeople
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,9 @@
</div>
% }

<& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Grouping => 'People', Table => 0 &>
<div class="show-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/ShowCustomFields?ObjectType=RT::Ticket&ObjectId=<% $Ticket->Id %>&Grouping=People&Table=0">
<& /Ticket/Elements/ShowCustomFields, Ticket => $Ticket, Grouping => 'People', Table => 0 &>
</div>
</div>
<%ARGS>
$Ticket => undef
Expand Down
32 changes: 20 additions & 12 deletions share/html/Ticket/Elements/ShowSummary
Original file line number Diff line number Diff line change
Expand Up @@ -69,15 +69,17 @@ my $modify_behavior = $InlineEdit ? ($inline_edit_behavior{Basics} || $inline_ed
data => { 'inline-edit-behavior' => $modify_behavior },
&>
% unless ($modify_behavior eq 'always') {
<div class="inline-edit-display">
<div class="inline-edit-display" hx-trigger="ticketBasicsChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Ticket/ShowBasics?id=<% $Ticket->id %>">
<& /Ticket/Elements/ShowBasics, Ticket => $Ticket &>
</div>
% }
% if ($modify_behavior ne 'hide') {
<form class="inline-edit" action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" method="post" enctype="multipart/form-data">
<form hx-post="<%RT->Config->Get('WebPath')%>/Helpers/TicketUpdate" hx-swap="none" class="inline-edit" enctype="multipart/form-data">
<input type="hidden" class="hidden" name="id" value="<% $Ticket->id %>" />
<& /Ticket/Elements/EditBasics, TicketObj => $Ticket, InTable => 1, ExcludeOwner => 1, ExcludeCustomRoles => 1 &>
<& /Elements/EditCustomFields, Object => $Ticket, Grouping => 'Basics', InTable => 1 &>
<div class="edit-custom-fields-container" hx-trigger="none" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/EditCustomFields?ObjectType=RT::Ticket&ObjectId=<% $Ticket->Id %>&Grouping=Basics&InTable=1" hx-swap="innerHTML">
<& /Elements/EditCustomFields, Object => $Ticket, Grouping => 'Basics', InTable => 1 &>
</div>
<div class="row mt-2">
<div class="col-12 text-end">
<input type="submit" class="button btn btn-primary" value="<&|/l&>Save</&>" />
Expand Down Expand Up @@ -105,14 +107,16 @@ my $people_behavior = $InlineEdit ? ($inline_edit_behavior{People} || $inline_ed
data => { 'inline-edit-behavior' => $people_behavior },
&>
% unless ($people_behavior eq 'always') {
<div class="inline-edit-display">
<div class="inline-edit-display" hx-trigger="ticketWatchersChanged from:body, ticketOwnerChanged from:body" hx-get="<%RT->Config->Get('WebPath')%>/Views/Ticket/ShowPeople?id=<% $Ticket->id %>">
<& /Ticket/Elements/ShowPeople, Ticket => $Ticket &>
</div>
% }
% if ($people_behavior ne 'hide') {
<form class="inline-edit" action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" method="post" enctype="multipart/form-data">
<form hx-post="<% RT->Config->Get('WebPath') %>/Helpers/TicketUpdate" hx-swap="none" class="inline-edit" enctype="multipart/form-data">
<input type="hidden" class="hidden" name="id" value="<% $Ticket->id %>" />
<& /Ticket/Elements/EditPeopleInline, Ticket => $Ticket &>
<div hx-trigger="ticketWatchersChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Ticket/EditPeopleInline?id=<% $Ticket->id %>" hx-swap="innerHTML">
<& /Ticket/Elements/EditPeopleInline, Ticket => $Ticket &>
</div>
<div class="row mt-2">
<div class="col-12 text-end">
<input type="submit" class="button btn btn-primary" value="<&|/l&>Save</&>" />
Expand All @@ -135,8 +139,10 @@ my $people_behavior = $InlineEdit ? ($inline_edit_behavior{People} || $inline_ed
title_href => RT->Config->Get('WebPath')."/Ticket/Reminders.html?id=".$Ticket->Id,
class => 'ticket-info-reminders fullwidth',
&>
<form action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" name="UpdateReminders" id="UpdateReminders" method="post">
<form hx-post="<% RT->Config->Get('WebPath') %>/Helpers/TicketUpdate" hx-swap="none" name="UpdateReminders" id="UpdateReminders">
<div hx-trigger="ticketRemindersChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Ticket/Reminders?ShowCompleted=0&id=<% $Ticket->id %>" hx-swap="innerHTML">
<& /Ticket/Elements/Reminders, Ticket => $Ticket, ShowCompleted => 0 &>
</div>
</form>
</&>
% }
Expand All @@ -155,12 +161,12 @@ my $dates_behavior = $InlineEdit ? ($inline_edit_behavior{Dates} || $inline_edit
data => { 'inline-edit-behavior' => $dates_behavior },
&>
% unless ($dates_behavior eq 'always') {
<div class="inline-edit-display">
<div class="inline-edit-display" hx-trigger="actionsChanged from:body, ticketDatesChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Ticket/ShowDates?id=<% $Ticket->id %>">
<& /Ticket/Elements/ShowDates, Ticket => $Ticket &>
</div>
% }
% if ($dates_behavior ne 'hide') {
<form class="inline-edit" action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" method="post" enctype="multipart/form-data">
<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="<% $Ticket->id %>" />
<& /Ticket/Elements/EditDates, TicketObj => $Ticket &>
<div class="row mt-2">
Expand Down Expand Up @@ -201,14 +207,16 @@ push @extra, (titleright_raw => $links_titleright) if $links_titleright;
@extra,
&>
% unless ($links_behavior eq 'always') {
<div class="inline-edit-display">
<div class="inline-edit-display" hx-trigger="ticketLinksChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/ShowLinks?ObjectType=RT::Ticket&ObjectId=<% $Ticket->id %>">
<& /Elements/ShowLinks, Object => $Ticket &>
</div>
% }
% if ($links_behavior ne 'hide') {
<form class="inline-edit" action="<%RT->Config->Get('WebPath')%>/Ticket/Display.html" method="post" enctype="multipart/form-data">
<input type="hidden" class="hidden" name="id" value="<% $Ticket->id %>" />
<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="<% $Ticket->id %>" />
<div hx-trigger="ticketLinksChanged from:body" hx-get="<% RT->Config->Get('WebPath') %>/Views/Component/EditLinks?ObjectType=RT::Ticket&ObjectId=<% $Ticket->id %>&TwoColumn=0" hx-swap="innerHTML">
<& /Elements/EditLinks, Object => $Ticket, TwoColumn => 0 &>
</div>

<h3><&|/l&>Merge</&></h3>
<& /Ticket/Elements/EditMerge, Ticket => $Ticket, MergeTextClass => '', %ARGS &>
Expand Down
7 changes: 7 additions & 0 deletions share/html/Views/Component/dhandler
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ if ( $component_name eq 'SavedSearch' ) {
}
}
}
elsif ( $ARGS{ObjectType} && $ARGS{ObjectType}->can('Load') && $ARGS{ObjectId} ) {
my $object = $ARGS{ObjectType}->new( $session{CurrentUser} );
$object->Load( $ARGS{ObjectId} );
if ( $object->CurrentUserCanSee ) {
$ARGS{Object} = $object;
}
}
</%init>
<%args>
</%args>
Loading

0 comments on commit e6978b8

Please sign in to comment.