// ----------------------------- // Projektplan — Verlauf über mehrere Sitzungen // ----------------------------- // Dieses Modul macht die Sitzungs-Historie eines Projekts sichtbar: die // Kompakt-Karte "Verlauf" unter dem GANTT zeigt den letzten Kommentarwechsel, // ein Klick öffnet #planHistoryModal mit dem vollständigen Verlauf. // // Der Verlauf selbst wird NICHT hier gezeichnet, sondern von // renderProjektVerlauf() in js/utils.js — derselben Darstellung, die auch der // Wochenbericht unter der Projektkarte und die Projektliste zeigen. Zuvor // hatte jede dieser Stellen ihre eigene Fassung mit eigener Auswahl (hier nur // Sitzungen mit Kommentarwechsel, im Bericht auch Termine und // Leistungsphasen), weshalb derselbe Projektverlauf je nach Aufrufort anders // aussah und sich widersprechen konnte. Der Dialog übergibt kein weekLabel: // Er kennt keine "aktuelle" Fassung, die auszulassen wäre, und zeigt deshalb // alle Sitzungen einschließlich der geöffneten. // // Hintergrund: Beim wöchentlichen cloneWeek() (js/weeks.js) wird der // Kommentartext in die neue Sitzung kopiert und dort überschrieben. Der alte // Text bleibt zwar in der alten Sitzung erhalten, war aber praktisch // unsichtbar, weil niemand in alte Sitzungen zurückwechselt. Damit ging der // Gesprächsfaden eines Projekts verloren — genau das, wofür das wöchentliche // Board ursprünglich gedacht war. // // WICHTIG — kein neuer Endpunkt nötig: Die Projektplan-Seite lädt über // GET /load-all ohnehin ALLE Sitzungen mit allen Projekten nach db.weeks // (siehe loadPlanData() in plan-state.js). Zusammen mit project_uid (der // dauerhaften, wochenunabhängigen Projekt-Identität, siehe // migrateAddProjectUid() in server.js) lässt sich der Verlauf daher rein im // Browser zusammenstellen. Ein serverseitiges GET /projects/:uid/history wird // erst nötig, wenn der Verlauf auch außerhalb dieser Seite gebraucht wird. // // Die hier definierten Helfer projectVersions()/previousProjectVersion() // werden auch von plan-build-gantt.js gebraucht (Geister-Balken der Vorwoche) // und deshalb auf window.PlanApp exportiert. Dieses Modul muss daher VOR // plan-build-gantt.js geladen werden. // // Läuft wie alle plan-Module in einem IIFE; Zustand: window.PlanApp // (plan-state.js). (function(){ const app = window.PlanApp; // projectVersions: alle Fassungen des aktuellen Projekts über alle // geladenen Sitzungen, chronologisch aufsteigend. Die eigentliche Logik // liegt seit der Kommentar-Überarbeitung in js/utils.js // (projectVersionsForUid), weil das Board sie ebenfalls braucht; hier bleibt // nur die Bindung an das aktuell geöffnete Projekt. function projectVersions(){ return projectVersionsForUid(app.project && app.project.projectUid); } // previousProjectVersion: die Fassung des Projekts aus der Sitzung // unmittelbar VOR der gerade geöffneten, oder null (früheste Sitzung bzw. // kein projectUid). Rückgabe: { week, project } | null. function previousProjectVersion(){ const versions = projectVersions(); const idx = versions.findIndex(v => app.week && v.week.label === app.week.label); return idx > 0 ? versions[idx - 1] : null; } // previousPlannedProjectVersion: die jüngste frühere Fassung, die überhaupt // einen befüllten Terminplan hat (mindestens eine Aufgabe oder einen // Meilenstein). Grundlage für die Geister-Balken im GANTT. // // Warum nicht einfach previousProjectVersion(): In der Praxis gibt es // Sitzungen, in denen ein Projekt zwar geführt wird, aber (noch) keinen // Terminplan hat — etwa weil die Sitzung neu angelegt statt dupliziert // wurde. Ein Vergleich gegen so eine leere Fassung würde gar nichts // anzeigen und die Funktion wirkte kaputt, obwohl es zwei Sitzungen weiter // hinten sehr wohl Vergleichsdaten gibt. Deshalb wird rückwärts gesucht, // bis eine Fassung mit Planinhalt gefunden ist. Die gefundene Sitzung wird // in den Tooltips namentlich genannt, damit der Bezug nie unklar ist. // Rückgabe: { week, project } | null. function previousPlannedProjectVersion(){ const versions = projectVersions(); const idx = versions.findIndex(v => app.week && v.week.label === app.week.label); if(idx <= 0) return null; for(let i = idx - 1; i >= 0; i--){ const plan = versions[i].project.plan; if(!plan) continue; const hasTodos = Array.isArray(plan.todos) && plan.todos.length > 0; const hasMilestones = Array.isArray(plan.milestones) && plan.milestones.length > 0; if(hasTodos || hasMilestones) return versions[i]; } return null; } // historyEntries: die Verlaufsliste des aktuell geöffneten Projekts // (neueste zuerst, Wiederholungen desselben Textes gefiltert). Logik in // js/utils.js, siehe projectStatusHistory(). function historyEntries(){ return projectStatusHistory(app.project && app.project.projectUid); } // renderPlanHistory: füllt die Kompakt-Karte "Verlauf" (#planHistorySummary // in Test.html) — Anzahl der Einträge und die Sitzung des letzten // Kommentarwechsels. Wird von renderPlanPage() (plan-state.js) nach dem // Laden aufgerufen. Keine Parameter, keine Rückgabe. window.renderPlanHistory = function(){ const summaryEl = document.getElementById('planHistorySummary'); if(!summaryEl || !app.project) return; // Ein Sandbox-Plan der Planung lebt in genau einer, nie geklonten Sitzung // (SANDBOX_WEEK_LABEL) — es gibt also nie einen "Verlauf über mehrere // Sitzungen" zu zeigen, nur immer denselben einen Schnappschuss. if(app.isSandboxPlan && app.isSandboxPlan()){ summaryEl.innerHTML = 'Kein Verlauf — dieser Terminplan gehört zu keiner Sitzung.'; return; } if(!app.project.projectUid){ summaryEl.innerHTML = 'Für dieses Projekt ist kein Verlauf verfügbar.'; return; } const entries = historyEntries(); if(entries.length === 0){ summaryEl.innerHTML = 'Noch keine Kommentare erfasst.'; return; } const latest = entries[0]; const versionCount = projectVersions().length; summaryEl.innerHTML = `