"Refactor guest blueprint templates and database schema"
This commit is contained in:
parent
a1f9e70fd2
commit
2e306cb0df
@ -4,6 +4,10 @@ import bcrypt
|
||||
from datetime import datetime, timedelta
|
||||
from flask import Blueprint, render_template, request, jsonify, redirect, url_for, abort, session, flash
|
||||
from flask_login import current_user, login_required
|
||||
from flask_wtf import FlaskForm
|
||||
from flask_wtf.file import FileField, FileAllowed
|
||||
from wtforms import StringField, TextAreaField, IntegerField, SelectField
|
||||
from wtforms.validators import DataRequired, Email, Optional, NumberRange
|
||||
from functools import wraps
|
||||
from sqlalchemy import desc
|
||||
from sqlalchemy.orm import joinedload
|
||||
@ -14,6 +18,19 @@ from utils.logging_config import get_logger
|
||||
guest_blueprint = Blueprint('guest', __name__)
|
||||
logger = get_logger("guest")
|
||||
|
||||
# Flask-WTF Formular für Gastanfragen
|
||||
class GuestRequestForm(FlaskForm):
|
||||
name = StringField('Vollständiger Name', validators=[DataRequired()])
|
||||
email = StringField('E-Mail-Adresse', validators=[DataRequired(), Email()])
|
||||
printer_id = SelectField('Drucker auswählen', coerce=int, validators=[Optional()])
|
||||
duration_min = IntegerField('Geschätzte Dauer (Minuten)',
|
||||
validators=[DataRequired(), NumberRange(min=1, max=1440)],
|
||||
default=60)
|
||||
reason = TextAreaField('Projektbeschreibung', validators=[Optional()])
|
||||
file = FileField('3D-Datei hochladen',
|
||||
validators=[Optional(), FileAllowed(['stl', 'obj', '3mf', 'amf', 'gcode'],
|
||||
'3D-Dateien sind erlaubt!')])
|
||||
|
||||
# Hilfsfunktionen
|
||||
def can_approve_jobs(user_id):
|
||||
"""Prüft, ob ein Benutzer Anfragen genehmigen darf."""
|
||||
|
Binary file not shown.
2
backend/app/static/css/tailwind.min.css
vendored
2
backend/app/static/css/tailwind.min.css
vendored
File diff suppressed because one or more lines are too long
@ -13,10 +13,10 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-3 7h3m-3 4h3m-6-4h.01M9 16h.01"/>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-slate-900 dark:text-white tracking-tight">Druckaufträge</h1>
|
||||
<p class="text-slate-500 dark:text-slate-400 mt-1">Verwalten Sie Ihre 3D-Druckjobs mit höchster Präzision</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-3">
|
||||
<button onclick="refreshJobs()"
|
||||
@ -40,10 +40,10 @@
|
||||
Erstellen Sie einen neuen Druckauftrag mit professionellen Einstellungen
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- Queue-Status-Anzeige -->
|
||||
<div id="queue-status-info" class="mb-6"></div>
|
||||
|
||||
|
||||
<form id="newJobForm" class="space-y-6">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<!-- Drucker auswählen -->
|
||||
@ -65,8 +65,8 @@
|
||||
<div class="flex-shrink-0">
|
||||
<svg class="h-5 w-5 text-orange-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-3L13.732 4c-.77-1.333-2.694-1.333-3.464 0L3.34 16c-.77 1.333.192 3 1.732 3z"/>
|
||||
</svg>
|
||||
</div>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="ml-3">
|
||||
<h3 class="text-sm font-medium text-orange-800 dark:text-orange-400 mb-2">
|
||||
Warteschlangen-Modus: Offline-Drucker ausgewählt
|
||||
@ -75,11 +75,11 @@
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-2 h-2 bg-red-500 rounded-full"></div>
|
||||
<span>Drucker ist derzeit OFFLINE</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-2 h-2 bg-yellow-500 rounded-full"></div>
|
||||
<span>Job wird in WARTESCHLANGE eingereiht</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="w-2 h-2 bg-blue-500 rounded-full"></div>
|
||||
<span>System überwacht alle 2 Minuten</span>
|
||||
@ -117,33 +117,33 @@
|
||||
|
||||
<div class="grid grid-cols-1 gap-6">
|
||||
<!-- Job-Titel -->
|
||||
<div>
|
||||
<div>
|
||||
<label for="job_title" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Job-Titel <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<input type="text" id="job_title" name="job_title" required
|
||||
class="block w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-800 text-slate-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
placeholder="Geben Sie einen beschreibenden Titel ein">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- STL-Datei hochladen -->
|
||||
<div>
|
||||
<div>
|
||||
<label for="stl_file" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
STL-Datei hochladen (optional)
|
||||
</label>
|
||||
<div class="flex items-center justify-center w-full">
|
||||
<div class="flex items-center justify-center w-full">
|
||||
<label for="stl_file" class="flex flex-col items-center justify-center w-full h-32 border-2 border-gray-300 dark:border-slate-600 border-dashed rounded-lg cursor-pointer bg-gray-50 dark:bg-slate-700/30 hover:bg-gray-100 dark:hover:bg-slate-700/50 transition-colors">
|
||||
<div class="flex flex-col items-center justify-center pt-5 pb-6">
|
||||
<div class="flex flex-col items-center justify-center pt-5 pb-6">
|
||||
<svg class="w-8 h-8 mb-3 text-gray-400 dark:text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12"/>
|
||||
</svg>
|
||||
</svg>
|
||||
<p class="mb-2 text-sm text-gray-500 dark:text-gray-400"><span class="font-semibold">Klicken Sie zum Hochladen</span> oder ziehen Sie die Datei hierher</p>
|
||||
<p class="text-xs text-gray-500 dark:text-gray-400">STL-Dateien bis zu 50MB</p>
|
||||
</div>
|
||||
<input id="stl_file" name="stl_file" type="file" accept=".stl" class="hidden" />
|
||||
</label>
|
||||
</div>
|
||||
<div id="file-name" class="mt-2 text-sm text-slate-500 dark:text-slate-400 hidden"></div>
|
||||
</div>
|
||||
<input id="stl_file" name="stl_file" type="file" accept=".stl" class="hidden" />
|
||||
</label>
|
||||
</div>
|
||||
<div id="file-name" class="mt-2 text-sm text-slate-500 dark:text-slate-400 hidden"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -177,10 +177,10 @@
|
||||
<div class="text-slate-400 dark:text-slate-500 mb-4">
|
||||
<svg class="w-12 h-12 mx-auto" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M9 5H7a2 2 0 00-2 2v10a2 2 0 002 2h8a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2"/>
|
||||
</svg>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-2">Keine aktiven Jobs</h3>
|
||||
<p class="text-slate-500 dark:text-slate-400">Sie haben derzeit keine aktiven oder geplanten Druckjobs.</p>
|
||||
<p class="text-slate-500 dark:text-slate-400">Sie haben derzeit keine aktiven oder geplanten Druckjobs.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -199,12 +199,12 @@
|
||||
<button onclick="closeJobModal()" class="p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors">
|
||||
<svg class="w-6 h-6 text-slate-500 dark:text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="jobDetailsContent">
|
||||
<!-- Inhalt wird dynamisch geladen -->
|
||||
<!-- Inhalt wird dynamisch geladen -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -222,8 +222,8 @@
|
||||
<button onclick="closeExtendModal()" class="p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors">
|
||||
<svg class="w-6 h-6 text-slate-500 dark:text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form id="extendJobForm" class="space-y-6">
|
||||
|
@ -16,8 +16,8 @@
|
||||
<div class="w-12 h-12 flex-shrink-0">
|
||||
<svg class="w-full h-full text-slate-900 dark:text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/>
|
||||
</svg>
|
||||
</div>
|
||||
</svg>
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold text-slate-900 dark:text-white tracking-tight">3D-Drucker</h1>
|
||||
<p class="text-slate-500 dark:text-slate-400 mt-1">Verwaltung und Überwachung Ihrer Produktionseinheiten</p>
|
||||
@ -114,15 +114,15 @@
|
||||
<select id="filterLocation" class="block w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-800 text-slate-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
||||
<option value="">Alle Standorte</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Printers Grid -->
|
||||
<div id="printers-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<!-- Printers will be loaded here -->
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Loading State -->
|
||||
<div id="loading-state" class="dashboard-card p-8 text-center">
|
||||
<div class="text-slate-400 dark:text-slate-500 mb-4">
|
||||
@ -131,14 +131,14 @@
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-slate-600 dark:text-slate-400">Lade Drucker...</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Empty State -->
|
||||
<div id="empty-state" class="dashboard-card p-8 text-center hidden">
|
||||
<div class="text-slate-400 dark:text-slate-500 mb-4">
|
||||
<svg class="w-12 h-12 mx-auto mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01"/>
|
||||
</svg>
|
||||
</svg>
|
||||
</div>
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white mb-2">Keine Drucker gefunden</h3>
|
||||
<p class="text-slate-500 dark:text-slate-400 mb-4">
|
||||
@ -146,16 +146,16 @@
|
||||
</p>
|
||||
<button onclick="openAddPrinterModal()" class="btn-primary">
|
||||
Ersten Drucker hinzufügen
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add/Edit Printer Modal -->
|
||||
<div id="printerModal" class="fixed inset-0 bg-black/60 backdrop-blur-sm hidden z-50">
|
||||
<div class="flex items-center justify-center min-h-screen p-4">
|
||||
<div class="dashboard-card max-w-lg w-full p-8 transform transition-all duration-300 scale-95 opacity-0" id="printerModalContent">
|
||||
<div class="flex justify-between items-center mb-6">
|
||||
<div>
|
||||
<div>
|
||||
<h3 id="printerModalTitle" class="text-xl font-bold text-slate-900 dark:text-white mb-2">
|
||||
Drucker hinzufügen
|
||||
</h3>
|
||||
@ -170,68 +170,68 @@
|
||||
|
||||
<form id="printerForm" class="space-y-6">
|
||||
<input type="hidden" id="printerId" name="printerId">
|
||||
|
||||
<div>
|
||||
|
||||
<div>
|
||||
<label for="printerName" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Drucker-Name <span class="text-red-500">*</span>
|
||||
</label>
|
||||
<input type="text" id="printerName" name="name" required
|
||||
class="block w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-800 text-slate-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
placeholder="z.B. Ultimaker S3">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="printerModel" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Modell
|
||||
</label>
|
||||
<input type="text" id="printerModel" name="model"
|
||||
class="block w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-800 text-slate-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
placeholder="z.B. Ultimaker S3">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="printerLocation" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
Standort
|
||||
</label>
|
||||
<input type="text" id="printerLocation" name="location"
|
||||
class="block w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-800 text-slate-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
placeholder="z.B. Produktionshalle A">
|
||||
</div>
|
||||
|
||||
<div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label for="printerIP" class="block text-sm font-medium text-slate-700 dark:text-slate-300 mb-2">
|
||||
IP-Adresse
|
||||
</label>
|
||||
<input type="text" id="printerIP" name="ip_address"
|
||||
class="block w-full px-3 py-2 border border-gray-300 dark:border-slate-600 rounded-lg bg-white dark:bg-slate-800 text-slate-900 dark:text-white focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
||||
placeholder="z.B. 192.168.1.100">
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex items-center">
|
||||
<input type="checkbox" id="printerActive" name="active" checked
|
||||
class="w-4 h-4 text-blue-600 bg-white dark:bg-slate-800 border-gray-300 dark:border-slate-600 rounded focus:ring-blue-500 focus:ring-2">
|
||||
<label for="printerActive" class="ml-2 text-sm text-slate-700 dark:text-slate-300">
|
||||
Drucker aktiv
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-end gap-3 pt-6 border-t border-gray-200 dark:border-slate-600">
|
||||
<button type="button" onclick="closePrinterModal()" class="btn-secondary">
|
||||
Abbrechen
|
||||
</button>
|
||||
Abbrechen
|
||||
</button>
|
||||
<button type="submit" class="btn-primary">
|
||||
Speichern
|
||||
</button>
|
||||
<button type="button" id="deletePrinterBtn" onclick="deletePrinter()" style="display: none;"
|
||||
class="px-4 py-2 bg-red-600 hover:bg-red-700 text-white rounded-lg transition-colors">
|
||||
Löschen
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Printer Details Modal -->
|
||||
<div id="printerDetailsModal" class="fixed inset-0 bg-black/60 backdrop-blur-sm hidden z-50">
|
||||
<div class="flex items-center justify-center min-h-screen p-4">
|
||||
@ -242,20 +242,20 @@
|
||||
Drucker Details
|
||||
</h3>
|
||||
<p class="text-slate-500 dark:text-slate-400">Detaillierte Informationen über den Drucker</p>
|
||||
</div>
|
||||
</div>
|
||||
<button onclick="closePrinterDetailsModal()" class="p-2 hover:bg-gray-100 dark:hover:bg-slate-700 rounded-lg transition-colors">
|
||||
<svg class="w-6 h-6 text-slate-500 dark:text-slate-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="printerDetailsContent">
|
||||
<!-- Details will be loaded here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let allPrinters = [];
|
||||
@ -293,8 +293,8 @@ async function loadPrinters() {
|
||||
function displayPrinters() {
|
||||
const grid = document.getElementById('printers-grid');
|
||||
const emptyState = document.getElementById('empty-state');
|
||||
|
||||
if (filteredPrinters.length === 0) {
|
||||
|
||||
if (filteredPrinters.length === 0) {
|
||||
grid.style.display = 'none';
|
||||
emptyState.classList.remove('hidden');
|
||||
return;
|
||||
@ -310,51 +310,51 @@ function displayPrinters() {
|
||||
function createPrinterCard(printer) {
|
||||
const statusClass = getStatusClass(printer.status);
|
||||
const statusIcon = getStatusIcon(printer.status);
|
||||
|
||||
return `
|
||||
|
||||
return `
|
||||
<div class="dashboard-card p-6 border-l-4 ${statusClass.border}">
|
||||
<div class="flex justify-between items-start mb-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-10 h-10 ${statusClass.bg} rounded-lg flex items-center justify-center">
|
||||
${statusIcon}
|
||||
</div>
|
||||
<div>
|
||||
<div>
|
||||
<h3 class="text-lg font-semibold text-slate-900 dark:text-white">${printer.name}</h3>
|
||||
<p class="text-sm text-slate-500 dark:text-slate-400">${printer.model || 'Unbekanntes Modell'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="inline-flex items-center px-3 py-1 rounded-full text-sm font-medium ${statusClass.badge}">
|
||||
${printer.status_text || printer.status}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="space-y-3 mb-4">
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-slate-500 dark:text-slate-400">Standort:</span>
|
||||
<span class="text-slate-900 dark:text-white">${printer.location || 'Nicht angegeben'}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-slate-500 dark:text-slate-400">IP-Adresse:</span>
|
||||
<span class="text-slate-900 dark:text-white">${printer.ip_address || 'Nicht konfiguriert'}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex justify-between text-sm">
|
||||
<span class="text-slate-500 dark:text-slate-400">Letzter Job:</span>
|
||||
<span class="text-slate-900 dark:text-white">${printer.last_job || 'Kein Job'}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-2">
|
||||
<button onclick="showPrinterDetails(${printer.id})"
|
||||
class="flex-1 px-3 py-2 text-sm bg-gray-100 dark:bg-slate-700 text-slate-700 dark:text-slate-300 rounded-lg hover:bg-gray-200 dark:hover:bg-slate-600 transition-colors">
|
||||
Details
|
||||
</button>
|
||||
Details
|
||||
</button>
|
||||
<button onclick="editPrinter(${printer.id})"
|
||||
class="flex-1 px-3 py-2 text-sm bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-400 rounded-lg hover:bg-blue-200 dark:hover:bg-blue-900/50 transition-colors">
|
||||
Bearbeiten
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
// Get status styling classes
|
||||
@ -454,7 +454,7 @@ function openAddPrinterModal() {
|
||||
document.getElementById('deletePrinterBtn').style.display = 'none';
|
||||
|
||||
modal.classList.remove('hidden');
|
||||
setTimeout(() => {
|
||||
setTimeout(() => {
|
||||
modalContent.classList.remove('scale-95', 'opacity-0');
|
||||
modalContent.classList.add('scale-100', 'opacity-100');
|
||||
}, 10);
|
||||
@ -516,7 +516,7 @@ function refreshPrinters() {
|
||||
document.getElementById('loading-state').style.display = 'block';
|
||||
document.getElementById('printers-grid').style.display = 'none';
|
||||
document.getElementById('empty-state').classList.add('hidden');
|
||||
loadPrinters();
|
||||
loadPrinters();
|
||||
}
|
||||
|
||||
function showError(message) {
|
||||
@ -538,22 +538,22 @@ document.getElementById('printerForm').addEventListener('submit', async function
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': document.querySelector('meta[name="csrf-token"]').getAttribute('content')
|
||||
},
|
||||
},
|
||||
body: JSON.stringify(data)
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
});
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.success) {
|
||||
closePrinterModal();
|
||||
refreshPrinters();
|
||||
} else {
|
||||
showError('Fehler beim Speichern: ' + result.error);
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error) {
|
||||
console.error('Error saving printer:', error);
|
||||
showError('Fehler beim Speichern des Druckers');
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user