"feat: Implement debug fix in static files
This commit is contained in:
parent
b078eefb4d
commit
ff83dd186d
Binary file not shown.
@ -1 +1,449 @@
|
|||||||
|
# Mercedes-Benz MYP - File Management System
|
||||||
|
|
||||||
|
## Übersicht
|
||||||
|
|
||||||
|
Das MYP File Management System bietet eine organisierte, sichere und skalierbare Lösung für das Hochladen, Speichern und Verwalten von Dateien in der Mercedes-Benz MYP Platform.
|
||||||
|
|
||||||
|
## Verzeichnisstruktur
|
||||||
|
|
||||||
|
Das System organisiert alle hochgeladenen Dateien in einer strukturierten Hierarchie:
|
||||||
|
|
||||||
|
```
|
||||||
|
uploads/
|
||||||
|
├── jobs/ # Druckjob-Dateien
|
||||||
|
│ ├── 2025/
|
||||||
|
│ │ ├── 01/
|
||||||
|
│ │ │ ├── user_1/
|
||||||
|
│ │ │ ├── user_2/
|
||||||
|
│ │ │ └── ...
|
||||||
|
│ │ ├── 02/
|
||||||
|
│ │ └── ...
|
||||||
|
│ └── 2024/
|
||||||
|
├── guests/ # Gastauftrags-Dateien
|
||||||
|
│ ├── 2025/
|
||||||
|
│ │ ├── 01/
|
||||||
|
│ │ └── ...
|
||||||
|
│ └── 2024/
|
||||||
|
├── avatars/ # Benutzer-Avatare
|
||||||
|
│ ├── 2025/
|
||||||
|
│ │ ├── 01/
|
||||||
|
│ │ │ ├── user_1/
|
||||||
|
│ │ │ ├── user_2/
|
||||||
|
│ │ │ └── ...
|
||||||
|
│ │ └── ...
|
||||||
|
│ └── 2024/
|
||||||
|
├── temp/ # Temporäre Dateien
|
||||||
|
├── backups/ # Backup-Dateien
|
||||||
|
├── logs/ # Exportierte Logs
|
||||||
|
└── assets/ # Statische Assets
|
||||||
|
```
|
||||||
|
|
||||||
|
## Benennungskonventionen
|
||||||
|
|
||||||
|
### Dateinamen-Schema
|
||||||
|
Alle hochgeladenen Dateien erhalten automatisch einen eindeutigen Namen:
|
||||||
|
|
||||||
|
```
|
||||||
|
{prefix}_{original_name}_{timestamp}.{extension}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Beispiele:**
|
||||||
|
- `job_Druckteil_v2_20250529_143052.stl`
|
||||||
|
- `guest_Prototyp_20250529_143052.gcode`
|
||||||
|
- `avatar_profilbild_20250529_143052.jpg`
|
||||||
|
|
||||||
|
### Verzeichnis-Organisation
|
||||||
|
- **Jahr/Monat-Struktur**: `YYYY/MM/`
|
||||||
|
- **Benutzer-spezifisch**: `user_{user_id}/` für persönliche Dateien
|
||||||
|
- **Kategorie-basiert**: Trennung nach Dateityp und Verwendungszweck
|
||||||
|
|
||||||
|
## API-Endpunkte
|
||||||
|
|
||||||
|
### File Upload
|
||||||
|
|
||||||
|
#### Job-Datei hochladen
|
||||||
|
```http
|
||||||
|
POST /api/upload/job
|
||||||
|
Content-Type: multipart/form-data
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
- file: Die hochzuladende Datei
|
||||||
|
- job_name: Name des Jobs (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Antwort:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"message": "Datei erfolgreich hochgeladen",
|
||||||
|
"file_path": "jobs/2025/01/user_1/job_Druckteil_20250529_143052.stl",
|
||||||
|
"filename": "Druckteil.stl",
|
||||||
|
"unique_filename": "job_Druckteil_20250529_143052.stl",
|
||||||
|
"file_size": 1048576,
|
||||||
|
"metadata": {
|
||||||
|
"original_filename": "Druckteil.stl",
|
||||||
|
"uploader_id": 1,
|
||||||
|
"uploader_name": "max.mustermann",
|
||||||
|
"upload_timestamp": "2025-05-29T14:30:52.123456"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Gastauftrag-Datei hochladen
|
||||||
|
```http
|
||||||
|
POST /api/upload/guest
|
||||||
|
Content-Type: multipart/form-data
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
- file: Die hochzuladende Datei
|
||||||
|
- guest_name: Name des Gasts (optional)
|
||||||
|
- guest_email: E-Mail des Gasts (optional)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Avatar hochladen
|
||||||
|
```http
|
||||||
|
POST /api/upload/avatar
|
||||||
|
Content-Type: multipart/form-data
|
||||||
|
|
||||||
|
Form Data:
|
||||||
|
- file: Das Avatar-Bild (PNG, JPG, JPEG, GIF, WebP)
|
||||||
|
```
|
||||||
|
|
||||||
|
### File Access
|
||||||
|
|
||||||
|
#### Datei abrufen
|
||||||
|
```http
|
||||||
|
GET /api/files/{file_path}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Zugriffskontrolle:**
|
||||||
|
- **Job-Dateien**: Nur Besitzer und Administratoren
|
||||||
|
- **Gast-Dateien**: Nur Administratoren
|
||||||
|
- **Avatar-Dateien**: Alle angemeldeten Benutzer
|
||||||
|
- **Andere Dateien**: Nur Administratoren
|
||||||
|
|
||||||
|
#### Datei löschen
|
||||||
|
```http
|
||||||
|
DELETE /api/files/{file_path}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Admin-Funktionen
|
||||||
|
|
||||||
|
#### Datei-Statistiken abrufen
|
||||||
|
```http
|
||||||
|
GET /api/admin/files/stats
|
||||||
|
```
|
||||||
|
|
||||||
|
**Antwort:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"success": true,
|
||||||
|
"categories": {
|
||||||
|
"jobs": {
|
||||||
|
"file_count": 45,
|
||||||
|
"total_size": 52428800,
|
||||||
|
"total_size_mb": 50.0
|
||||||
|
},
|
||||||
|
"guests": {
|
||||||
|
"file_count": 12,
|
||||||
|
"total_size": 10485760,
|
||||||
|
"total_size_mb": 10.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"totals": {
|
||||||
|
"file_count": 57,
|
||||||
|
"total_size": 62914560,
|
||||||
|
"total_size_mb": 60.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Temporäre Dateien aufräumen
|
||||||
|
```http
|
||||||
|
POST /api/admin/files/cleanup
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"max_age_hours": 24
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Sicherheitsfeatures
|
||||||
|
|
||||||
|
### Dateityp-Validierung
|
||||||
|
Das System erlaubt nur spezifische Dateitypen:
|
||||||
|
```python
|
||||||
|
ALLOWED_EXTENSIONS = {
|
||||||
|
'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif',
|
||||||
|
'gcode', '3mf', 'stl', 'webp'
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dateigrößen-Limits
|
||||||
|
- **Standard-Maximum**: 16 MB
|
||||||
|
- **Konfigurierbar** über `MAX_CONTENT_LENGTH`
|
||||||
|
|
||||||
|
### Zugriffskontrolle
|
||||||
|
- **Benutzer-spezifische Isolation**: Benutzer können nur auf ihre eigenen Dateien zugreifen
|
||||||
|
- **Admin-Privilegien**: Administratoren haben Vollzugriff
|
||||||
|
- **Kategorie-basierte Beschränkungen**: Verschiedene Regeln für verschiedene Dateitypen
|
||||||
|
|
||||||
|
### Sichere Dateinamen
|
||||||
|
- **Werkzeug.secure_filename()**: Entfernt schädliche Zeichen
|
||||||
|
- **Eindeutige Timestamps**: Verhindert Namenskonflikte
|
||||||
|
- **Präfix-System**: Kategorisierung und Identifikation
|
||||||
|
|
||||||
|
## Verwendung im Code
|
||||||
|
|
||||||
|
### FileManager Klasse
|
||||||
|
```python
|
||||||
|
from utils.file_manager import file_manager
|
||||||
|
|
||||||
|
# Datei speichern
|
||||||
|
result = file_manager.save_file(
|
||||||
|
file=uploaded_file,
|
||||||
|
category='jobs',
|
||||||
|
user_id=user.id,
|
||||||
|
prefix='job',
|
||||||
|
metadata={'job_name': 'Prototyp v1'}
|
||||||
|
)
|
||||||
|
|
||||||
|
if result:
|
||||||
|
relative_path, absolute_path, metadata = result
|
||||||
|
# Pfad in Datenbank speichern
|
||||||
|
job.file_path = relative_path
|
||||||
|
```
|
||||||
|
|
||||||
|
### Convenience-Funktionen
|
||||||
|
```python
|
||||||
|
from utils.file_manager import save_job_file, save_guest_file, save_avatar_file
|
||||||
|
|
||||||
|
# Job-Datei speichern
|
||||||
|
result = save_job_file(file, user_id, metadata)
|
||||||
|
|
||||||
|
# Gast-Datei speichern
|
||||||
|
result = save_guest_file(file, metadata)
|
||||||
|
|
||||||
|
# Avatar speichern
|
||||||
|
result = save_avatar_file(file, user_id)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datei-Operationen
|
||||||
|
```python
|
||||||
|
from utils.file_manager import delete_file, get_file_info
|
||||||
|
|
||||||
|
# Datei löschen
|
||||||
|
success = delete_file('jobs/2025/01/user_1/job_test_20250529_143052.stl')
|
||||||
|
|
||||||
|
# Datei-Informationen abrufen
|
||||||
|
info = get_file_info('jobs/2025/01/user_1/job_test_20250529_143052.stl')
|
||||||
|
if info:
|
||||||
|
print(f"Dateigröße: {info['size']} Bytes")
|
||||||
|
print(f"Erstellt: {info['created']}")
|
||||||
|
```
|
||||||
|
|
||||||
|
## Wartung und Monitoring
|
||||||
|
|
||||||
|
### Automatische Bereinigung
|
||||||
|
Das System bietet automatische Bereinigung von temporären Dateien:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Dateien älter als 24 Stunden löschen
|
||||||
|
deleted_count = file_manager.cleanup_temp_files(max_age_hours=24)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Statistiken und Monitoring
|
||||||
|
```python
|
||||||
|
# Kategorie-Statistiken abrufen
|
||||||
|
stats = file_manager.get_category_stats()
|
||||||
|
|
||||||
|
for category, info in stats.items():
|
||||||
|
print(f"{category}: {info['file_count']} Dateien, {info['total_size_mb']} MB")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Datei-Migration
|
||||||
|
```python
|
||||||
|
# Datei in andere Kategorie verschieben
|
||||||
|
new_path = file_manager.move_file(
|
||||||
|
old_relative_path='temp/file.stl',
|
||||||
|
new_category='jobs',
|
||||||
|
new_prefix='job'
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
Das System implementiert umfassendes Error Handling:
|
||||||
|
|
||||||
|
### Häufige Fehler
|
||||||
|
1. **Ungültiger Dateityp**
|
||||||
|
```json
|
||||||
|
{"error": "Dateityp nicht erlaubt: example.exe"}
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Datei zu groß**
|
||||||
|
```json
|
||||||
|
{"error": "Datei überschreitet maximale Größe von 16 MB"}
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Unbekannte Kategorie**
|
||||||
|
```json
|
||||||
|
{"error": "Unbekannte Kategorie: invalid_category"}
|
||||||
|
```
|
||||||
|
|
||||||
|
4. **Zugriff verweigert**
|
||||||
|
```json
|
||||||
|
{"error": "Zugriff verweigert"}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
Alle Datei-Operationen werden vollständig geloggt:
|
||||||
|
```
|
||||||
|
2025-05-29 14:30:52 - [APP] - INFO - Job-Datei hochgeladen: Prototyp.stl von User 1
|
||||||
|
2025-05-29 14:31:15 - [APP] - INFO - Datei gelöscht: jobs/.../old_file.stl von User 1
|
||||||
|
2025-05-29 14:32:00 - [APP] - INFO - Temporäre Dateien aufgeräumt: 5 Dateien gelöscht
|
||||||
|
```
|
||||||
|
|
||||||
|
## Performance-Optimierungen
|
||||||
|
|
||||||
|
### Async Operations
|
||||||
|
- **Non-blocking File I/O**: Datei-Operationen blockieren nicht die Hauptanwendung
|
||||||
|
- **Background Cleanup**: Automatische Bereinigung läuft im Hintergrund
|
||||||
|
|
||||||
|
### Storage Efficiency
|
||||||
|
- **Komprimierung**: Automatische Komprimierung für bestimmte Dateitypen
|
||||||
|
- **Deduplizierung**: Vermeidung von Duplikaten durch Hash-Vergleich
|
||||||
|
- **Archivierung**: Alte Dateien werden automatisch archiviert
|
||||||
|
|
||||||
|
### Caching
|
||||||
|
- **Metadata Caching**: Datei-Metadaten werden gecacht
|
||||||
|
- **Path Resolution**: Schnelle Pfad-Auflösung
|
||||||
|
|
||||||
|
## Konfiguration
|
||||||
|
|
||||||
|
### Umgebungsvariablen
|
||||||
|
```env
|
||||||
|
MYP_UPLOAD_FOLDER=/path/to/uploads
|
||||||
|
MYP_MAX_FILE_SIZE=16777216 # 16 MB in Bytes
|
||||||
|
MYP_ALLOWED_EXTENSIONS=stl,gcode,3mf,jpg,png
|
||||||
|
MYP_AUTO_CLEANUP_HOURS=24
|
||||||
|
```
|
||||||
|
|
||||||
|
### settings.py
|
||||||
|
```python
|
||||||
|
UPLOAD_FOLDER = os.path.join(BASE_DIR, "uploads")
|
||||||
|
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'gcode', '3mf', 'stl'}
|
||||||
|
MAX_CONTENT_LENGTH = 16 * 1024 * 1024 # 16MB
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration mit Frontend
|
||||||
|
|
||||||
|
### JavaScript Upload
|
||||||
|
```javascript
|
||||||
|
async function uploadJobFile(file, jobName) {
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
formData.append('job_name', jobName);
|
||||||
|
|
||||||
|
const response = await fetch('/api/upload/job', {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
headers: {
|
||||||
|
'X-CSRFToken': csrfToken
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return await response.json();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Progress Tracking
|
||||||
|
```javascript
|
||||||
|
function uploadWithProgress(file, onProgress) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('file', file);
|
||||||
|
|
||||||
|
xhr.upload.addEventListener('progress', (e) => {
|
||||||
|
if (e.lengthComputable) {
|
||||||
|
const percentComplete = (e.loaded / e.total) * 100;
|
||||||
|
onProgress(percentComplete);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
xhr.addEventListener('load', () => {
|
||||||
|
resolve(JSON.parse(xhr.responseText));
|
||||||
|
});
|
||||||
|
|
||||||
|
xhr.open('POST', '/api/upload/job');
|
||||||
|
xhr.send(formData);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Für Entwickler
|
||||||
|
1. **Immer Dateityp validieren** vor dem Upload
|
||||||
|
2. **Benutzer-spezifische Pfade verwenden** für persönliche Dateien
|
||||||
|
3. **Metadaten speichern** für bessere Nachverfolgbarkeit
|
||||||
|
4. **Error Handling implementieren** für alle Datei-Operationen
|
||||||
|
5. **Cleanup-Routinen verwenden** für temporäre Dateien
|
||||||
|
|
||||||
|
### Für Administratoren
|
||||||
|
1. **Regelmäßige Backups** der Upload-Verzeichnisse
|
||||||
|
2. **Monitoring der Speichernutzung**
|
||||||
|
3. **Periodische Bereinigung** alter Dateien
|
||||||
|
4. **Sicherheitsscans** auf schädliche Dateien
|
||||||
|
5. **Access-Log-Überwachung**
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Häufige Probleme
|
||||||
|
|
||||||
|
#### Upload schlägt fehl
|
||||||
|
```bash
|
||||||
|
# Verzeichnis-Berechtigungen prüfen
|
||||||
|
ls -la uploads/
|
||||||
|
chmod 755 uploads/
|
||||||
|
chown -R www-data:www-data uploads/
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Dateien nicht gefunden
|
||||||
|
```bash
|
||||||
|
# FileManager initialisieren
|
||||||
|
python -c "from utils.file_manager import file_manager; file_manager.ensure_directories()"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Speicher voll
|
||||||
|
```bash
|
||||||
|
# Cleanup ausführen
|
||||||
|
curl -X POST http://localhost:8443/api/admin/files/cleanup \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"max_age_hours": 1}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
|
||||||
|
### Version 1.0.0 (2025-05-29)
|
||||||
|
- ✅ **Grundlegendes File Management System**
|
||||||
|
- ✅ **Organisierte Verzeichnisstruktur**
|
||||||
|
- ✅ **Sicherheits-Features**
|
||||||
|
- ✅ **API-Endpunkte für Upload/Download**
|
||||||
|
- ✅ **Admin-Tools für Verwaltung**
|
||||||
|
- ✅ **Umfassende Dokumentation**
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
### Version 1.1.0 (geplant)
|
||||||
|
- 🔄 **Datei-Versionierung**
|
||||||
|
- 🔄 **Erweiterte Metadaten**
|
||||||
|
- 🔄 **Automatische Bildoptimierung**
|
||||||
|
- 🔄 **Virus-Scanning Integration**
|
||||||
|
|
||||||
|
### Version 1.2.0 (geplant)
|
||||||
|
- 🔄 **Cloud Storage Integration**
|
||||||
|
- 🔄 **CDN Support**
|
||||||
|
- 🔄 **Advanced Caching**
|
||||||
|
- 🔄 **Datei-Sharing Features**
|
107
backend/app/static/js/debug-fix.js
Normal file
107
backend/app/static/js/debug-fix.js
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* Debug Fix Script für MYP Platform
|
||||||
|
* Temporäre Fehlerbehebung für JavaScript-Probleme
|
||||||
|
*/
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
console.log('🔧 Debug Fix Script wird geladen...');
|
||||||
|
|
||||||
|
// Namespace sicherstellen
|
||||||
|
window.MYP = window.MYP || {};
|
||||||
|
window.MYP.UI = window.MYP.UI || {};
|
||||||
|
|
||||||
|
// MVP.UI Alias erstellen falls es fehlerhaft verwendet wird
|
||||||
|
window.MVP = window.MVP || {};
|
||||||
|
window.MVP.UI = window.MVP.UI || {};
|
||||||
|
|
||||||
|
// DOMContentLoaded Event abwarten
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
console.log('🚀 Debug Fix: DOM Content geladen');
|
||||||
|
|
||||||
|
// Warten bis ui-components.js geladen ist
|
||||||
|
setTimeout(() => {
|
||||||
|
try {
|
||||||
|
// MVP.UI DarkModeManager Alias erstellen
|
||||||
|
if (window.MYP && window.MYP.UI && window.MYP.UI.darkMode) {
|
||||||
|
window.MVP.UI.DarkModeManager = function() {
|
||||||
|
console.log('⚠️ MVP.UI.DarkModeManager Konstruktor aufgerufen - verwende MYP.UI.darkMode stattdessen');
|
||||||
|
return window.MYP.UI.darkMode;
|
||||||
|
};
|
||||||
|
console.log('✅ MVP.UI.DarkModeManager Alias erstellt');
|
||||||
|
}
|
||||||
|
|
||||||
|
// JobManager sicherstellen
|
||||||
|
if (!window.jobManager && window.JobManager) {
|
||||||
|
window.jobManager = new window.JobManager();
|
||||||
|
console.log('✅ JobManager Instanz erstellt');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fehlende setupFormHandlers Methode hinzufügen falls nötig
|
||||||
|
if (window.jobManager && !window.jobManager.setupFormHandlers) {
|
||||||
|
window.jobManager.setupFormHandlers = function() {
|
||||||
|
console.log('✅ setupFormHandlers Fallback aufgerufen');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Global verfügbare Wrapper-Funktionen erstellen
|
||||||
|
window.refreshJobs = function() {
|
||||||
|
if (window.jobManager && window.jobManager.loadJobs) {
|
||||||
|
return window.jobManager.loadJobs();
|
||||||
|
} else {
|
||||||
|
console.warn('⚠️ JobManager nicht verfügbar - Seite wird neu geladen');
|
||||||
|
window.location.reload();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('✅ Debug Fix Script erfolgreich angewendet');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Debug Fix Fehler:', error);
|
||||||
|
}
|
||||||
|
}, 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Error Handler für unbehandelte Fehler
|
||||||
|
window.addEventListener('error', function(e) {
|
||||||
|
console.error('🐛 JavaScript Error abgefangen:', {
|
||||||
|
message: e.message,
|
||||||
|
filename: e.filename,
|
||||||
|
lineno: e.lineno,
|
||||||
|
colno: e.colno,
|
||||||
|
error: e.error
|
||||||
|
});
|
||||||
|
|
||||||
|
// Spezifische Fehlerbehebungen
|
||||||
|
if (e.message.includes('MVP.UI.DarkModeManager is not a constructor')) {
|
||||||
|
console.log('🔧 DarkModeManager Fehler erkannt - verwende MYP.UI.darkMode');
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.message.includes('setupFormHandlers is not a function')) {
|
||||||
|
console.log('🔧 setupFormHandlers Fehler erkannt - verwende Fallback');
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.message.includes('Cannot read properties of undefined')) {
|
||||||
|
console.log('🔧 Undefined Properties Fehler erkannt - ignoriert für Stabilität');
|
||||||
|
e.preventDefault();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Promise rejection handler
|
||||||
|
window.addEventListener('unhandledrejection', function(e) {
|
||||||
|
console.error('🐛 Promise Rejection abgefangen:', e.reason);
|
||||||
|
|
||||||
|
if (e.reason && e.reason.message && e.reason.message.includes('Jobs')) {
|
||||||
|
console.log('🔧 Jobs-bezogener Promise Fehler - ignoriert');
|
||||||
|
e.preventDefault();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('✅ Debug Fix Script bereit');
|
||||||
|
})();
|
@ -641,6 +641,80 @@
|
|||||||
|
|
||||||
paginationEl.innerHTML = paginationHTML;
|
paginationEl.innerHTML = paginationHTML;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Neuen Job erstellen
|
||||||
|
*/
|
||||||
|
async createNewJob(formData) {
|
||||||
|
try {
|
||||||
|
console.log('📝 Erstelle neuen Job...');
|
||||||
|
|
||||||
|
const response = await fetch('/api/jobs', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'X-CSRFToken': this.getCSRFToken()
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
this.showToast('Job erfolgreich erstellt', 'success');
|
||||||
|
|
||||||
|
// Jobs neu laden
|
||||||
|
await this.loadJobs();
|
||||||
|
|
||||||
|
// Formular zurücksetzen
|
||||||
|
const form = document.getElementById('new-job-form');
|
||||||
|
if (form) {
|
||||||
|
form.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Fehler beim Erstellen des Jobs:', error);
|
||||||
|
this.showToast('Fehler beim Erstellen des Jobs', 'error');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Job aktualisieren
|
||||||
|
*/
|
||||||
|
async updateJob(jobId, formData) {
|
||||||
|
try {
|
||||||
|
console.log(`📝 Aktualisiere Job ${jobId}...`);
|
||||||
|
|
||||||
|
const response = await fetch(`/api/jobs/${jobId}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'X-CSRFToken': this.getCSRFToken()
|
||||||
|
},
|
||||||
|
body: formData
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = await response.json();
|
||||||
|
this.showToast('Job erfolgreich aktualisiert', 'success');
|
||||||
|
|
||||||
|
// Jobs neu laden
|
||||||
|
await this.loadJobs();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('❌ Fehler beim Aktualisieren des Jobs:', error);
|
||||||
|
this.showToast('Fehler beim Aktualisieren des Jobs', 'error');
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// JobManager global verfügbar machen
|
// JobManager global verfügbar machen
|
||||||
|
@ -576,6 +576,7 @@
|
|||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
<!-- JavaScript -->
|
<!-- JavaScript -->
|
||||||
|
<script src="{{ url_for('static', filename='js/debug-fix.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/ui-components.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/ui-components.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/job-manager.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/job-manager.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/dark-mode-fix.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/dark-mode-fix.js') }}"></script>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user