📝 "Fix: Resolve issues with database shm andwal files in FEHLER_BEHOBEN.md, app.py, and templates/jobs.html (#123)"
This commit is contained in:
@@ -881,7 +881,6 @@
|
||||
{% block scripts %}
|
||||
<script>
|
||||
// Globale Variablen
|
||||
window.isAdmin = {% if current_user.is_admin %}true{% else %}false{% endif %};
|
||||
let jobsData = [];
|
||||
let filteredJobs = [];
|
||||
let currentPage = 1;
|
||||
@@ -891,6 +890,9 @@ let selectedJobs = new Set();
|
||||
let refreshInterval;
|
||||
let lastUpdateTime;
|
||||
|
||||
// Benutzer-spezifische Konfiguration
|
||||
window.isAdmin = {% if current_user.is_admin %}true{% else %}false{% endif %};
|
||||
|
||||
// Job Management System
|
||||
class JobManager {
|
||||
constructor() {
|
||||
@@ -964,13 +966,25 @@ class JobManager {
|
||||
async loadPrinters() {
|
||||
try {
|
||||
const response = await fetch('/api/printers');
|
||||
|
||||
if (!response.ok) {
|
||||
console.error(`HTTP Error ${response.status}: ${response.statusText}`);
|
||||
this.showError(`Fehler beim Laden der Drucker: ${response.statusText}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.populatePrinterDropdowns(data.printers || []);
|
||||
if (data.success && data.printers) {
|
||||
this.populatePrinterDropdowns(data.printers);
|
||||
console.log(`${data.printers.length} Drucker erfolgreich geladen`);
|
||||
} else {
|
||||
console.error('API Response structure:', data);
|
||||
this.showError('Fehler beim Laden der Drucker: Unerwartete Response-Struktur');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error loading printers:', error);
|
||||
this.showError(`Fehler beim Laden der Drucker: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1393,6 +1407,8 @@ class JobManager {
|
||||
|
||||
animateCounter(elementId, targetValue) {
|
||||
const element = document.getElementById(elementId);
|
||||
if (!element) return;
|
||||
|
||||
const currentValue = parseInt(element.textContent) || 0;
|
||||
const duration = 1000;
|
||||
const steps = 30;
|
||||
@@ -1449,14 +1465,50 @@ class JobManager {
|
||||
};
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
// Implementation für Error Display
|
||||
console.error(message);
|
||||
initializeStatistics() {
|
||||
// Initialize any statistics-related functionality
|
||||
console.log('Statistics initialized');
|
||||
}
|
||||
|
||||
showSuccess(message) {
|
||||
// Implementation für Success Display
|
||||
console.log(message);
|
||||
updatePagination() {
|
||||
const totalPages = Math.ceil(filteredJobs.length / itemsPerPage);
|
||||
const paginationContainer = document.getElementById('pagination-container');
|
||||
|
||||
if (totalPages <= 1) {
|
||||
paginationContainer.classList.add('hidden');
|
||||
return;
|
||||
}
|
||||
|
||||
paginationContainer.classList.remove('hidden');
|
||||
|
||||
// Update page info
|
||||
const pageInfo = document.getElementById('page-info');
|
||||
const startIndex = (currentPage - 1) * itemsPerPage + 1;
|
||||
const endIndex = Math.min(currentPage * itemsPerPage, filteredJobs.length);
|
||||
pageInfo.textContent = `${startIndex}-${endIndex} von ${filteredJobs.length}`;
|
||||
|
||||
// Update navigation buttons
|
||||
document.getElementById('prev-page').disabled = currentPage === 1;
|
||||
document.getElementById('next-page').disabled = currentPage === totalPages;
|
||||
}
|
||||
|
||||
toggleJobSelection(jobId) {
|
||||
if (selectedJobs.has(jobId)) {
|
||||
selectedJobs.delete(jobId);
|
||||
} else {
|
||||
selectedJobs.add(jobId);
|
||||
}
|
||||
|
||||
// Update selected count
|
||||
document.getElementById('selected-count').textContent = selectedJobs.size;
|
||||
|
||||
// Show/hide batch actions
|
||||
const batchActions = document.getElementById('batch-actions');
|
||||
if (selectedJobs.size > 0) {
|
||||
batchActions.classList.remove('hidden');
|
||||
} else {
|
||||
batchActions.classList.add('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
closeAllModals() {
|
||||
@@ -1468,6 +1520,325 @@ class JobManager {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// File handling methods
|
||||
handleDragOver(e) {
|
||||
e.preventDefault();
|
||||
e.target.classList.add('drag-over');
|
||||
}
|
||||
|
||||
handleDragLeave(e) {
|
||||
e.preventDefault();
|
||||
e.target.classList.remove('drag-over');
|
||||
}
|
||||
|
||||
handleFileDrop(e) {
|
||||
e.preventDefault();
|
||||
e.target.classList.remove('drag-over');
|
||||
const files = e.dataTransfer.files;
|
||||
if (files.length > 0) {
|
||||
this.handleFileSelect({target: {files: files}});
|
||||
}
|
||||
}
|
||||
|
||||
handleFileSelect(e) {
|
||||
const file = e.target.files[0];
|
||||
if (file) {
|
||||
const preview = document.getElementById('file-preview');
|
||||
preview.textContent = `Ausgewählte Datei: ${file.name} (${(file.size / 1024 / 1024).toFixed(2)} MB)`;
|
||||
preview.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
// ===== JOB MANAGEMENT ACTIONS =====
|
||||
|
||||
async startJob(jobId) {
|
||||
try {
|
||||
const response = await fetch(`/api/jobs/${jobId}/start`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': this.getCSRFToken()
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showSuccess(`Job erfolgreich gestartet: ${data.message}`);
|
||||
this.loadJobs(); // Refresh job list
|
||||
} else {
|
||||
this.showError(`Fehler beim Starten: ${data.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error starting job:', error);
|
||||
this.showError('Fehler beim Starten des Jobs');
|
||||
}
|
||||
}
|
||||
|
||||
async pauseJob(jobId) {
|
||||
try {
|
||||
const response = await fetch(`/api/jobs/${jobId}/pause`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': this.getCSRFToken()
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showSuccess(`Job erfolgreich pausiert: ${data.message}`);
|
||||
this.loadJobs(); // Refresh job list
|
||||
} else {
|
||||
this.showError(`Fehler beim Pausieren: ${data.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error pausing job:', error);
|
||||
this.showError('Fehler beim Pausieren des Jobs');
|
||||
}
|
||||
}
|
||||
|
||||
async resumeJob(jobId) {
|
||||
try {
|
||||
const response = await fetch(`/api/jobs/${jobId}/resume`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': this.getCSRFToken()
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showSuccess(`Job erfolgreich fortgesetzt: ${data.message}`);
|
||||
this.loadJobs(); // Refresh job list
|
||||
} else {
|
||||
this.showError(`Fehler beim Fortsetzen: ${data.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error resuming job:', error);
|
||||
this.showError('Fehler beim Fortsetzen des Jobs');
|
||||
}
|
||||
}
|
||||
|
||||
async deleteJob(jobId) {
|
||||
if (!confirm('Sind Sie sicher, dass Sie diesen Job löschen möchten?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/jobs/${jobId}`, {
|
||||
method: 'DELETE',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': this.getCSRFToken()
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showSuccess('Job erfolgreich gelöscht');
|
||||
this.loadJobs(); // Refresh job list
|
||||
} else {
|
||||
this.showError(`Fehler beim Löschen: ${data.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error deleting job:', error);
|
||||
this.showError('Fehler beim Löschen des Jobs');
|
||||
}
|
||||
}
|
||||
|
||||
// ===== FORM HANDLERS =====
|
||||
|
||||
setupFormHandlers() {
|
||||
// Quick Reservation Form Handler
|
||||
const quickForm = document.getElementById('quickReservationForm');
|
||||
if (quickForm) {
|
||||
quickForm.addEventListener('submit', this.handleQuickReservation.bind(this));
|
||||
}
|
||||
|
||||
// Main Job Form Handler
|
||||
const mainForm = document.getElementById('newJobForm');
|
||||
if (mainForm) {
|
||||
mainForm.addEventListener('submit', this.handleJobSubmit.bind(this));
|
||||
}
|
||||
|
||||
// Set default start time to now
|
||||
const startTimeInput = document.getElementById('quick-start-time');
|
||||
if (startTimeInput) {
|
||||
const now = new Date();
|
||||
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
|
||||
startTimeInput.value = now.toISOString().slice(0, 16);
|
||||
}
|
||||
|
||||
const mainStartTimeInput = document.getElementById('start_time');
|
||||
if (mainStartTimeInput) {
|
||||
const now = new Date();
|
||||
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
|
||||
mainStartTimeInput.value = now.toISOString().slice(0, 16);
|
||||
}
|
||||
}
|
||||
|
||||
async handleQuickReservation(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(e.target);
|
||||
const jobData = {
|
||||
printer_id: parseInt(formData.get('printer_id')),
|
||||
start_iso: formData.get('start_time'),
|
||||
duration_minutes: parseInt(formData.get('duration')),
|
||||
name: formData.get('title') || 'Schnell-Reservierung'
|
||||
};
|
||||
|
||||
// Validierung
|
||||
if (!jobData.printer_id) {
|
||||
this.showError('Bitte wählen Sie einen Drucker aus');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!jobData.start_iso) {
|
||||
this.showError('Bitte geben Sie eine Startzeit an');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!jobData.duration_minutes || jobData.duration_minutes < 15) {
|
||||
this.showError('Dauer muss mindestens 15 Minuten betragen');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/jobs', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': this.getCSRFToken()
|
||||
},
|
||||
body: JSON.stringify(jobData)
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showSuccess('Schnell-Reservierung erfolgreich erstellt!');
|
||||
closeQuickReservationModal();
|
||||
this.loadJobs(); // Refresh job list
|
||||
|
||||
// Reset form
|
||||
e.target.reset();
|
||||
|
||||
// Show additional info if immediate start
|
||||
if (data.immediate_start) {
|
||||
setTimeout(() => {
|
||||
this.showSuccess('Job wurde sofort gestartet und Drucker eingeschaltet!');
|
||||
}, 1000);
|
||||
}
|
||||
} else {
|
||||
this.showError(`Fehler beim Erstellen: ${data.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating quick reservation:', error);
|
||||
this.showError('Fehler beim Erstellen der Reservierung');
|
||||
}
|
||||
}
|
||||
|
||||
async handleJobSubmit(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const formData = new FormData(e.target);
|
||||
const jobData = {
|
||||
printer_id: parseInt(formData.get('printer_id')),
|
||||
start_iso: formData.get('start_time'),
|
||||
duration_minutes: parseInt(formData.get('duration')),
|
||||
name: formData.get('job_title') || 'Neuer Druckjob'
|
||||
};
|
||||
|
||||
// File upload handling (optional)
|
||||
const fileInput = document.getElementById('stl_file');
|
||||
if (fileInput.files.length > 0) {
|
||||
// TODO: Implement file upload
|
||||
console.log('File selected:', fileInput.files[0]);
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/jobs', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': this.getCSRFToken()
|
||||
},
|
||||
body: JSON.stringify(jobData)
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.success) {
|
||||
this.showSuccess('Job erfolgreich erstellt!');
|
||||
this.loadJobs(); // Refresh job list
|
||||
|
||||
// Reset form
|
||||
e.target.reset();
|
||||
|
||||
// Collapse form
|
||||
toggleFormExpansion();
|
||||
} else {
|
||||
this.showError(`Fehler beim Erstellen: ${data.error}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error creating job:', error);
|
||||
this.showError('Fehler beim Erstellen des Jobs');
|
||||
}
|
||||
}
|
||||
|
||||
// ===== UTILITY FUNCTIONS =====
|
||||
|
||||
getCSRFToken() {
|
||||
const token = document.querySelector('meta[name=csrf-token]');
|
||||
return token ? token.getAttribute('content') : '';
|
||||
}
|
||||
|
||||
showSuccess(message) {
|
||||
// Create and show success toast
|
||||
this.showToast(message, 'success');
|
||||
}
|
||||
|
||||
showError(message) {
|
||||
// Create and show error toast
|
||||
this.showToast(message, 'error');
|
||||
}
|
||||
|
||||
showToast(message, type = 'info') {
|
||||
// Simple toast implementation
|
||||
const toast = document.createElement('div');
|
||||
toast.className = `fixed top-4 right-4 p-4 rounded-lg shadow-lg z-50 ${
|
||||
type === 'success' ? 'bg-green-500 text-white' :
|
||||
type === 'error' ? 'bg-red-500 text-white' :
|
||||
'bg-blue-500 text-white'
|
||||
}`;
|
||||
toast.textContent = message;
|
||||
|
||||
document.body.appendChild(toast);
|
||||
|
||||
// Animate in
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(0)';
|
||||
toast.style.opacity = '1';
|
||||
}, 10);
|
||||
|
||||
// Remove after 5 seconds
|
||||
setTimeout(() => {
|
||||
toast.style.transform = 'translateX(100%)';
|
||||
toast.style.opacity = '0';
|
||||
setTimeout(() => {
|
||||
if (toast.parentNode) {
|
||||
toast.parentNode.removeChild(toast);
|
||||
}
|
||||
}, 300);
|
||||
}, 5000);
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Animations
|
||||
|
Reference in New Issue
Block a user