Web pages re-render only when their data changes

The newer pages rebuilt innerHTML on every poll, which re-renders every
<img> (the visible blink on Photos) and wiped the pipeline page's limit
field between polls. Every page now snapshots its payload and skips
identical renders — the guard the review page always had.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-02 17:37:48 -04:00
parent 189c534315
commit 16003ee39f
5 changed files with 27 additions and 3 deletions
+4
View File
@@ -39,8 +39,12 @@ function render() {
: `Nothing extracted yet — start on the <a href="/photos">photos page</a>.`}</p>`; : `Nothing extracted yet — start on the <a href="/photos">photos page</a>.`}</p>`;
} }
let LAST = null;
async function refresh() { async function refresh() {
const state = await fetchJSON("/api/state"); const state = await fetchJSON("/api/state");
const payload = JSON.stringify(state.catalog);
if (payload === LAST) return;
LAST = payload;
CATALOG = state.catalog; CATALOG = state.catalog;
render(); render();
} }
+6 -1
View File
@@ -45,8 +45,13 @@ function render() {
Run the pipeline through <code>enrich</code> to fill these shelves.`}</p>`; Run the pipeline through <code>enrich</code> to fill these shelves.`}</p>`;
} }
let LAST = null;
async function refresh() { async function refresh() {
GAMES = await fetchJSON("/api/library"); const games = await fetchJSON("/api/library");
const payload = JSON.stringify(games);
if (payload === LAST) return;
LAST = payload;
GAMES = games;
render(); render();
} }
+5
View File
@@ -59,11 +59,16 @@ function render(state, photos) {
</figure>`).join(""); </figure>`).join("");
} }
let LAST = null;
async function refresh() { async function refresh() {
const [state, photos] = await Promise.all([ const [state, photos] = await Promise.all([
fetchJSON("/api/state"), fetchJSON("/api/state"),
fetchJSON("/api/photos-list"), fetchJSON("/api/photos-list"),
]); ]);
// re-render only on change: rebuilding innerHTML re-renders every <img>
const payload = JSON.stringify([state.unidentified, state.warnings, photos]);
if (payload === LAST) return;
LAST = payload;
render(state, photos); render(state, photos);
} }
+6 -1
View File
@@ -78,8 +78,13 @@ function render() {
if (atBottom) logEl.scrollTop = logEl.scrollHeight; if (atBottom) logEl.scrollTop = logEl.scrollHeight;
} }
let LAST = null;
async function refresh() { async function refresh() {
P = await fetchJSON("/api/pipeline"); const p = await fetchJSON("/api/pipeline");
const payload = JSON.stringify(p);
if (payload === LAST) return;
LAST = payload;
P = p;
render(); render();
} }
+6 -1
View File
@@ -43,8 +43,13 @@ function render(q) {
document.getElementById("queuebody").innerHTML = html; document.getElementById("queuebody").innerHTML = html;
} }
let LAST = null;
async function refresh() { async function refresh() {
render(await fetchJSON("/api/queue")); const q = await fetchJSON("/api/queue");
const payload = JSON.stringify(q);
if (payload === LAST) return;
LAST = payload;
render(q);
} }
refresh().catch(err => errorBanner(err.message || err)); refresh().catch(err => errorBanner(err.message || err));