From 4d16c6ea337d7edad99a24be6054410ee76e490e Mon Sep 17 00:00:00 2001 From: Jerome Lefeuvre Date: Thu, 23 Jul 2026 18:54:34 -0400 Subject: [PATCH] fix(qbittorrent): guard against stale pagination responses MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit refreshData() aborts the previous in-flight fetch before firing a new one, but abort() is a no-op once a response has already arrived — common on localhost, where the round-trip can beat the click-to-JS-execution delay. A periodic poll response for the old page could then land after a user's page-change click and silently snap the view back to the previous page. Add a sequence counter so a response is only applied if no newer request has been issued since, regardless of whether abort() worked. Co-Authored-By: Claude Sonnet 5 --- symfony/templates/qbittorrent/index.html.twig | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/symfony/templates/qbittorrent/index.html.twig b/symfony/templates/qbittorrent/index.html.twig index 0c7b1001..0ce633b7 100644 --- a/symfony/templates/qbittorrent/index.html.twig +++ b/symfony/templates/qbittorrent/index.html.twig @@ -1212,10 +1212,17 @@ body[data-bs-theme="dark"] .qbt-torrent-list[data-view="table"] .qbt-cell-progre }); var refreshCtrl = null; + var refreshSeq = 0; function refreshData() { // Annule le fetch précédent s'il est encore en vol (évite empilement) if (refreshCtrl) refreshCtrl.abort(); refreshCtrl = new AbortController(); + // abort() n'a aucun effet si la réponse précédente est déjà arrivée + // (fréquent en local, où le round-trip peut être plus rapide que le + // délai clic → exécution JS) : sans ce numéro de séquence, une réponse + // de sondage périodique pour l'ancienne page peut s'appliquer APRÈS + // celle du clic sur une autre page, et y revenir juste après l'affichage. + var seq = ++refreshSeq; var q = new URLSearchParams({ page: pagState.page, perPage: pagState.perPage, @@ -1229,6 +1236,7 @@ body[data-bs-theme="dark"] .qbt-torrent-list[data-view="table"] .qbt-cell-progre fetch(BASE + '/api/torrents?' + q, { signal: refreshCtrl.signal, headers: { 'X-Requested-With': 'XMLHttpRequest' } }) .then(function(r) { return r.json(); }) .then(function(data) { + if (seq !== refreshSeq) return; // une requête plus récente a déjà été émise if (data.error) return; updateStats(data.stats); updateList(data.torrents);