From 63036fc33ecf51eb638efbe49b7e4f8888f74a0d Mon Sep 17 00:00:00 2001 From: Dogfather Date: Mon, 7 Sep 2026 23:26:38 +0200 Subject: [PATCH] Wiederholungen bekommen eine eigene Tafel -- und nur den laufenden Monat Filipe: "ich will da auch noch eine kategorie fuer automatische wiederholungen. die sollen dann auch nur fuer den monat selbst angezeigt werden und nicht monate im voraus." DAS PROBLEM WAR ECHT UND GROSS, UND ES STAND SEIT TAGEN AUF SEINEM BILDSCHIRM Der Nachfueller haelt einen Horizont von 180 Tagen gefuellt (siehe workspace-serien.js). Ein woechentlicher Community-Talk ergibt darin sechsundzwanzig Zeilen -- und alle standen unter "Steht an". Auf dem Bild waren es siebenundzwanzig Karten, fast alle derselbe Termin. Die Liste war damit unbrauchbar fuer genau das, wofuer sie da ist: zu sehen, was WIRKLICH ansteht. Jetzt sind es zwei getrennte Fragen: STEHT AN was einmalig bevorsteht LAEUFT AUTOMATISCH was von allein wiederkommt -- und davon nur der LAUFENDE MONAT Der Monatsschnitt ist die eigentliche Antwort auf "nicht Monate im Voraus": Eine Wiederholung im November sagt einem heute nichts, was man nicht schon weiss. Wer weiter schauen will, hat den Kalender -- und genau das steht als Satz in der Gruppe. Gerechnet wird auf dem reinen Datumstext (`beginn` beginnt mit JJJJ-MM), nicht mit `new Date`. Kein Zeitzonenfehler, kein Nachtfehler. Die Trennung faellt im SERVER, nicht in der Oberflaeche: Eine zweite Regel im Browser waere die sichere Zusage, dass beide auseinanderlaufen. DREI AUSSAGEN STATT EINER pruef-call-kategorien saet jetzt zwei Auspraegungen derselben Serie -- eine in vier, eine in sechzig Tagen -- und misst: 1. die Wiederholung dieses Monats steht in "Laeuft automatisch" 2. die des naechsten Monats NICHT 3. und unter "Steht an" steht keine von beiden Vorher wird geprueft, dass die beiden ueberhaupt in verschiedenen Monaten liegen. Ohne diese Zeile waere Nummer 2 an einem 1. des Monats trivial erfuellt -- gruen, ohne etwas gemessen zu haben. Zwei Fehler beim Bau der Pruefung, beide von ihr selbst gemeldet: `page.evaluate` lief in "Target page has been closed" (der Block davor schliesst seinen Browserkontext -- diese Aussage braucht ohnehin keinen Browser, sie betrifft die Schnittstelle), und eine Hilfsfunktion stand nach ihrer ersten Benutzung. pruef-call-kategorien von 17 auf 22. Neun Pruefungen gelaufen, alle gruen. Co-Authored-By: Claude Opus 5 --- server/pruef-call-kategorien.mjs | 67 ++++++++++++++++++++++++++++++++ server/workspace-calls.js | 30 +++++++++++++- workspace/assets/js/calls.js | 11 +++++- workspace/aufgaben.html | 18 ++++----- workspace/automation.html | 20 +++++----- workspace/bereich.html | 28 ++++++------- workspace/calls.html | 22 +++++------ workspace/chat.html | 20 +++++----- workspace/content.html | 24 ++++++------ workspace/dateien.html | 20 +++++----- workspace/index.html | 4 +- workspace/kalender.html | 22 +++++------ workspace/leistung.html | 20 +++++----- workspace/personen.html | 20 +++++----- workspace/profil.html | 22 +++++------ workspace/report.html | 22 +++++------ workspace/scouting.html | 20 +++++----- workspace/start.html | 18 ++++----- workspace/startcheck.html | 22 +++++------ workspace/steckbrief.html | 20 +++++----- workspace/uebersicht.html | 20 +++++----- workspace/wissen.html | 20 +++++----- 22 files changed, 295 insertions(+), 195 deletions(-) diff --git a/server/pruef-call-kategorien.mjs b/server/pruef-call-kategorien.mjs index 15b77fee..8b682299 100644 --- a/server/pruef-call-kategorien.mjs +++ b/server/pruef-call-kategorien.mjs @@ -340,6 +340,73 @@ melde("\n=== Gegenprobe ==="); } await ctx.close(); +/* ======================================================================= + 4. WIEDERHOLUNGEN STEHEN IN IHRER EIGENEN GRUPPE -- UND NUR DER + LAUFENDE MONAT (07.09.2026) + + Filipe: "ich will da auch noch eine kategorie fuer automatische + wiederholungen. die sollen dann auch nur fuer den monat selbst + angezeigt werden und nicht monate im voraus." + + Der Nachfueller haelt einen Horizont von 180 Tagen gefuellt; ein + woechentlicher Termin ergibt darin sechsundzwanzig Zeilen, und alle + standen unter "Steht an". Geprueft werden deshalb DREI Aussagen -- + eine allein waere auch erfuellt, wenn schlicht nichts ankaeme: + + 1. die Wiederholung dieses Monats steht in `serien` + 2. die des naechsten Monats NICHT + 3. und in `anstehend` steht keine von beiden + ======================================================================= */ +melde("\n=== Wiederholungen: eigene Gruppe, nur dieser Monat ==="); +{ + const inTagen = (n) => { + const t = new Date(Date.now() + n * 86400000); + const p = (x) => String(x).padStart(2, "0"); + return `${t.getFullYear()}-${p(t.getMonth() + 1)}-${p(t.getDate())}T18:00`; + }; + const d2 = new DatabaseSync(process.env.WORKSPACE_DB); + d2.prepare(`INSERT INTO termin_serien (titel, art, takt, start_tag, uhrzeit, dauer_min, aktiv, erstellt, erstellt_von) + VALUES ('Community-Talk','call','woechentlich',?,'18:00',30,1,?,1)`) + .run(inTagen(0).slice(0, 10), new Date().toISOString()); + const serieId = d2.prepare("SELECT last_insert_rowid() AS id").get().id; + const rein = d2.prepare(`INSERT INTO termine (titel, art, beginn, dauer_min, serie_id, erstellt, erstellt_von) + VALUES (?,?,?,?,?,?,1)`); + /* Zwei Auspraegungen derselben Serie: eine in vier Tagen (also mit + grosser Wahrscheinlichkeit dieser Monat) und eine in sechzig Tagen + (sicher ein anderer). Der Monatsschnitt wird aus dem Datumstext + gerechnet, nicht aus einer Zeitzone. */ + const nah = inTagen(4), fern = inTagen(60); + rein.run("Serie dieser Monat", "call", nah, 30, serieId, new Date().toISOString()); + rein.run("Serie spaeter", "call", fern, 30, serieId, new Date().toISOString()); + d2.close(); + + /* OHNE BROWSER. Die Seite ist an dieser Stelle laengst geschlossen + (der Block darueber macht seinen Kontext zu), und `page.evaluate` + lief deshalb in "Target page has been closed". Diese Aussage + braucht ohnehin keinen Browser: Sie betrifft die Schnittstelle. */ + const anmeldung = await fetch(BASIS + "/workspace/api/anmelden", { + method: "POST", headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ rolle: "admin", code: "CODE-DOGI-0001" }), + }); + const keks = (anmeldung.headers.getSetCookie?.() || []) + .map((z) => z.split(";")[0]).join("; "); + ok(!!keks, "als DogFather angemeldet"); + const antwort = await (await fetch(BASIS + "/workspace/api/calls", + { headers: { cookie: keks } })).json(); + const serien = (antwort.serien || []).map((c) => c.titel); + const anstehend = (antwort.anstehend || []).map((c) => c.titel); + + const gleicherMonat = nah.slice(0, 7) === fern.slice(0, 7); + ok(!gleicherMonat, + `die beiden Auspraegungen liegen in verschiedenen Monaten (${nah.slice(0, 7)} / ${fern.slice(0, 7)})`); + ok(serien.includes("Serie dieser Monat"), + `die Wiederholung dieses Monats steht in "Laeuft automatisch" (${serien.join(", ") || "leer"})`); + ok(!serien.includes("Serie spaeter"), + "die des naechsten Monats nicht -- keine Monate im Voraus"); + ok(!anstehend.includes("Serie dieser Monat") && !anstehend.includes("Serie spaeter"), + `und unter "Steht an" steht keine von beiden (${anstehend.length} Eintraege)`); +} + await browser.close(); try { rmSync(ordner, { recursive: true, force: true }); } catch { /* egal */ } diff --git a/server/workspace-calls.js b/server/workspace-calls.js index 57a47abc..772c8cea 100644 --- a/server/workspace-calls.js +++ b/server/workspace-calls.js @@ -69,7 +69,7 @@ callRouter.use("/workspace/api/calls", angemeldet); const SPALTEN = ` t.id, t.titel, t.beschreibung, t.art, t.beginn, t.dauer_min, t.ort, - t.creator_id, t.teilnehmer_id, t.erledigt, + t.creator_id, t.teilnehmer_id, t.erledigt, t.serie_id, pc.name AS creator_name, pt.name AS teilnehmer_name, pr.id AS protokoll_id, pr.punkte, pr.entscheidungen, pr.erstellt AS protokoll_erstellt, pr.naechster_termin_id, @@ -133,8 +133,34 @@ callRouter.get("/workspace/api/calls", (req, res) => { call_link: einstellung("call_link", "") || "", /* Die Reihenfolge der Gruppen ist die Dringlichkeit: Was fehlt, steht oben -- nicht was als Naechstes kommt. */ + /* WIEDERHOLUNGEN BEKOMMEN EINE EIGENE GRUPPE (07.09.2026). + + Filipe: "ich will da auch noch eine kategorie fuer automatische + wiederholungen. die sollen dann auch nur fuer den monat selbst + angezeigt werden und nicht monate im voraus." + + DAS PROBLEM WAR ECHT UND GROSS: Der Nachfueller haelt einen + Horizont von 180 Tagen gefuellt (siehe workspace-serien.js). + Ein woechentlicher Community-Talk ergibt darin sechsundzwanzig + Zeilen -- und alle standen unter "Steht an". Auf Filipes Bild + waren es siebenundzwanzig Karten, fast alle derselbe Termin. + Die Liste war damit unbrauchbar fuer das, wofuer sie da ist: + zu sehen, was WIRKLICH ansteht. + + Jetzt zwei getrennte Fragen: + STEHT AN was einmalig bevorsteht + LAEUFT AUTOMATISCH was von allein wiederkommt, und davon + nur der LAUFENDE MONAT + + Der Monatsschnitt ist die eigentliche Antwort auf "nicht Monate + im Voraus": Eine Wiederholung im November sagt einem heute + nichts, was man nicht schon weiss. Gerechnet wird auf dem + reinen Datumstext (`beginn` beginnt mit JJJJ-MM) -- kein + `new Date`, keine Zeitzone, kein Nachtfehler. */ offen: alle.filter((c) => c.beginn <= grenze && !c.protokoll_id).reverse(), - anstehend: alle.filter((c) => c.beginn > grenze).reverse(), + anstehend: alle.filter((c) => c.beginn > grenze && !c.serie_id).reverse(), + serien: alle.filter((c) => c.beginn > grenze && c.serie_id + && String(c.beginn).slice(0, 7) === grenze.slice(0, 7)).reverse(), erledigt: alle.filter((c) => c.beginn <= grenze && c.protokoll_id), }); } catch (fehler) { diff --git a/workspace/assets/js/calls.js b/workspace/assets/js/calls.js index c189051d..2ad4ef0e 100644 --- a/workspace/assets/js/calls.js +++ b/workspace/assets/js/calls.js @@ -403,6 +403,8 @@ { schluessel: 'offen', titel: 'Protokoll fehlt', frage: 'Diese Gespräche sind vorbei, aber noch nicht festgehalten.' }, { schluessel: 'anstehend', titel: 'Steht an', frage: null }, + { schluessel: 'serien', titel: 'Läuft automatisch', + frage: 'Wiederholungen dieses Monats. Was danach kommt, steht im Kalender.' }, { schluessel: 'erledigt', titel: 'Festgehalten', frage: null }, ]; @@ -460,7 +462,8 @@ ziel.textContent = ''; ziel.setAttribute('aria-busy', 'false'); - if (!daten.offen.length && !daten.anstehend.length && !daten.erledigt.length) { + if (!daten.offen.length && !daten.anstehend.length + && !(daten.serien || []).length && !daten.erledigt.length) { const leer = el('div', 'leer-hinweis'); leer.append(document.createTextNode('Noch keine Calls. Termine mit der Art „Call" oder „Review" ')); const a = el('a', 'call__verweis', 'im Kalender'); @@ -493,7 +496,11 @@ ziel.className = 'call-brett'; for (const g of GRUPPEN) { - const liste = daten[g.schluessel]; + /* `|| []` fuer den Fall, dass ein Server ohne die neue Gruppe + antwortet -- etwa wenn die Seite noch aus dem Zwischenspeicher + kommt, der Dienst aber schon neu ist. Eine Oberflaeche, die + daran abstuerzt, waere der schlechtere Ausgang. */ + const liste = daten[g.schluessel] || []; if (!liste.length) continue; const s = el('section', 'gruppe'); s.dataset.gruppe = g.schluessel; diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index 9a2b0729..7113543e 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -9,10 +9,10 @@ - - - - + + + + @@ -212,10 +212,10 @@ - - - - - + + + + + diff --git a/workspace/automation.html b/workspace/automation.html index aec38745..6a5d282c 100644 --- a/workspace/automation.html +++ b/workspace/automation.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -135,10 +135,10 @@ - - - - - + + + + + diff --git a/workspace/bereich.html b/workspace/bereich.html index ce5e120a..63720f16 100644 --- a/workspace/bereich.html +++ b/workspace/bereich.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -144,14 +144,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/workspace/calls.html b/workspace/calls.html index 46b0f1ec..8308cc3d 100644 --- a/workspace/calls.html +++ b/workspace/calls.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -77,11 +77,11 @@ - - - - - - + + + + + + diff --git a/workspace/chat.html b/workspace/chat.html index 0c2cf6f3..2db312ca 100644 --- a/workspace/chat.html +++ b/workspace/chat.html @@ -9,17 +9,17 @@ - - + + - - - + + + @@ -155,10 +155,10 @@ - - - - - + + + + + diff --git a/workspace/content.html b/workspace/content.html index 04c15b4b..d10e72f1 100644 --- a/workspace/content.html +++ b/workspace/content.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -167,12 +167,12 @@ - - - - - - - + + + + + + + diff --git a/workspace/dateien.html b/workspace/dateien.html index 55696cca..7a8368dc 100644 --- a/workspace/dateien.html +++ b/workspace/dateien.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -96,10 +96,10 @@ - - - - - + + + + + diff --git a/workspace/index.html b/workspace/index.html index 20a118f2..097cd470 100644 --- a/workspace/index.html +++ b/workspace/index.html @@ -27,7 +27,7 @@ - + @@ -219,6 +219,6 @@ - + diff --git a/workspace/kalender.html b/workspace/kalender.html index 3ba2f6df..19b121bc 100644 --- a/workspace/kalender.html +++ b/workspace/kalender.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -258,11 +258,11 @@ - - - - - - + + + + + + diff --git a/workspace/leistung.html b/workspace/leistung.html index 6cc4a142..f05b5210 100644 --- a/workspace/leistung.html +++ b/workspace/leistung.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -212,10 +212,10 @@ - - - - - + + + + + diff --git a/workspace/personen.html b/workspace/personen.html index ec9afd27..a8925a38 100644 --- a/workspace/personen.html +++ b/workspace/personen.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -157,10 +157,10 @@ - - - - - + + + + + diff --git a/workspace/profil.html b/workspace/profil.html index 6b8a668c..ef5597ab 100644 --- a/workspace/profil.html +++ b/workspace/profil.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -202,11 +202,11 @@ - - - - - - + + + + + + diff --git a/workspace/report.html b/workspace/report.html index a8b58e9d..d822b4af 100644 --- a/workspace/report.html +++ b/workspace/report.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -94,11 +94,11 @@ - - - - - - + + + + + + diff --git a/workspace/scouting.html b/workspace/scouting.html index affb3717..acb154ad 100644 --- a/workspace/scouting.html +++ b/workspace/scouting.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -127,10 +127,10 @@ - - - - - + + + + + diff --git a/workspace/start.html b/workspace/start.html index a421e0c5..0c759005 100644 --- a/workspace/start.html +++ b/workspace/start.html @@ -9,12 +9,12 @@ - - + + - - + + @@ -320,10 +320,10 @@

- - - - - + + + + + diff --git a/workspace/startcheck.html b/workspace/startcheck.html index 87f5f405..e9951d84 100644 --- a/workspace/startcheck.html +++ b/workspace/startcheck.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -73,11 +73,11 @@ - - - - - - + + + + + + diff --git a/workspace/steckbrief.html b/workspace/steckbrief.html index 8be1c5d3..177dd6cc 100644 --- a/workspace/steckbrief.html +++ b/workspace/steckbrief.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -114,10 +114,10 @@ - - - - - + + + + + diff --git a/workspace/uebersicht.html b/workspace/uebersicht.html index ff97f19a..423ccb17 100644 --- a/workspace/uebersicht.html +++ b/workspace/uebersicht.html @@ -9,13 +9,13 @@ - - + + - - - + + + @@ -137,11 +137,11 @@ - + - - - - + + + + diff --git a/workspace/wissen.html b/workspace/wissen.html index 5a2180c7..e70f72c8 100644 --- a/workspace/wissen.html +++ b/workspace/wissen.html @@ -9,11 +9,11 @@ - - - - - + + + + + @@ -178,10 +178,10 @@ - - - - - + + + + +