diff --git a/backend/app/app.py b/backend/app/app.py index 1ed7529a..493dc9a1 100644 --- a/backend/app/app.py +++ b/backend/app/app.py @@ -865,7 +865,7 @@ def user_update_settings(): contrast = "normal" # Benutzer aus der Datenbank laden - user = db_session.query(User).filter(User.id == current_user.id).first() + user = db_session.query(User).filter(User.id == int(current_user.id)).first() if not user: error = "Benutzer nicht gefunden." @@ -1016,7 +1016,7 @@ def user_change_password(): return redirect(url_for("user_profile")) db_session = get_db_session() - user = db_session.query(User).filter(User.id == current_user.id).first() + user = db_session.query(User).filter(User.id == int(current_user.id)).first() if user and user.check_password(current_password): # Passwort aktualisieren @@ -1059,7 +1059,7 @@ def user_export_data(): """Exportiert alle Benutzerdaten als JSON für DSGVO-Konformität""" try: db_session = get_db_session() - user = db_session.query(User).filter(User.id == current_user.id).first() + user = db_session.query(User).filter(User.id == int(current_user.id)).first() if not user: db_session.close() @@ -1109,7 +1109,7 @@ def user_update_profile_api(): data = request.get_json() db_session = get_db_session() - user = db_session.query(User).filter(User.id == current_user.id).first() + user = db_session.query(User).filter(User.id == int(current_user.id)).first() if not user: db_session.close() @@ -2430,7 +2430,7 @@ def get_current_job(): db_session = get_db_session() try: current_job = db_session.query(Job).filter( - Job.user_id == current_user.id, + Job.user_id == int(current_user.id), Job.status.in_(["scheduled", "running"]) ).order_by(Job.start_at).first() @@ -2741,9 +2741,9 @@ def get_stats(): # Benutzer-spezifische Statistiken (falls nicht Admin) user_stats = {} if not current_user.is_admin: - user_jobs = db_session.query(Job).filter(Job.user_id == current_user.id).count() + user_jobs = db_session.query(Job).filter(Job.user_id == int(current_user.id)).count() user_completed = db_session.query(Job).filter( - Job.user_id == current_user.id, + Job.user_id == int(current_user.id), Job.status == "completed" ).count() user_stats = { @@ -5039,7 +5039,7 @@ def perform_batch_operation(): else: jobs = db_session.query(Job).filter( Job.id.in_(job_ids), - Job.user_id == current_user.id + Job.user_id == int(current_user.id) ).all() if not jobs: @@ -6148,4 +6148,4 @@ if __name__ == "__main__": stop_queue_manager() except: pass - sys.exit(1) \ No newline at end of file + sys.exit(1) diff --git a/backend/app/database/myp.db-shm b/backend/app/database/myp.db-shm index 0ec1c0b3..977efdfd 100644 Binary files a/backend/app/database/myp.db-shm and b/backend/app/database/myp.db-shm differ diff --git a/backend/app/database/myp.db-wal b/backend/app/database/myp.db-wal index 465d21d7..284336af 100644 Binary files a/backend/app/database/myp.db-wal and b/backend/app/database/myp.db-wal differ diff --git a/backend/app/static/js/debug-ui.js b/backend/app/static/js/debug-ui.js index 0519ecba..4f5a96ff 100644 --- a/backend/app/static/js/debug-ui.js +++ b/backend/app/static/js/debug-ui.js @@ -1 +1,401 @@ - \ No newline at end of file +/** + * MYP Platform - UI Debug & Diagnostic Tool + * Diagnostiziert und behebt UI-Probleme in Echtzeit + */ + +(function() { + 'use strict'; + + console.log('🔍 UI-Debug-Tool wird geladen...'); + + // Debug-Konfiguration + const DEBUG_CONFIG = { + logClicks: true, + logErrors: true, + logNavigation: true, + showVisualFeedback: true, + autoFix: true + }; + + /** + * Hauptinitialisierung des Debug-Tools + */ + function initDebugTool() { + console.log('🚀 UI-Debug-Tool gestartet'); + + // 1. Click-Tracking + setupClickTracking(); + + // 2. Error-Tracking + setupErrorTracking(); + + // 3. Navigation-Tracking + setupNavigationTracking(); + + // 4. Element-Diagnostik + diagnoseElements(); + + // 5. Auto-Fix aktivieren + if (DEBUG_CONFIG.autoFix) { + setupAutoFix(); + } + + // 6. Debug-Panel erstellen + createDebugPanel(); + + console.log('✅ UI-Debug-Tool vollständig initialisiert'); + } + + /** + * Click-Tracking einrichten + */ + function setupClickTracking() { + if (!DEBUG_CONFIG.logClicks) return; + + document.addEventListener('click', function(event) { + const target = event.target; + const info = { + element: target.tagName, + id: target.id || 'keine ID', + classes: target.className || 'keine Klassen', + href: target.href || 'kein href', + type: target.type || 'kein type', + dataAction: target.getAttribute('data-action') || 'keine data-action', + clickable: isElementClickable(target), + hasEventListeners: hasEventListeners(target) + }; + + console.log('👆 KLICK ERKANNT:', info); + + // Visuelles Feedback + if (DEBUG_CONFIG.showVisualFeedback) { + showClickFeedback(target); + } + + // Auto-Fix für nicht-klickbare Elemente + if (!info.clickable && DEBUG_CONFIG.autoFix) { + makeElementClickable(target); + } + }, true); + } + + /** + * Error-Tracking einrichten + */ + function setupErrorTracking() { + if (!DEBUG_CONFIG.logErrors) return; + + window.addEventListener('error', function(event) { + console.error('🚨 JAVASCRIPT-FEHLER:', { + message: event.message, + filename: event.filename, + lineno: event.lineno, + colno: event.colno, + error: event.error + }); + }); + + window.addEventListener('unhandledrejection', function(event) { + console.error('🚨 UNHANDLED PROMISE REJECTION:', event.reason); + }); + } + + /** + * Navigation-Tracking einrichten + */ + function setupNavigationTracking() { + if (!DEBUG_CONFIG.logNavigation) return; + + // Link-Klicks verfolgen + document.addEventListener('click', function(event) { + const link = event.target.closest('a'); + if (link) { + console.log('🔗 NAVIGATION:', { + href: link.href, + text: link.textContent.trim(), + target: link.target, + internal: isInternalLink(link.href) + }); + } + }); + } + + /** + * Element-Diagnostik durchführen + */ + function diagnoseElements() { + console.log('🔍 Starte Element-Diagnostik...'); + + // Alle potentiell klickbaren Elemente finden + const clickableSelectors = [ + 'a', 'button', '[role="button"]', '[data-action]', + '.btn', '.clickable', '.nav-item', '.menu-item' + ]; + + clickableSelectors.forEach(selector => { + const elements = document.querySelectorAll(selector); + console.log(`📊 ${selector}: ${elements.length} Elemente gefunden`); + + elements.forEach((element, index) => { + const diagnosis = diagnoseElement(element); + if (diagnosis.issues.length > 0) { + console.warn(`⚠️ ${selector}[${index}] hat Probleme:`, diagnosis); + } + }); + }); + } + + /** + * Einzelnes Element diagnostizieren + */ + function diagnoseElement(element) { + const issues = []; + const info = { + tag: element.tagName, + id: element.id, + classes: element.className, + href: element.href, + type: element.type, + disabled: element.disabled, + hidden: element.hidden || element.style.display === 'none', + hasEventListeners: hasEventListeners(element), + clickable: isElementClickable(element) + }; + + // Probleme identifizieren + if (element.tagName === 'A' && (!element.href || element.href === '#')) { + issues.push('Link ohne gültiges href-Attribut'); + } + + if (element.tagName === 'BUTTON' && element.disabled) { + issues.push('Button ist deaktiviert'); + } + + if (!info.hasEventListeners && !element.href && !element.onclick) { + issues.push('Keine Event-Listener oder onclick-Handler gefunden'); + } + + if (info.hidden) { + issues.push('Element ist versteckt'); + } + + return { info, issues }; + } + + /** + * Auto-Fix einrichten + */ + function setupAutoFix() { + console.log('🔧 Auto-Fix aktiviert'); + + // Alle problematischen Elemente finden und reparieren + const problematicElements = document.querySelectorAll('a[href="#"], button:disabled, [data-action]:not([onclick])'); + + problematicElements.forEach(element => { + fixElement(element); + }); + + // Mutation Observer für dynamisch hinzugefügte Elemente + const observer = new MutationObserver(function(mutations) { + mutations.forEach(function(mutation) { + mutation.addedNodes.forEach(function(node) { + if (node.nodeType === Node.ELEMENT_NODE) { + const problematic = node.querySelectorAll('a[href="#"], button:disabled, [data-action]:not([onclick])'); + problematic.forEach(fixElement); + } + }); + }); + }); + + observer.observe(document.body, { childList: true, subtree: true }); + } + + /** + * Element reparieren + */ + function fixElement(element) { + console.log('🔧 Repariere Element:', element); + + if (element.tagName === 'A' && (!element.href || element.href === '#')) { + // Link ohne href reparieren + element.style.cursor = 'pointer'; + element.addEventListener('click', function(e) { + e.preventDefault(); + console.log('🔗 Reparierter Link geklickt:', this); + }); + } + + if (element.tagName === 'BUTTON' && element.disabled) { + // Deaktivierten Button aktivieren (falls sicher) + if (!element.hasAttribute('data-keep-disabled')) { + element.disabled = false; + console.log('🔘 Button aktiviert:', element); + } + } + + if (element.hasAttribute('data-action') && !hasEventListeners(element)) { + // Data-Action-Element ohne Event-Listener reparieren + element.addEventListener('click', function(e) { + e.preventDefault(); + const action = this.getAttribute('data-action'); + console.log('⚡ Data-Action ausgeführt:', action); + + // Versuche globale Handler zu finden + if (window.MYP_UI_FIXES && window.MYP_UI_FIXES[action]) { + window.MYP_UI_FIXES[action](); + } + }); + } + } + + /** + * Debug-Panel erstellen + */ + function createDebugPanel() { + const panel = document.createElement('div'); + panel.id = 'debug-panel'; + panel.style.cssText = ` + position: fixed; + top: 10px; + right: 10px; + width: 300px; + background: rgba(0, 0, 0, 0.9); + color: white; + padding: 10px; + border-radius: 5px; + font-family: monospace; + font-size: 12px; + z-index: 10000; + max-height: 400px; + overflow-y: auto; + display: none; + `; + + panel.innerHTML = ` +
+ 🔍 UI Debug Panel + +
+
+
✅ Debug-Tool aktiv
+
👆 Klicks werden verfolgt
+
🔧 Auto-Fix aktiviert
+
+ `; + + document.body.appendChild(panel); + + // Toggle-Button für Debug-Panel + const toggleButton = document.createElement('button'); + toggleButton.textContent = '🔍'; + toggleButton.style.cssText = ` + position: fixed; + bottom: 20px; + right: 20px; + width: 50px; + height: 50px; + border-radius: 50%; + background: #007bff; + color: white; + border: none; + font-size: 20px; + cursor: pointer; + z-index: 10001; + box-shadow: 0 2px 10px rgba(0,0,0,0.3); + `; + + toggleButton.addEventListener('click', function() { + const panel = document.getElementById('debug-panel'); + panel.style.display = panel.style.display === 'none' ? 'block' : 'none'; + }); + + document.body.appendChild(toggleButton); + } + + /** + * Hilfsfunktionen + */ + function isElementClickable(element) { + const style = window.getComputedStyle(element); + return style.pointerEvents !== 'none' && + style.display !== 'none' && + style.visibility !== 'hidden' && + !element.disabled; + } + + function hasEventListeners(element) { + // Vereinfachte Prüfung - in der Realität schwer zu detektieren + return element.onclick !== null || + element.getAttribute('onclick') !== null || + element.hasAttribute('data-action'); + } + + function isInternalLink(href) { + if (!href) return false; + return href.startsWith('/') || + href.startsWith('./') || + href.startsWith('../') || + href.includes(window.location.hostname); + } + + function makeElementClickable(element) { + if (!isElementClickable(element)) { + element.style.cursor = 'pointer'; + element.style.pointerEvents = 'auto'; + + if (!hasEventListeners(element)) { + element.addEventListener('click', function(e) { + console.log('🔧 Auto-Fix Klick auf:', this); + }); + } + } + } + + function showClickFeedback(element) { + const feedback = document.createElement('div'); + feedback.style.cssText = ` + position: absolute; + background: rgba(0, 255, 0, 0.3); + border: 2px solid #00ff00; + pointer-events: none; + z-index: 9999; + border-radius: 3px; + `; + + const rect = element.getBoundingClientRect(); + feedback.style.left = rect.left + 'px'; + feedback.style.top = rect.top + 'px'; + feedback.style.width = rect.width + 'px'; + feedback.style.height = rect.height + 'px'; + + document.body.appendChild(feedback); + + setTimeout(() => { + feedback.remove(); + }, 500); + } + + /** + * Initialisierung + */ + if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', initDebugTool); + } else { + initDebugTool(); + } + + // Globale Debug-Funktionen + window.DEBUG_UI = { + diagnose: diagnoseElements, + fix: setupAutoFix, + toggle: function() { + const panel = document.getElementById('debug-panel'); + if (panel) { + panel.style.display = panel.style.display === 'none' ? 'block' : 'none'; + } + } + }; + + console.log('✅ UI-Debug-Tool geladen'); + +})(); \ No newline at end of file diff --git a/backend/app/templates/base.html b/backend/app/templates/base.html index 6db1bfb8..c61a2329 100644 --- a/backend/app/templates/base.html +++ b/backend/app/templates/base.html @@ -577,6 +577,7 @@ +