From 094af3906db14827b0d3c205aa39b30b65fadb4d Mon Sep 17 00:00:00 2001 From: Alexander Heldt Date: Sun, 12 Jul 2026 17:29:32 +0000 Subject: [PATCH] Show a changelog in the update banner changelog.json is a hand-maintained, newest-first list of user-visible changes; it is part of the SW asset cache and the build hash, so even a changelog-only edit rolls a new version. When the update banner appears, the app fetches changelog.json twice: the plain URL is answered cache-first by the old controlling worker (the running build's copy) while a cache-busting query bypasses every SW cache and hits the network (the waiting build's copy). Entries the fresh copy has that the cached one lacks are exactly what the update brings, and are listed under the banner message. --- server/main.go | 2 +- src/app.js | 35 +++++++++++++++++++++++++++++++++++ src/changelog.json | 5 +++++ src/index.html | 15 ++++++++++----- src/style.css | 21 ++++++++++++++++----- src/sw.js | 1 + 6 files changed, 68 insertions(+), 11 deletions(-) create mode 100644 src/changelog.json diff --git a/server/main.go b/server/main.go index 9452812..ec8636c 100644 --- a/server/main.go +++ b/server/main.go @@ -517,7 +517,7 @@ func newSWVersion(dir string) *swVersion { // circular and it never changes except when we edit it here. return &swVersion{ dir: dir, - files: []string{"index.html", "style.css", "app.js", "manifest.json", "icon.svg"}, + files: []string{"index.html", "style.css", "app.js", "manifest.json", "icon.svg", "changelog.json"}, } } diff --git a/src/app.js b/src/app.js index 85f2250..3a47709 100644 --- a/src/app.js +++ b/src/app.js @@ -2149,9 +2149,44 @@ location.reload(); }); + // What the waiting build changes compared to the running one. The plain + // URL is answered by the *old* controlling worker cache-first, i.e. the + // loaded build's changelog; the cache-busting query misses every SW cache + // and hits the network, i.e. the new build's changelog. Entries in the + // fresh copy that the cached one lacks are exactly "new since this build". + async function changelogDiff() { + const load = async (url) => { + try { + const res = await fetch(url); + if (!res.ok) return null; + const body = await res.json(); + return Array.isArray(body) ? body : null; + } catch { + return null; + } + }; + const current = await load("changelog.json"); + const fresh = await load(`changelog.json?v=${Date.now()}`); + if (!fresh) return []; + const seen = new Set((current || []).map(e => e && e.text)); + return fresh.filter(e => e && e.text && !seen.has(e.text)); + } + function showUpdateBanner(worker) { waitingWorker = worker; updateBanner.hidden = false; + const list = document.getElementById("update-changelog"); + list.hidden = true; + list.innerHTML = ""; + changelogDiff().then(entries => { + if (entries.length === 0) return; + for (const e of entries.slice(0, 6)) { + const li = document.createElement("li"); + li.textContent = e.text; + list.appendChild(li); + } + list.hidden = false; + }); } updateReload.addEventListener("click", () => { diff --git a/src/changelog.json b/src/changelog.json new file mode 100644 index 0000000..a7904ce --- /dev/null +++ b/src/changelog.json @@ -0,0 +1,5 @@ +[ + { "date": "2026-07-12", "text": "The update banner now lists what changed in the new version" }, + { "date": "2026-07-12", "text": "Fixed adding an exercise on iPhone: stale app updates, and the keyboard's Go key discarding the input" }, + { "date": "2026-07-12", "text": "Training: define exercises with how-to reminders, log sessions in one tap, and follow a 14-day consistency view" } +] diff --git a/src/index.html b/src/index.html index a4db13b..94779ad 100644 --- a/src/index.html +++ b/src/index.html @@ -25,11 +25,16 @@ it and refreshes onto the new assets; "Later" dismisses until next time. Suppressed on the very first install (see app.js). -->