feat: Update frontend and backend configurations for development environment - Downgrade PyP100 version in requirements.txt for compatibility. - Add new frontend routes for index, login, dashboard, printers, jobs, and profile pages. - Modify docker-compose files for development setup, including environment variables and service names. - Update Caddyfile for local development with Raspberry Pi backend. - Adjust health check route to use updated backend URL. - Enhance setup-backend-url.sh for development environment configuration. """
362 lines
17 KiB
HTML
362 lines
17 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Drucker - MYP Platform{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
|
<!-- Header -->
|
|
<div class="mb-8">
|
|
<div class="flex items-center justify-between">
|
|
<div>
|
|
<h1 class="text-3xl font-bold text-mercedes-black">Drucker</h1>
|
|
<p class="mt-2 text-mercedes-gray">Verwalten Sie Ihre 3D-Drucker</p>
|
|
</div>
|
|
<div class="flex space-x-4">
|
|
<button onclick="refreshPrinters()" class="bg-mercedes-blue hover:bg-blue-700 text-white px-4 py-2 rounded-lg mercedes-button transition-all duration-200">
|
|
<svg class="h-5 w-5 inline mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" />
|
|
</svg>
|
|
Aktualisieren
|
|
</button>
|
|
{% if current_user.is_admin %}
|
|
<button onclick="showAddPrinterModal()" class="bg-mercedes-green hover:bg-green-700 text-white px-4 py-2 rounded-lg mercedes-button transition-all duration-200">
|
|
<svg class="h-5 w-5 inline mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6v6m0 0v6m0-6h6m-6 0H6" />
|
|
</svg>
|
|
Drucker hinzufügen
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Printers Grid -->
|
|
<div id="printers-grid" class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
|
<!-- Loading state -->
|
|
<div class="col-span-full text-center py-12">
|
|
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-mercedes-blue mx-auto"></div>
|
|
<p class="mt-4 text-mercedes-gray">Lade Drucker...</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add Printer Modal -->
|
|
{% if current_user.is_admin %}
|
|
<div id="addPrinterModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50">
|
|
<div class="flex items-center justify-center min-h-screen p-4">
|
|
<div class="mercedes-card rounded-xl p-6 w-full max-w-md">
|
|
<div class="flex items-center justify-between mb-6">
|
|
<h2 class="text-xl font-bold text-mercedes-black">Neuen Drucker hinzufügen</h2>
|
|
<button onclick="hideAddPrinterModal()" class="text-mercedes-gray hover:text-mercedes-black">
|
|
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<form id="addPrinterForm" onsubmit="handleAddPrinter(event)" class="space-y-4">
|
|
<div>
|
|
<label for="printer-name" class="block text-sm font-medium text-mercedes-black mb-2">Name</label>
|
|
<input type="text" id="printer-name" name="name" required
|
|
class="w-full px-3 py-2 border border-mercedes-silver rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue">
|
|
</div>
|
|
|
|
<div>
|
|
<label for="printer-model" class="block text-sm font-medium text-mercedes-black mb-2">Modell</label>
|
|
<input type="text" id="printer-model" name="model" required
|
|
class="w-full px-3 py-2 border border-mercedes-silver rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue">
|
|
</div>
|
|
|
|
<div>
|
|
<label for="printer-location" class="block text-sm font-medium text-mercedes-black mb-2">Standort</label>
|
|
<input type="text" id="printer-location" name="location" required
|
|
class="w-full px-3 py-2 border border-mercedes-silver rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue">
|
|
</div>
|
|
|
|
<div>
|
|
<label for="printer-mac" class="block text-sm font-medium text-mercedes-black mb-2">MAC-Adresse</label>
|
|
<input type="text" id="printer-mac" name="mac_address" required
|
|
placeholder="AA:BB:CC:DD:EE:FF"
|
|
class="w-full px-3 py-2 border border-mercedes-silver rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue">
|
|
</div>
|
|
|
|
<div>
|
|
<label for="printer-ip" class="block text-sm font-medium text-mercedes-black mb-2">Plug IP-Adresse</label>
|
|
<input type="text" id="printer-ip" name="plug_ip" required
|
|
placeholder="192.168.1.100"
|
|
class="w-full px-3 py-2 border border-mercedes-silver rounded-lg focus:ring-2 focus:ring-mercedes-blue focus:border-mercedes-blue">
|
|
</div>
|
|
|
|
<div class="flex space-x-3 pt-4">
|
|
<button type="button" onclick="hideAddPrinterModal()"
|
|
class="flex-1 bg-mercedes-silver hover:bg-gray-400 text-mercedes-black py-2 px-4 rounded-lg mercedes-button transition-all duration-200">
|
|
Abbrechen
|
|
</button>
|
|
<button type="submit"
|
|
class="flex-1 bg-mercedes-green hover:bg-green-700 text-white py-2 px-4 rounded-lg mercedes-button transition-all duration-200">
|
|
Hinzufügen
|
|
</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endif %}
|
|
|
|
<!-- Printer Detail Modal -->
|
|
<div id="printerDetailModal" class="fixed inset-0 bg-black bg-opacity-50 hidden z-50">
|
|
<div class="flex items-center justify-center min-h-screen p-4">
|
|
<div class="mercedes-card rounded-xl p-6 w-full max-w-lg">
|
|
<div class="flex items-center justify-between mb-6">
|
|
<h2 class="text-xl font-bold text-mercedes-black">Drucker Details</h2>
|
|
<button onclick="hidePrinterDetailModal()" class="text-mercedes-gray hover:text-mercedes-black">
|
|
<svg class="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
|
|
<div id="printer-detail-content">
|
|
<!-- Content will be loaded here -->
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block scripts %}
|
|
<script>
|
|
let printers = [];
|
|
|
|
// Load printers
|
|
async function loadPrinters() {
|
|
try {
|
|
const response = await apiCall('/api/printers');
|
|
printers = response.printers || [];
|
|
renderPrinters();
|
|
} catch (error) {
|
|
console.error('Error loading printers:', error);
|
|
showFlashMessage('Fehler beim Laden der Drucker', 'error');
|
|
}
|
|
}
|
|
|
|
// Render printers grid
|
|
function renderPrinters() {
|
|
const grid = document.getElementById('printers-grid');
|
|
|
|
if (printers.length === 0) {
|
|
grid.innerHTML = `
|
|
<div class="col-span-full text-center py-12">
|
|
<svg class="h-16 w-16 text-mercedes-silver mx-auto mb-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 3v2m6-2v2M9 19v2m6-2v2M5 9H3m2 6H3m18-6h-2m2 6h-2M7 19h10a2 2 0 002-2V7a2 2 0 00-2-2H7a2 2 0 00-2 2v10a2 2 0 002 2zM9 9h6v6H9V9z" />
|
|
</svg>
|
|
<p class="text-mercedes-gray text-lg">Keine Drucker vorhanden</p>
|
|
{% if current_user.is_admin %}
|
|
<button onclick="showAddPrinterModal()" class="mt-4 bg-mercedes-green hover:bg-green-700 text-white px-6 py-2 rounded-lg mercedes-button transition-all duration-200">
|
|
Ersten Drucker hinzufügen
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
grid.innerHTML = printers.map(printer => {
|
|
const statusColor = getPrinterStatusColor(printer.status);
|
|
const statusText = getPrinterStatusText(printer.status);
|
|
|
|
return `
|
|
<div class="mercedes-card rounded-xl p-6 mercedes-shadow hover:shadow-lg transition-shadow duration-200">
|
|
<div class="flex items-start justify-between mb-4">
|
|
<div class="flex-1">
|
|
<h3 class="text-lg font-bold text-mercedes-black">${printer.name}</h3>
|
|
<p class="text-sm text-mercedes-gray">${printer.model}</p>
|
|
</div>
|
|
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${statusColor}">
|
|
${statusText}
|
|
</span>
|
|
</div>
|
|
|
|
<div class="space-y-2 mb-4">
|
|
<div class="flex items-center text-sm text-mercedes-gray">
|
|
<svg class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z" />
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 11a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
</svg>
|
|
${printer.location}
|
|
</div>
|
|
|
|
<div class="flex items-center text-sm text-mercedes-gray">
|
|
<svg class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z" />
|
|
</svg>
|
|
${printer.mac_address}
|
|
</div>
|
|
|
|
<div class="flex items-center text-sm text-mercedes-gray">
|
|
<svg class="h-4 w-4 mr-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 12a9 9 0 01-9 9m9-9a9 9 0 00-9-9m9 9H3m9 9v-9m0-9v9" />
|
|
</svg>
|
|
${printer.plug_ip}
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex space-x-2">
|
|
<button onclick="showPrinterDetail(${printer.id})"
|
|
class="flex-1 bg-mercedes-blue hover:bg-blue-700 text-white py-2 px-3 rounded-lg text-sm mercedes-button transition-all duration-200">
|
|
Details
|
|
</button>
|
|
|
|
{% if current_user.is_admin %}
|
|
<button onclick="deletePrinter(${printer.id})"
|
|
class="bg-mercedes-red hover:bg-red-700 text-white py-2 px-3 rounded-lg text-sm mercedes-button transition-all duration-200">
|
|
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
|
|
</svg>
|
|
</button>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
// Helper functions
|
|
function getPrinterStatusColor(status) {
|
|
switch (status) {
|
|
case 'available': return 'bg-mercedes-green text-white';
|
|
case 'busy': return 'bg-mercedes-yellow text-mercedes-black';
|
|
case 'offline': return 'bg-mercedes-red text-white';
|
|
case 'maintenance': return 'bg-mercedes-silver text-mercedes-black';
|
|
default: return 'bg-mercedes-gray text-white';
|
|
}
|
|
}
|
|
|
|
function getPrinterStatusText(status) {
|
|
switch (status) {
|
|
case 'available': return 'Verfügbar';
|
|
case 'busy': return 'Beschäftigt';
|
|
case 'offline': return 'Offline';
|
|
case 'maintenance': return 'Wartung';
|
|
default: return 'Unbekannt';
|
|
}
|
|
}
|
|
|
|
// Modal functions
|
|
function showAddPrinterModal() {
|
|
document.getElementById('addPrinterModal').classList.remove('hidden');
|
|
}
|
|
|
|
function hideAddPrinterModal() {
|
|
document.getElementById('addPrinterModal').classList.add('hidden');
|
|
document.getElementById('addPrinterForm').reset();
|
|
}
|
|
|
|
function showPrinterDetail(printerId) {
|
|
const printer = printers.find(p => p.id === printerId);
|
|
if (!printer) return;
|
|
|
|
const content = document.getElementById('printer-detail-content');
|
|
content.innerHTML = `
|
|
<div class="space-y-4">
|
|
<div>
|
|
<h3 class="font-medium text-mercedes-black">${printer.name}</h3>
|
|
<p class="text-sm text-mercedes-gray">${printer.model}</p>
|
|
</div>
|
|
|
|
<div class="grid grid-cols-2 gap-4 text-sm">
|
|
<div>
|
|
<span class="font-medium text-mercedes-gray">Status:</span>
|
|
<span class="ml-2 ${getPrinterStatusColor(printer.status)} px-2 py-1 rounded text-xs">
|
|
${getPrinterStatusText(printer.status)}
|
|
</span>
|
|
</div>
|
|
|
|
<div>
|
|
<span class="font-medium text-mercedes-gray">Standort:</span>
|
|
<span class="ml-2 text-mercedes-black">${printer.location}</span>
|
|
</div>
|
|
|
|
<div>
|
|
<span class="font-medium text-mercedes-gray">MAC:</span>
|
|
<span class="ml-2 text-mercedes-black font-mono text-xs">${printer.mac_address}</span>
|
|
</div>
|
|
|
|
<div>
|
|
<span class="font-medium text-mercedes-gray">Plug IP:</span>
|
|
<span class="ml-2 text-mercedes-black font-mono text-xs">${printer.plug_ip}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="pt-4 border-t border-mercedes-silver">
|
|
<p class="text-xs text-mercedes-gray">
|
|
Erstellt: ${formatDate(printer.created_at)}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
`;
|
|
|
|
document.getElementById('printerDetailModal').classList.remove('hidden');
|
|
}
|
|
|
|
function hidePrinterDetailModal() {
|
|
document.getElementById('printerDetailModal').classList.add('hidden');
|
|
}
|
|
|
|
// Add printer
|
|
async function handleAddPrinter(event) {
|
|
event.preventDefault();
|
|
|
|
const formData = new FormData(event.target);
|
|
const printerData = {
|
|
name: formData.get('name'),
|
|
model: formData.get('model'),
|
|
location: formData.get('location'),
|
|
mac_address: formData.get('mac_address'),
|
|
plug_ip: formData.get('plug_ip')
|
|
};
|
|
|
|
try {
|
|
await apiCall('/api/printers', {
|
|
method: 'POST',
|
|
body: JSON.stringify(printerData)
|
|
});
|
|
|
|
showFlashMessage('Drucker erfolgreich hinzugefügt', 'success');
|
|
hideAddPrinterModal();
|
|
loadPrinters();
|
|
} catch (error) {
|
|
showFlashMessage('Fehler beim Hinzufügen des Druckers', 'error');
|
|
}
|
|
}
|
|
|
|
// Delete printer
|
|
async function deletePrinter(printerId) {
|
|
if (!confirm('Sind Sie sicher, dass Sie diesen Drucker löschen möchten?')) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
await apiCall(`/api/printers/${printerId}`, {
|
|
method: 'DELETE'
|
|
});
|
|
|
|
showFlashMessage('Drucker erfolgreich gelöscht', 'success');
|
|
loadPrinters();
|
|
} catch (error) {
|
|
showFlashMessage('Fehler beim Löschen des Druckers', 'error');
|
|
}
|
|
}
|
|
|
|
// Refresh printers
|
|
function refreshPrinters() {
|
|
showFlashMessage('Drucker werden aktualisiert...', 'info');
|
|
loadPrinters();
|
|
}
|
|
|
|
// Initialize
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
loadPrinters();
|
|
});
|
|
</script>
|
|
{% endblock %} |