Skip to content

Commit 3b0e5f7

Browse files
committed
Make "Jump to Unread" links work with paginated history
When a URL contains an anchor referencing a transaction like #txn-123, RT will now automatically locate the history page containing transaction #123 and navigate to the appropriate page.
1 parent f4d159a commit 3b0e5f7

File tree

6 files changed

+60
-11
lines changed

6 files changed

+60
-11
lines changed

share/html/Elements/RT__Ticket/ColumnMap

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,8 @@ $COLUMN_MAP = {
419419

420420
my $link = RT->Config->Get('WebPath');
421421
$link .= $session{'CurrentUser'}->Privileged ? '/Ticket/Display.html?id=' : '/SelfService/Display.html?id=';
422-
$link .= $self->id . '&MarkAsSeen=1&ShowHistory=1&Anchor=txn-' . $first_unread->id;
422+
$link .= $self->id . '&MarkAsSeen=1&Anchor=txn-' . $first_unread->id;
423+
$link .= '&ForceShowHistory=1' if RT->Config->Get( 'ShowHistory', $session{'CurrentUser'} ) eq 'click';
423424

424425
my $title = loc("Jump to Unread & Mark as Seen");
425426
return \( '<a data-bs-toggle="tooltip" data-bs-title="' . $title . '" href="' . $link . '"><b>' ),

share/html/Elements/ShowHistoryHeader

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ $SingleTransaction => 0
5555
$Title => loc('History')
5656
$FilterURL => ''
5757
$FilterTarget => ''
58-
$ShowHistory => ''
58+
$ShowHistory => $ScrollShowHistory ? 'scroll' : RT->Config->Get( 'ShowHistory', $session{CurrentUser} )
5959
</%ARGS>
6060
<%INIT>
6161
my $record_type = $Object->RecordType;
@@ -81,7 +81,7 @@ $FilterURL ||= RT->Config->Get('WebPath')
8181

8282
$FilterTarget ||= "#$container_id";
8383
</%INIT>
84-
<div class="history <% lc $record_type %>" id="<% $histid %>">
84+
<div class="history <% lc $record_type %>" id="<% $histid %>" data-history-mode="<% $ShowHistory %>">
8585
<%perl>
8686

8787
my $oldestTransactionsFirst;
@@ -214,6 +214,7 @@ if ( $ShowDisplayModes or $ShowTitle or $ScrollShowHistory ) {
214214
if ( $ShowHistory eq 'page' ) {
215215
$titleright .= qq{<input type="hidden" name="ShowPagination" value="1">};
216216
$titleright .= qq{<input type="hidden" name="Page" value="1">};
217+
$titleright .= qq{<input type="hidden" name="focusTransactionId" value="">};
217218
if ( $ARGS{PerPage} ) {
218219
$titleright .= qq{<input type="hidden" name="PerPage" value="$ARGS{PerPage}">};
219220
}

share/html/Helpers/TicketHistoryPage

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,21 @@ if ($ShowPagination && defined $Page) {
147147
# Apply pagination to collection (RT uses 0-based page indexing internally)
148148
$transactions->RowsPerPage($PerPage);
149149
$transactions->GotoPage($Page - 1);
150+
151+
# Auto jump to the page that contains specified txn
152+
if ($focusTransactionId) {
153+
my $auto_page = $Page;
154+
while ( !grep { $focusTransactionId == $_->Id } @{ $transactions->ItemsArrayRef || [] } ) {
155+
$auto_page++;
156+
$transactions->GotoPage( $auto_page - 1 );
157+
if ( $auto_page > $total_pages ) {
158+
RT->Logger->debug("Couldn't find transaction #$focusTransactionId");
159+
undef $auto_page;
160+
last;
161+
}
162+
}
163+
$Page = $auto_page if $auto_page;
164+
}
150165
} elsif ($focusTransactionId) { # make sure we load enough if we need to focus a transaction
151166
$transactions->Limit(
152167
FIELD => 'id',
@@ -172,7 +187,8 @@ if ($ShowPagination && defined $Page) {
172187

173188
# Add pagination controls if there are multiple pages
174189
if ($total_pages > 1) {
175-
my %url_params = map { $_ => $ARGS{$_} } grep { defined $ARGS{$_} && !blessed $ARGS{$_} } keys %ARGS;
190+
my %url_params = map { $_ => $ARGS{$_} }
191+
grep { defined $ARGS{$_} && !blessed $ARGS{$_} && $_ ne 'focusTransactionId' } keys %ARGS;
176192
$url_params{ShowPagination} = 1;
177193

178194
my $base_url = RT->Config->Get('WebPath') . "/Helpers/TicketHistoryPage";

share/html/Ticket/Elements/PagedShowHistory

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ my %params = (
5353
PerPage => $ARGS{PerPage} || 10,
5454
Page => $ARGS{Page} || 1,
5555
id => $Ticket->id,
56+
( RT::Interface::Web::RequestENV('HTTP_HX_CURRENT_URL') // '' ) =~ m{#txn-(\d+)$}
57+
&& !$ARGS{Page} ? ( focusTransactionId => $1 ) : (),
5658
);
5759

5860
my $url = RT->Config->Get('WebPath') . "/Helpers/TicketHistoryPage?" .

share/html/Ticket/Elements/ShowUpdateStatus

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757
% my $ShowHistory = RT->Config->Get( 'ShowHistory', $session{'CurrentUser'} );
5858
% my $url = RT->Config->Get('WebPath') . "/$DisplayPath/Display.html?id=" . $Ticket->id;
5959
% if ( $ShowHistory eq 'click' ) {
60-
% $url .= '&ShowHistory=1';
60+
% $url .= '&ForceShowHistory=1';
6161
% }
6262
<a
6363
% if ( RT::Interface::Web::RequestENV('REQUEST_URI') eq $url ) { # URL doesn't change, no need to reload
@@ -67,7 +67,7 @@
6767
<div class="d-sm-none mt-1"></div>
6868
<a class="btn btn-primary btn-sm" href="<% RT->Config->Get('WebPath') ."/$DisplayPath/Display.html?id=". $Ticket->id. "&MarkAsSeen=1" |n %>"><&|/l&>Mark as Seen</&></a>
6969
<div class="d-sm-none mt-1"></div>
70-
<a class="btn btn-primary btn-sm" href="<% RT->Config->Get('WebPath') ."/$DisplayPath/Display.html?id=". $Ticket->id ."&MarkAsSeen=1&ShowHistory=1&Anchor=txn-" . $txn->id |n %>"><&|/l&>Jump & Mark as Seen</&></a>
70+
<a class="btn btn-primary btn-sm" href="<% $url . '&MarkAsSeen=1&Anchor=txn-' . $txn->id |n %>"><&|/l&>Jump & Mark as Seen</&></a>
7171
</span>
7272
</div>
7373
</div>

share/static/js/init.js

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -704,10 +704,17 @@ document.addEventListener('htmx:load', function(evt) {
704704
elem.change( trigger_func );
705705
});
706706

707-
if (window.location.hash.match(/#txn-\d+$/)) {
708-
revealHistoryWidget();
709-
}
707+
if (window.location.hash) {
708+
const hash = window.location.hash;
709+
if (hash.match(/#txn-\d+$/)) {
710+
revealHistoryWidget();
711+
}
710712

713+
// Automatically scroll to the specified element
714+
if (elt.querySelector(hash) || elt.querySelector('[name="' + hash.substring(1) + '"]')) {
715+
location.href = location.href;
716+
}
717+
}
711718

712719
/* inline edit on ticket display */
713720
jQuery('.titlebox[data-inline-edit-behavior="link"], .titlebox[data-inline-edit-behavior="click"]').each(function() {
@@ -933,8 +940,30 @@ jQuery(document).on('click', 'a.search-filter', function (e) {
933940
});
934941

935942
// Automatically reveal history widget so anchor links like #txn-586 can work
936-
jQuery(document).on('click', 'a.jump-to-unread', function () {
937-
revealHistoryWidget();
943+
jQuery(document).on('click', 'a.jump-to-unread', function (evt) {
944+
const widget = document.querySelector('.htmx-load-widget[hx-get$="/Widgets/Display/History"]');
945+
if (widget) {
946+
const history_mode = widget.querySelector('[data-history-mode]')?.getAttribute('data-history-mode');
947+
// For paginated history, we need to reload widget if the specified txn is not on current page
948+
if ( history_mode === 'page' && widget.getAttribute('data-hx-revealed') === 'true' ) {
949+
const matched = evt.target.getAttribute('href').match(/#(txn-(\d+))$/);
950+
if ( matched && !document.querySelector('[name="' + matched[1] + '"]') ) {
951+
// Update location first so widget can retrieve the txn id from hash in URL
952+
location.href = evt.target.getAttribute('href');
953+
const filter_form = widget.querySelector('form.transaction-filter-form');
954+
if (filter_form) {
955+
filter_form.querySelector('input[name=focusTransactionId]').value = matched[2];
956+
htmx.trigger(filter_form, 'submit');
957+
setTimeout(function() {
958+
filter_form.querySelector('input[name=focusTransactionId]').value = '';
959+
}, 100);
960+
}
961+
}
962+
}
963+
else {
964+
revealHistoryWidget();
965+
}
966+
}
938967
});
939968

940969
// Clip content

0 commit comments

Comments
 (0)