"feat: Update database schema in myp.db-wal

This commit is contained in:
Till Tomczak 2025-05-29 20:02:03 +02:00
parent b7addfef77
commit a0bd9ba753
4 changed files with 0 additions and 976 deletions

Binary file not shown.

View File

@ -1,401 +0,0 @@
/**
* 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 = `
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
<strong>🔍 UI Debug Panel</strong>
<button onclick="this.parentElement.parentElement.style.display='none'" style="background: red; color: white; border: none; padding: 2px 6px; border-radius: 3px; cursor: pointer;">×</button>
</div>
<div id="debug-content">
<div> Debug-Tool aktiv</div>
<div>👆 Klicks werden verfolgt</div>
<div>🔧 Auto-Fix aktiviert</div>
</div>
`;
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');
})();

View File

@ -1,573 +0,0 @@
/**
* MYP Platform - UI Issues Fix
* Behebt alle Klickbarkeits- und Interaktivitätsprobleme
* Version: 1.0.0
*/
(function() {
'use strict';
console.log('🔧 UI-Fix wird geladen...');
// Globale Variablen für bessere Kompatibilität
window.MYP_UI_FIXED = false;
/**
* Hauptinitialisierung
*/
function initializeUIFixes() {
if (window.MYP_UI_FIXED) {
console.log('✅ UI bereits gefixt');
return;
}
console.log('🚀 Starte UI-Fixes...');
// 1. Event-Delegation für alle Klicks
setupGlobalClickHandlers();
// 2. Navigation-Fixes
fixNavigationClicks();
// 3. Button-Fixes
fixButtonClicks();
// 4. Form-Fixes
fixFormSubmissions();
// 5. Modal-Fixes
fixModalInteractions();
// 6. Dark Mode Fix
fixDarkModeToggle();
// 7. Mobile Menu Fix
fixMobileMenu();
// 8. Dropdown-Fixes
fixDropdowns();
// 9. CSRF-Token-Fixes
fixCSRFTokens();
// 10. Auto-Refresh-Fixes
setupAutoRefresh();
window.MYP_UI_FIXED = true;
console.log('✅ Alle UI-Fixes erfolgreich angewendet!');
}
/**
* 1. Globale Click-Handler mit Event-Delegation
*/
function setupGlobalClickHandlers() {
console.log('🎯 Richte globale Click-Handler ein...');
// Entferne alte Event-Listener
document.removeEventListener('click', handleGlobalClick);
// Füge neuen Event-Listener hinzu
document.addEventListener('click', handleGlobalClick, true);
function handleGlobalClick(event) {
const target = event.target;
const closest = target.closest('a, button, [role="button"], [data-action], .clickable');
if (!closest) return;
// Verhindere doppelte Events
if (event.defaultPrevented) return;
console.log('👆 Klick erkannt auf:', closest);
// Spezielle Handler für verschiedene Elemente
if (closest.matches('a[href]')) {
handleLinkClick(event, closest);
} else if (closest.matches('button, [role="button"]')) {
handleButtonClick(event, closest);
} else if (closest.hasAttribute('data-action')) {
handleDataActionClick(event, closest);
}
}
}
/**
* Link-Klicks behandeln
*/
function handleLinkClick(event, link) {
const href = link.getAttribute('href');
if (!href || href === '#') {
event.preventDefault();
return;
}
// Externe Links in neuem Tab öffnen
if (href.startsWith('http') && !href.includes(window.location.hostname)) {
event.preventDefault();
window.open(href, '_blank', 'noopener,noreferrer');
return;
}
// Interne Navigation
if (href.startsWith('/') || href.startsWith('./') || href.startsWith('../')) {
console.log('🔗 Navigiere zu:', href);
// Lass den Browser die Navigation normal handhaben
return;
}
}
/**
* Button-Klicks behandeln
*/
function handleButtonClick(event, button) {
// Verhindere doppelte Klicks
if (button.disabled || button.classList.contains('loading')) {
event.preventDefault();
return;
}
// Spezielle Button-Typen
const buttonType = button.getAttribute('data-type') || button.type;
switch (buttonType) {
case 'logout':
event.preventDefault();
handleLogoutClick();
break;
case 'dark-mode-toggle':
event.preventDefault();
handleDarkModeToggle();
break;
case 'mobile-menu-toggle':
event.preventDefault();
handleMobileMenuToggle();
break;
case 'refresh':
event.preventDefault();
handleRefreshClick(button);
break;
default:
// Normale Button-Behandlung
console.log('🔘 Button geklickt:', button);
break;
}
}
/**
* Data-Action-Klicks behandeln
*/
function handleDataActionClick(event, element) {
event.preventDefault();
const action = element.getAttribute('data-action');
const params = getDataActionParams(element);
console.log('⚡ Data-Action ausgeführt:', action, params);
switch (action) {
case 'logout':
handleLogoutClick();
break;
case 'toggle-dark-mode':
handleDarkModeToggle();
break;
case 'toggle-mobile-menu':
handleMobileMenuToggle();
break;
case 'refresh-page':
window.location.reload();
break;
case 'go-back':
window.history.back();
break;
case 'close-modal':
closeModal(params.target);
break;
default:
console.warn('⚠️ Unbekannte Data-Action:', action);
break;
}
}
/**
* Data-Action-Parameter extrahieren
*/
function getDataActionParams(element) {
const params = {};
for (const attr of element.attributes) {
if (attr.name.startsWith('data-action-')) {
const key = attr.name.replace('data-action-', '');
params[key] = attr.value;
}
}
return params;
}
/**
* 2. Navigation-Fixes
*/
function fixNavigationClicks() {
console.log('🧭 Fixe Navigation...');
// Alle Navigations-Links finden und reparieren
const navLinks = document.querySelectorAll('nav a, .navbar a, .nav-item');
navLinks.forEach(link => {
if (!link.href || link.href === '#') {
link.style.cursor = 'pointer';
link.addEventListener('click', function(e) {
e.preventDefault();
console.log('🔗 Navigation-Link geklickt:', this);
});
}
});
}
/**
* 3. Button-Fixes
*/
function fixButtonClicks() {
console.log('🔘 Fixe Buttons...');
// Alle Buttons finden und Event-Listener hinzufügen
const buttons = document.querySelectorAll('button, [role="button"], .btn');
buttons.forEach(button => {
// Entferne alte Event-Listener
button.removeEventListener('click', handleButtonClickFix);
// Füge neuen Event-Listener hinzu
button.addEventListener('click', handleButtonClickFix);
});
function handleButtonClickFix(event) {
console.log('🔘 Button-Fix aktiviert für:', this);
// Verhindere doppelte Klicks
if (this.disabled) {
event.preventDefault();
return;
}
// Visuelles Feedback
this.style.transform = 'scale(0.95)';
setTimeout(() => {
this.style.transform = '';
}, 150);
}
}
/**
* 4. Form-Fixes
*/
function fixFormSubmissions() {
console.log('📝 Fixe Formulare...');
const forms = document.querySelectorAll('form');
forms.forEach(form => {
form.addEventListener('submit', function(event) {
console.log('📤 Formular wird abgesendet:', this);
// CSRF-Token prüfen
const csrfToken = this.querySelector('input[name="csrf_token"]');
if (!csrfToken) {
console.warn('⚠️ CSRF-Token fehlt in Formular');
addCSRFTokenToForm(this);
}
});
});
}
/**
* 5. Modal-Fixes
*/
function fixModalInteractions() {
console.log('🪟 Fixe Modals...');
// Modal-Close-Buttons
const closeButtons = document.querySelectorAll('[data-modal-close], .modal-close');
closeButtons.forEach(button => {
button.addEventListener('click', function(event) {
event.preventDefault();
const modal = this.closest('.modal, .fixed');
if (modal) {
closeModal(modal);
}
});
});
// Modal-Backdrop-Klicks
const modals = document.querySelectorAll('.modal, .fixed');
modals.forEach(modal => {
modal.addEventListener('click', function(event) {
if (event.target === this) {
closeModal(this);
}
});
});
}
/**
* 6. Dark Mode Fix
*/
function fixDarkModeToggle() {
console.log('🌙 Fixe Dark Mode...');
const darkModeToggle = document.getElementById('darkModeToggle') ||
document.querySelector('[data-action="toggle-dark-mode"]');
if (darkModeToggle) {
darkModeToggle.addEventListener('click', handleDarkModeToggle);
}
}
function handleDarkModeToggle() {
console.log('🌙 Dark Mode Toggle aktiviert');
const html = document.documentElement;
const isDark = html.classList.contains('dark');
if (isDark) {
html.classList.remove('dark');
localStorage.setItem('myp-dark-mode', 'false');
} else {
html.classList.add('dark');
localStorage.setItem('myp-dark-mode', 'true');
}
// Icons aktualisieren
updateDarkModeIcons(!isDark);
}
function updateDarkModeIcons(isDark) {
const sunIcons = document.querySelectorAll('.sun-icon');
const moonIcons = document.querySelectorAll('.moon-icon');
sunIcons.forEach(icon => {
icon.classList.toggle('hidden', isDark);
});
moonIcons.forEach(icon => {
icon.classList.toggle('hidden', !isDark);
});
}
/**
* 7. Mobile Menu Fix
*/
function fixMobileMenu() {
console.log('📱 Fixe Mobile Menu...');
const mobileMenuToggle = document.getElementById('mobileMenuToggle') ||
document.querySelector('[data-action="toggle-mobile-menu"]');
const mobileMenu = document.getElementById('mobileMenu');
if (mobileMenuToggle && mobileMenu) {
mobileMenuToggle.addEventListener('click', handleMobileMenuToggle);
}
}
function handleMobileMenuToggle() {
console.log('📱 Mobile Menu Toggle aktiviert');
const mobileMenu = document.getElementById('mobileMenu');
if (mobileMenu) {
mobileMenu.classList.toggle('hidden');
}
}
/**
* 8. Dropdown-Fixes
*/
function fixDropdowns() {
console.log('📋 Fixe Dropdowns...');
const dropdownToggles = document.querySelectorAll('[data-dropdown-toggle]');
dropdownToggles.forEach(toggle => {
toggle.addEventListener('click', function(event) {
event.preventDefault();
const targetId = this.getAttribute('data-dropdown-toggle');
const dropdown = document.getElementById(targetId);
if (dropdown) {
dropdown.classList.toggle('hidden');
}
});
});
// Schließe Dropdowns bei Klick außerhalb
document.addEventListener('click', function(event) {
const dropdowns = document.querySelectorAll('[data-dropdown-menu]');
dropdowns.forEach(dropdown => {
if (!dropdown.contains(event.target) &&
!event.target.matches('[data-dropdown-toggle]')) {
dropdown.classList.add('hidden');
}
});
});
}
/**
* 9. CSRF-Token-Fixes
*/
function fixCSRFTokens() {
console.log('🔒 Fixe CSRF-Tokens...');
const csrfToken = document.querySelector('meta[name="csrf-token"]');
if (!csrfToken) {
console.warn('⚠️ CSRF-Token Meta-Tag fehlt');
return;
}
const tokenValue = csrfToken.getAttribute('content');
// Füge CSRF-Token zu allen Formularen hinzu
const forms = document.querySelectorAll('form');
forms.forEach(form => {
if (!form.querySelector('input[name="csrf_token"]')) {
addCSRFTokenToForm(form, tokenValue);
}
});
}
function addCSRFTokenToForm(form, tokenValue = null) {
if (!tokenValue) {
const csrfMeta = document.querySelector('meta[name="csrf-token"]');
tokenValue = csrfMeta ? csrfMeta.getAttribute('content') : '';
}
if (tokenValue) {
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'csrf_token';
input.value = tokenValue;
form.appendChild(input);
}
}
/**
* 10. Auto-Refresh-Setup
*/
function setupAutoRefresh() {
console.log('🔄 Richte Auto-Refresh ein...');
// Auto-Refresh für bestimmte Seiten
const refreshInterval = 30000; // 30 Sekunden
if (window.location.pathname.includes('/dashboard') ||
window.location.pathname.includes('/printers') ||
window.location.pathname.includes('/jobs')) {
setInterval(() => {
refreshPageData();
}, refreshInterval);
}
}
function refreshPageData() {
// Implementierung für spezifische Seiten-Refreshs
console.log('🔄 Aktualisiere Seitendaten...');
}
/**
* Logout-Handler
*/
function handleLogoutClick() {
console.log('👋 Logout-Prozess gestartet');
if (confirm('Möchten Sie sich wirklich abmelden?')) {
// CSRF-Token holen
const csrfToken = document.querySelector('meta[name="csrf-token"]');
// Logout-Form erstellen
const form = document.createElement('form');
form.method = 'POST';
form.action = '/auth/logout';
form.style.display = 'none';
if (csrfToken) {
const input = document.createElement('input');
input.type = 'hidden';
input.name = 'csrf_token';
input.value = csrfToken.getAttribute('content');
form.appendChild(input);
}
document.body.appendChild(form);
form.submit();
}
}
/**
* Refresh-Handler
*/
function handleRefreshClick(button) {
console.log('🔄 Refresh-Button geklickt');
// Button-State ändern
const originalText = button.textContent;
button.textContent = 'Wird aktualisiert...';
button.disabled = true;
// Seite neu laden
setTimeout(() => {
window.location.reload();
}, 500);
}
/**
* Modal schließen
*/
function closeModal(modal) {
if (typeof modal === 'string') {
modal = document.getElementById(modal) || document.querySelector(modal);
}
if (modal) {
modal.classList.add('hidden');
modal.style.display = 'none';
}
}
/**
* Initialisierung bei DOM-Ready
*/
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeUIFixes);
} else {
initializeUIFixes();
}
// Backup-Initialisierung nach 1 Sekunde
setTimeout(initializeUIFixes, 1000);
// Globale Funktionen für Kompatibilität
window.MYP_UI_FIXES = {
init: initializeUIFixes,
handleLogout: handleLogoutClick,
handleDarkMode: handleDarkModeToggle,
handleMobileMenu: handleMobileMenuToggle,
closeModal: closeModal
};
console.log('✅ UI-Fix-Script geladen');
})();

View File

@ -576,8 +576,6 @@
</footer>
<!-- JavaScript -->
<script src="{{ url_for('static', filename='js/fix-ui-issues.js') }}"></script>
<script src="{{ url_for('static', filename='js/debug-ui.js') }}"></script>
<script src="{{ url_for('static', filename='js/ui-components.js') }}"></script>
<script src="{{ url_for('static', filename='js/dark-mode-fix.js') }}"></script>
<script src="{{ url_for('static', filename='js/optimization-features.js') }}"></script>