Merge pull request 'Reload-Countdown, CHANGELOG (#108) und Aufnahmeseite: "gespeichert" statt "verworfen"' (#111) from fds2610-bot/monitor:main into main
Reviewed-on: https://codeberg.org/fds2610/monitor/pulls/111
This commit is contained in:
commit
90897c956c
7 changed files with 48 additions and 16 deletions
|
|
@ -30,9 +30,11 @@ CODEBERG_TOKEN=
|
||||||
# Mit eingerichtetem Webhook (siehe unten) ist das nur noch das Sicherheitsnetz fuer
|
# Mit eingerichtetem Webhook (siehe unten) ist das nur noch das Sicherheitsnetz fuer
|
||||||
# verpasste Zustellungen und darf gross bleiben - Issue-Aenderungen landen dann in Sekunden
|
# verpasste Zustellungen und darf gross bleiben - Issue-Aenderungen landen dann in Sekunden
|
||||||
# auf dem Board, nicht erst beim naechsten Lauf.
|
# auf dem Board, nicht erst beim naechsten Lauf.
|
||||||
# Speist ausserdem den rein kosmetischen Reload-Countdown im Header der Buero-Visualisierung
|
# Speist ausserdem den Reload-Countdown im Header der Buero-Visualisierung (Service "web",
|
||||||
# (Service "web", siehe docker/nginx/default.conf.template) - der Countdown zaehlt nur mit,
|
# siehe docker/nginx/default.conf.template) - erreicht der Countdown 0, laedt der Browser die
|
||||||
# er loest selbst keinen echten Reload/Sync aus.
|
# 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
|
MONITOR_SYNC_INTERVAL=600
|
||||||
|
|
||||||
# Secret des Codeberg-Webhooks (Repo -> Einstellungen -> Webhooks -> Forgejo, Ziel-URL
|
# Secret des Codeberg-Webhooks (Repo -> Einstellungen -> Webhooks -> Forgejo, Ziel-URL
|
||||||
|
|
|
||||||
10
CHANGELOG.md
Normal file
10
CHANGELOG.md
Normal file
|
|
@ -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).
|
||||||
|
|
@ -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,
|
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
|
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!".
|
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
|
- 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
|
(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
|
wirken sofort im laufenden `sync`-Dienst, ohne Neustart. Schreibende Aktionen fragen einmalig
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,9 @@ server {
|
||||||
# definiert, bleibt ihr Platzhalter stehen und nginx verweigert den Start
|
# definiert, bleibt ihr Platzhalter stehen und nginx verweigert den Start
|
||||||
# ("unknown \"monitor_api_base\" variable") - besser ein lauter Fehler als eine still
|
# ("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).
|
# 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
|
# MONITOR_SYNC_INTERVAL speist den Reload-Countdown im Header (Issue #12) - der laedt die
|
||||||
# (Issue #12) - hat keinen Einfluss auf den tatsaechlichen Update-Takt der Szene.
|
# 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 {
|
location = /config.js {
|
||||||
default_type application/javascript;
|
default_type application/javascript;
|
||||||
add_header Cache-Control "no-store";
|
add_header Cache-Control "no-store";
|
||||||
|
|
|
||||||
|
|
@ -349,6 +349,7 @@ function renderPullRequestStripePattern() {
|
||||||
width: 10,
|
width: 10,
|
||||||
height: 10,
|
height: 10,
|
||||||
patternUnits: "userSpaceOnUse",
|
patternUnits: "userSpaceOnUse",
|
||||||
|
patternTransform: "rotate(45)",
|
||||||
});
|
});
|
||||||
pattern.appendChild(el("rect", { x: 0, y: 0, width: 10, height: 3, fill: "#000000" }));
|
pattern.appendChild(el("rect", { x: 0, y: 0, width: 10, height: 3, fill: "#000000" }));
|
||||||
defs.appendChild(pattern);
|
defs.appendChild(pattern);
|
||||||
|
|
@ -2537,9 +2538,12 @@ function setAgentProblemBanner(agents) {
|
||||||
banner.classList.toggle("api-banner-warning", !expired && Boolean(expiring));
|
banner.classList.toggle("api-banner-warning", !expired && Boolean(expiring));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rein kosmetischer Countdown im Header (Issue #12): zaehlt unabhaengig vom tatsaechlichen
|
// Countdown im Header (Issue #12, seit Issue #108 mit echtem Reload): zaehlt unabhaengig vom
|
||||||
// SSE-/Polling-Takt von MONITOR_SYNC_INTERVAL (aus config.js, siehe office.html) auf 0
|
// tatsaechlichen SSE-/Polling-Takt von MONITOR_SYNC_INTERVAL (aus config.js, siehe office.html)
|
||||||
// herunter und startet danach von vorn - loest selbst keinen Reload aus.
|
// 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() {
|
function startReloadCountdown() {
|
||||||
const countdownEl = document.getElementById("reload-countdown");
|
const countdownEl = document.getElementById("reload-countdown");
|
||||||
if (!countdownEl) {
|
if (!countdownEl) {
|
||||||
|
|
@ -2551,7 +2555,12 @@ function startReloadCountdown() {
|
||||||
countdownEl.textContent = `${remaining}s`;
|
countdownEl.textContent = `${remaining}s`;
|
||||||
|
|
||||||
window.setInterval(() => {
|
window.setInterval(() => {
|
||||||
remaining = nextCountdownSeconds(remaining, intervalSeconds);
|
const next = nextCountdownSeconds(remaining, intervalSeconds);
|
||||||
|
if (next === intervalSeconds) {
|
||||||
|
window.location.reload();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
remaining = next;
|
||||||
countdownEl.textContent = `${remaining}s`;
|
countdownEl.textContent = `${remaining}s`;
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1045,9 +1045,11 @@ export function advancePoVisitStage(stage) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------------------
|
||||||
// Reload-Countdown im Header (Issue #12): rein kosmetischer Sekundenzaehler, der die
|
// Reload-Countdown im Header (Issue #12, seit Issue #108 mit echtem Reload): Sekundenzaehler,
|
||||||
// Sync-Frequenz des Backends (MONITOR_SYNC_INTERVAL, siehe .env.example) im Header
|
// 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).
|
// 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;
|
export const DEFAULT_RELOAD_INTERVAL_SECONDS = 600;
|
||||||
|
|
|
||||||
|
|
@ -113,12 +113,16 @@ function stopRecording() {
|
||||||
startButton.hidden = false;
|
startButton.hidden = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function discardRecording() {
|
function resetRecording() {
|
||||||
recordedBlob = null;
|
recordedBlob = null;
|
||||||
audioPreview.removeAttribute("src");
|
audioPreview.removeAttribute("src");
|
||||||
audioPreview.hidden = true;
|
audioPreview.hidden = true;
|
||||||
uploadButton.hidden = true;
|
uploadButton.hidden = true;
|
||||||
discardButton.hidden = true;
|
discardButton.hidden = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function discardRecording() {
|
||||||
|
resetRecording();
|
||||||
setStatus("Aufnahme verworfen.");
|
setStatus("Aufnahme verworfen.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,8 +137,8 @@ async function upload() {
|
||||||
const extension = (recordedBlob.type.split("/")[1] || "webm").split(";")[0];
|
const extension = (recordedBlob.type.split("/")[1] || "webm").split(";")[0];
|
||||||
try {
|
try {
|
||||||
await uploadRecording(recordedBlob, `aufnahme.${extension}`);
|
await uploadRecording(recordedBlob, `aufnahme.${extension}`);
|
||||||
setStatus("Hochgeladen, danke!");
|
resetRecording();
|
||||||
discardRecording();
|
setStatus("Aufnahme gespeichert, danke!");
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus(error.message, true);
|
setStatus(error.message, true);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue