A previous `git pull --rebase origin main` dropped 177 local commits,
losing 3400+ files across admin-v2, backend, studio-v2, website,
klausur-service, and many other services. The partial restore attempt
(660295e2) only recovered some files.
This commit restores all missing files from pre-rebase ref 98933f5e
while preserving post-rebase additions (night-scheduler, night-mode UI,
NightModeWidget dashboard integration).
Restored features include:
- AI Module Sidebar (FAB), OCR Labeling, OCR Compare
- GPU Dashboard, RAG Pipeline, Magic Help
- Klausur-Korrektur (8 files), Abitur-Archiv (5+ files)
- Companion, Zeugnisse-Crawler, Screen Flow
- Full backend, studio-v2, website, klausur-service
- All compliance SDKs, agent-core, voice-service
- CI/CD configs, documentation, scripts
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
224 lines
6.5 KiB
JavaScript
224 lines
6.5 KiB
JavaScript
/**
|
|
* BreakPilot Studio - Mindmap Module
|
|
*
|
|
* Mindmap/Lernplakat-Generierung aus Arbeitsblättern:
|
|
* - Generieren von Mindmaps aus analysierten Arbeitsblättern
|
|
* - Vorschau und Anzeige
|
|
* - Druck-Funktion (A4/A3)
|
|
*
|
|
* Refactored: 2026-01-19
|
|
*/
|
|
|
|
import { t } from './i18n.js';
|
|
import { setStatus, setStatusWorking, setStatusError, setStatusSuccess, fetchJSON } from './api-helpers.js';
|
|
|
|
// State
|
|
let currentMindmapData = null;
|
|
|
|
// DOM References
|
|
let mindmapPreview = null;
|
|
let mindmapBadge = null;
|
|
let btnMindmapGenerate = null;
|
|
let btnMindmapShow = null;
|
|
let btnMindmapPrint = null;
|
|
|
|
// Callback für aktuelle Datei
|
|
let getCurrentFileCallback = null;
|
|
|
|
/**
|
|
* Initialisiert das Mindmap-Modul
|
|
* @param {Object} options - Konfiguration
|
|
* @param {Function} options.getCurrentFile - Callback um die aktuelle Datei zu bekommen
|
|
*/
|
|
export function initMindmapModule(options = {}) {
|
|
getCurrentFileCallback = options.getCurrentFile || (() => null);
|
|
|
|
mindmapPreview = document.getElementById('mindmap-preview') || options.previewEl;
|
|
mindmapBadge = document.getElementById('mindmap-badge') || options.badgeEl;
|
|
btnMindmapGenerate = document.getElementById('btn-mindmap-generate') || options.generateBtn;
|
|
btnMindmapShow = document.getElementById('btn-mindmap-show') || options.showBtn;
|
|
btnMindmapPrint = document.getElementById('btn-mindmap-print') || options.printBtn;
|
|
|
|
// Event-Listener
|
|
if (btnMindmapGenerate) {
|
|
btnMindmapGenerate.addEventListener('click', generateMindmap);
|
|
}
|
|
|
|
if (btnMindmapShow) {
|
|
btnMindmapShow.addEventListener('click', openMindmapView);
|
|
}
|
|
|
|
if (btnMindmapPrint) {
|
|
btnMindmapPrint.addEventListener('click', openMindmapPrint);
|
|
}
|
|
|
|
// Event für Datei-Wechsel
|
|
window.addEventListener('fileSelected', (ev) => {
|
|
loadMindmapData();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Generiert eine Mindmap für die aktuelle Datei
|
|
*/
|
|
export async function generateMindmap() {
|
|
const currentFile = getCurrentFileCallback();
|
|
if (!currentFile) {
|
|
alert(t('select_file_first') || 'Bitte zuerst eine Datei auswählen.');
|
|
return;
|
|
}
|
|
|
|
try {
|
|
setStatusWorking(t('mindmap_generating') || 'Generiere Mindmap...');
|
|
if (mindmapBadge) {
|
|
mindmapBadge.textContent = t('generating') || 'Generiert...';
|
|
mindmapBadge.className = 'card-badge';
|
|
}
|
|
|
|
const resp = await fetch('/api/generate-mindmap/' + encodeURIComponent(currentFile), {
|
|
method: 'POST'
|
|
});
|
|
|
|
if (!resp.ok) {
|
|
throw new Error('HTTP ' + resp.status);
|
|
}
|
|
|
|
const data = await resp.json();
|
|
|
|
if (data.status === 'OK') {
|
|
if (mindmapBadge) {
|
|
mindmapBadge.textContent = t('ready') || 'Fertig';
|
|
mindmapBadge.className = 'card-badge badge-success';
|
|
}
|
|
setStatusSuccess(t('mindmap_generated') || 'Mindmap erstellt!');
|
|
|
|
// Lade Mindmap-Daten
|
|
await loadMindmapData();
|
|
} else if (data.status === 'NOT_FOUND') {
|
|
if (mindmapBadge) {
|
|
mindmapBadge.textContent = t('no_analysis') || 'Keine Analyse';
|
|
mindmapBadge.className = 'card-badge badge-error';
|
|
}
|
|
setStatusError(t('analyze_first') || 'Bitte zuerst analysieren (Neuaufbau starten)');
|
|
} else {
|
|
throw new Error(data.message || 'Fehler bei der Mindmap-Generierung');
|
|
}
|
|
} catch (err) {
|
|
console.error('Mindmap error:', err);
|
|
if (mindmapBadge) {
|
|
mindmapBadge.textContent = t('error') || 'Fehler';
|
|
mindmapBadge.className = 'card-badge badge-error';
|
|
}
|
|
setStatusError(t('error') || 'Fehler', err.message);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Lädt die Mindmap-Daten für die aktuelle Datei
|
|
*/
|
|
export async function loadMindmapData() {
|
|
const currentFile = getCurrentFileCallback();
|
|
|
|
if (!currentFile) {
|
|
if (mindmapPreview) mindmapPreview.innerHTML = '';
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const resp = await fetch('/api/mindmap-data/' + encodeURIComponent(currentFile));
|
|
const data = await resp.json();
|
|
|
|
if (data.status === 'OK' && data.data) {
|
|
currentMindmapData = data.data;
|
|
renderMindmapPreview();
|
|
if (btnMindmapShow) btnMindmapShow.style.display = 'inline-block';
|
|
if (btnMindmapPrint) btnMindmapPrint.style.display = 'inline-block';
|
|
if (mindmapBadge) {
|
|
mindmapBadge.textContent = t('ready') || 'Fertig';
|
|
mindmapBadge.className = 'card-badge badge-success';
|
|
}
|
|
} else {
|
|
currentMindmapData = null;
|
|
if (mindmapPreview) mindmapPreview.innerHTML = '';
|
|
if (btnMindmapShow) btnMindmapShow.style.display = 'none';
|
|
if (btnMindmapPrint) btnMindmapPrint.style.display = 'none';
|
|
if (mindmapBadge) {
|
|
mindmapBadge.textContent = t('ready') || 'Bereit';
|
|
mindmapBadge.className = 'card-badge';
|
|
}
|
|
}
|
|
} catch (err) {
|
|
console.error('Error loading mindmap:', err);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Rendert die Mindmap-Vorschau
|
|
*/
|
|
function renderMindmapPreview() {
|
|
if (!mindmapPreview) return;
|
|
|
|
if (!currentMindmapData) {
|
|
mindmapPreview.innerHTML = '';
|
|
return;
|
|
}
|
|
|
|
const topic = currentMindmapData.topic || 'Thema';
|
|
const categories = currentMindmapData.categories || [];
|
|
const categoryCount = categories.length;
|
|
const termCount = categories.reduce((sum, cat) => sum + (cat.terms ? cat.terms.length : 0), 0);
|
|
|
|
mindmapPreview.innerHTML = `
|
|
<div style="margin-top:10px;padding:12px;background:linear-gradient(135deg,#f0f9ff,#e0f2fe);border-radius:10px;text-align:center;">
|
|
<div style="font-size:18px;font-weight:bold;color:#0369a1;margin-bottom:8px;">${escapeHtml(topic)}</div>
|
|
<div style="font-size:12px;color:#64748b;">
|
|
${categoryCount} ${t('categories') || 'Kategorien'} | ${termCount} ${t('terms') || 'Begriffe'}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
|
|
/**
|
|
* Öffnet die Mindmap-Ansicht (A4)
|
|
*/
|
|
export function openMindmapView() {
|
|
const currentFile = getCurrentFileCallback();
|
|
if (!currentFile) return;
|
|
window.open('/api/mindmap-html/' + encodeURIComponent(currentFile) + '?format=a4', '_blank');
|
|
}
|
|
|
|
/**
|
|
* Öffnet die Mindmap-Druckansicht (A3)
|
|
*/
|
|
export function openMindmapPrint() {
|
|
const currentFile = getCurrentFileCallback();
|
|
if (!currentFile) return;
|
|
window.open('/api/mindmap-html/' + encodeURIComponent(currentFile) + '?format=a3', '_blank');
|
|
}
|
|
|
|
/**
|
|
* Gibt die aktuellen Mindmap-Daten zurück
|
|
* @returns {Object|null}
|
|
*/
|
|
export function getMindmapData() {
|
|
return currentMindmapData;
|
|
}
|
|
|
|
/**
|
|
* Setzt die Mindmap-Daten
|
|
* @param {Object} data
|
|
*/
|
|
export function setMindmapData(data) {
|
|
currentMindmapData = data;
|
|
renderMindmapPreview();
|
|
}
|
|
|
|
/**
|
|
* Helper: HTML-Escape
|
|
*/
|
|
function escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|