From 5fe82b24896fa56d1db77c47dd37c9fcfb1385bc Mon Sep 17 00:00:00 2001
From: soyalejolopez <88358406+soyalejolopez@users.noreply.github.com>
Date: Thu, 23 Jul 2026 16:34:48 -0500
Subject: [PATCH] Fix giscus like button not persisting first reaction (#1312)
The report detail page embeds giscus for likes. On resources with no backing Discussion yet, the first reaction hit giscus bug #1312: giscus creates the discussion and adds the reaction server-side but never refetches, so the like visually reverts until a manual refresh.
Fix the existing workaround so the remount reliably fires:
- Event-driven remount: track whether a discussion existed at mount time and remount once when metadata reports it was just created by the user's reaction.
- Remove the self-defeating hasDiscussion re-check from the blur-timer callback (it cancelled the very remount meant to persist the like).
- Re-arm recovery when a speculative (blur-triggered) refetch finds no discussion, so a later genuine first reaction can still stick.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 61593e5a-6c5f-46eb-bb43-08ee66fce301
---
index.html | 39 +++++++++++++++++++++++++++++++++++----
1 file changed, 35 insertions(+), 4 deletions(-)
diff --git a/index.html b/index.html
index 329a4f8..610de38 100644
--- a/index.html
+++ b/index.html
@@ -2334,7 +2334,13 @@
Browse all 54 scripts →
// fails to refetch, so the 👍 visually "reverts". We detect that the discussion
// does not exist yet (via emit-metadata) and, once the user interacts, re-mount
// giscus to pull the freshly-created discussion + reaction so it sticks.
- const giscusState = { slug: null, hasDiscussion: false, refetched: false, pendingTimer: null };
+ // existedAtMount: whether a backing discussion already existed the first time
+ // giscus reported metadata for the current slug (null = not yet known). It lets us
+ // tell a pre-existing discussion apart from one the user just created by reacting.
+ // speculativeRefetch: true when the current refetch was triggered by iframe focus
+ // (blur fallback) rather than an observed discussion creation, so we can re-arm if
+ // it turns out no discussion was actually created.
+ const giscusState = { slug: null, hasDiscussion: false, refetched: false, existedAtMount: null, speculativeRefetch: false, pendingTimer: null };
function giscusClearPending() {
if (giscusState.pendingTimer) { clearTimeout(giscusState.pendingTimer); giscusState.pendingTimer = null; }
@@ -2351,6 +2357,8 @@ Browse all 54 scripts →
} else {
giscusState.hasDiscussion = false;
giscusState.refetched = false;
+ giscusState.existedAtMount = null;
+ giscusState.speculativeRefetch = false;
}
const script = document.createElement('script');
script.src = "https://giscus.app/client.js";
@@ -2380,7 +2388,25 @@ Browse all 54 scripts →
const payload = event.data && event.data.giscus;
if (!payload || !('discussion' in payload)) return;
const d = payload.discussion;
- giscusState.hasDiscussion = !!(d && d.id);
+ const exists = !!(d && d.id);
+ giscusState.hasDiscussion = exists;
+ // Record whether a discussion already existed the first time giscus reported in.
+ // Kept as a standalone `if` (not part of the chain below) so the re-arm branch can
+ // still run on the same message even when this is the first metadata we receive.
+ if (giscusState.existedAtMount === null) {
+ giscusState.existedAtMount = exists;
+ }
+ if (exists && giscusState.existedAtMount === false && !giscusState.refetched) {
+ // The discussion just came into existence — the user's first reaction created it
+ // (#1312). giscus won't refetch on its own, so remount once to make the 👍 stick.
+ giscusState.speculativeRefetch = false;
+ mountGiscus(giscusState.slug, document.documentElement.getAttribute('data-theme'), true);
+ } else if (!exists && giscusState.refetched && giscusState.speculativeRefetch) {
+ // A blur-triggered (speculative) refetch happened but there is still no discussion,
+ // so it was "wasted" (the iframe focus was a sign-in/comment, not a reaction).
+ // Re-arm recovery so a later genuine first reaction can still be refetched.
+ giscusState.refetched = false;
+ }
});
// When the user clicks into the giscus iframe (e.g. to react) on a resource that
@@ -2394,9 +2420,14 @@ Browse all 54 scripts →
if (!giscusState.slug || giscusState.hasDiscussion || giscusState.refetched || giscusState.pendingTimer) return;
giscusState.pendingTimer = setTimeout(() => {
giscusState.pendingTimer = null;
- if (!giscusState.slug || giscusState.hasDiscussion || giscusState.refetched) return;
+ // Do NOT re-check hasDiscussion here: by now the reaction may have (just) created
+ // the discussion, which is exactly the case that needs a refetch. A remount is
+ // harmless (it only refetches current server state) and must fire so the 👍 sticks.
+ // Mark it speculative so we re-arm if it turns out no discussion was created.
+ if (!giscusState.slug || giscusState.refetched) return;
+ giscusState.speculativeRefetch = true;
mountGiscus(giscusState.slug, document.documentElement.getAttribute('data-theme'), true);
- }, 2500);
+ }, 3000);
}, 0);
});