diff --git a/.env.example b/.env.example index 4467e46..0efa430 100644 --- a/.env.example +++ b/.env.example @@ -30,9 +30,11 @@ CODEBERG_TOKEN= # Mit eingerichtetem Webhook (siehe unten) ist das nur noch das Sicherheitsnetz fuer # verpasste Zustellungen und darf gross bleiben - Issue-Aenderungen landen dann in Sekunden # auf dem Board, nicht erst beim naechsten Lauf. -# Speist ausserdem den rein kosmetischen Reload-Countdown im Header der Buero-Visualisierung -# (Service "web", siehe docker/nginx/default.conf.template) - der Countdown zaehlt nur mit, -# er loest selbst keinen echten Reload/Sync aus. +# Speist ausserdem den Reload-Countdown im Header der Buero-Visualisierung (Service "web", +# siehe docker/nginx/default.conf.template) - erreicht der Countdown 0, laedt der Browser die +# Seite tatsaechlich neu (Issue #108), damit ein dauerhaft offener Wand-Tab laengstens nach +# einem Intervall den aktuell deployten Frontend-Stand bekommt. Auf den periodischen +# Codeberg-Sync hat das keinen Einfluss, dafuer ist weiterhin allein das Backend zustaendig. MONITOR_SYNC_INTERVAL=600 # Secret des Codeberg-Webhooks (Repo -> Einstellungen -> Webhooks -> Forgejo, Ziel-URL diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9bfe24b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +Format in Anlehnung an [Keep a Changelog](https://keepachangelog.com/de/1.0.0/). + +## Unreleased + +- Reload-Countdown im Header der Buero-Visualisierung laedt die Seite bei 0 tatsaechlich neu, + statt nur kosmetisch herunterzuzaehlen - ein dauerhaft offener Wand-Tab bekommt dadurch + laengstens nach einem `MONITOR_SYNC_INTERVAL` den aktuell deployten Frontend-Stand + (#108). diff --git a/README.md b/README.md index e94ac03..049691e 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,11 @@ die dazugehörigen Klärungen in [Detailfragen.md](Detailfragen.md) und Agenten laufen animiert zwischen Schreibtisch/Board/Monitor-Wand/Kaffee-Ecke (Phase 3-5, siehe Visualization.md Abschnitt 9). Ist die API nicht erreichbar, zeigt die Szene ersatzweise Demo-Daten — kenntlich gemacht durch einen roten Banner „API nicht erreichbar!". - Die Basis-URL der API kommt aus `MONITOR_API_BASE` (siehe `.env.example`). + Die Basis-URL der API kommt aus `MONITOR_API_BASE` (siehe `.env.example`). Ein dauerhaft + offener Tab (z.B. auf einer Monitor-Wand) lädt sich spätestens alle `MONITOR_SYNC_INTERVAL` + Sekunden selbst neu (Reload-Countdown im Header, Issue #108), damit er immer den aktuell + deployten Frontend-Stand zeigt statt auf unbestimmte Zeit eine alte Version weiterlaufen zu + lassen. - Klick auf den PO öffnet ein Modal, in dem sich die vom Codeberg-Sync gelesenen Projekte (Owner/Repo + Farbe) hinzufügen, bearbeiten und löschen lassen (Issue #27) — Änderungen wirken sofort im laufenden `sync`-Dienst, ohne Neustart. Schreibende Aktionen fragen einmalig diff --git a/docker/nginx/default.conf.template b/docker/nginx/default.conf.template index dfb8435..50d550c 100644 --- a/docker/nginx/default.conf.template +++ b/docker/nginx/default.conf.template @@ -18,8 +18,9 @@ server { # definiert, bleibt ihr Platzhalter stehen und nginx verweigert den Start # ("unknown \"monitor_api_base\" variable") - besser ein lauter Fehler als eine still # falsche URL. docker-compose.yml setzt beide Variablen daher immer (ggf. mit Default). - # MONITOR_SYNC_INTERVAL speist nur den rein kosmetischen Reload-Countdown im Header - # (Issue #12) - hat keinen Einfluss auf den tatsaechlichen Update-Takt der Szene. + # MONITOR_SYNC_INTERVAL speist den Reload-Countdown im Header (Issue #12) - der laedt die + # Seite bei 0 tatsaechlich per location.reload() neu (Issue #108), hat aber keinen Einfluss + # auf den laufenden Update-Takt der Szene selbst (SSE/Polling, siehe office-render.js). location = /config.js { default_type application/javascript; add_header Cache-Control "no-store"; diff --git a/html/js/office-render.js b/html/js/office-render.js index eb013e2..ada1866 100644 --- a/html/js/office-render.js +++ b/html/js/office-render.js @@ -349,6 +349,7 @@ function renderPullRequestStripePattern() { width: 10, height: 10, patternUnits: "userSpaceOnUse", + patternTransform: "rotate(45)", }); pattern.appendChild(el("rect", { x: 0, y: 0, width: 10, height: 3, fill: "#000000" })); defs.appendChild(pattern); @@ -2537,9 +2538,12 @@ function setAgentProblemBanner(agents) { banner.classList.toggle("api-banner-warning", !expired && Boolean(expiring)); } -// Rein kosmetischer Countdown im Header (Issue #12): zaehlt unabhaengig vom tatsaechlichen -// SSE-/Polling-Takt von MONITOR_SYNC_INTERVAL (aus config.js, siehe office.html) auf 0 -// herunter und startet danach von vorn - loest selbst keinen Reload aus. +// Countdown im Header (Issue #12, seit Issue #108 mit echtem Reload): zaehlt unabhaengig vom +// tatsaechlichen SSE-/Polling-Takt von MONITOR_SYNC_INTERVAL (aus config.js, siehe office.html) +// auf 0 herunter und laedt die Seite dann per location.reload() neu, statt nur wieder von vorn +// zu zaehlen - ein dauerhaft offener Wand-Tab holt sich damit laengstens nach einem Intervall +// den aktuell deployten Frontend-Stand (sonst zeigt er auf unbestimmte Zeit die alte +// JS-Version weiter an, selbst wenn ein Fix laengst gemergt/deployt ist). function startReloadCountdown() { const countdownEl = document.getElementById("reload-countdown"); if (!countdownEl) { @@ -2551,7 +2555,12 @@ function startReloadCountdown() { countdownEl.textContent = `${remaining}s`; window.setInterval(() => { - remaining = nextCountdownSeconds(remaining, intervalSeconds); + const next = nextCountdownSeconds(remaining, intervalSeconds); + if (next === intervalSeconds) { + window.location.reload(); + return; + } + remaining = next; countdownEl.textContent = `${remaining}s`; }, 1000); } diff --git a/html/js/office-scene.js b/html/js/office-scene.js index 087b82b..703bbc0 100644 --- a/html/js/office-scene.js +++ b/html/js/office-scene.js @@ -1045,9 +1045,11 @@ export function advancePoVisitStage(stage) { } // --------------------------------------------------------------------------------------- -// Reload-Countdown im Header (Issue #12): rein kosmetischer Sekundenzaehler, der die -// Sync-Frequenz des Backends (MONITOR_SYNC_INTERVAL, siehe .env.example) im Header -// widerspiegelt - ohne selbst irgendetwas neu zu laden (siehe office-render.js). +// Reload-Countdown im Header (Issue #12, seit Issue #108 mit echtem Reload): Sekundenzaehler, +// der die Sync-Frequenz des Backends (MONITOR_SYNC_INTERVAL, siehe .env.example) im Header +// widerspiegelt - erreicht er 0, laedt office-render.js die Seite tatsaechlich neu, damit ein +// dauerhaft offener Wand-Tab laengstens nach einem Intervall den aktuell deployten +// Frontend-Stand bekommt. // --------------------------------------------------------------------------------------- export const DEFAULT_RELOAD_INTERVAL_SECONDS = 600; diff --git a/html/js/record.js b/html/js/record.js index 96f891d..42a464c 100644 --- a/html/js/record.js +++ b/html/js/record.js @@ -113,12 +113,16 @@ function stopRecording() { startButton.hidden = false; } -function discardRecording() { +function resetRecording() { recordedBlob = null; audioPreview.removeAttribute("src"); audioPreview.hidden = true; uploadButton.hidden = true; discardButton.hidden = true; +} + +function discardRecording() { + resetRecording(); setStatus("Aufnahme verworfen."); } @@ -133,8 +137,8 @@ async function upload() { const extension = (recordedBlob.type.split("/")[1] || "webm").split(";")[0]; try { await uploadRecording(recordedBlob, `aufnahme.${extension}`); - setStatus("Hochgeladen, danke!"); - discardRecording(); + resetRecording(); + setStatus("Aufnahme gespeichert, danke!"); } catch (error) { setStatus(error.message, true); } finally {