@@ -310,6 +313,44 @@
.btn-link {
padding: 0 4px;
}
+
+/* Multi-select improvements */
+select[multiple] {
+ scrollbar-width: thin;
+ scrollbar-color: #6c757d #f8f9fa;
+}
+
+select[multiple]::-webkit-scrollbar {
+ width: 8px;
+}
+
+select[multiple]::-webkit-scrollbar-track {
+ background: #f8f9fa;
+}
+
+select[multiple]::-webkit-scrollbar-thumb {
+ background-color: #6c757d;
+ border-radius: 4px;
+}
+
+select[multiple] option {
+ padding: 4px 8px;
+}
+
+select[multiple] option:checked {
+ background-color: #0d6efd;
+ color: white;
+}
+
+select[multiple] option:hover {
+ background-color: #e9ecef;
+ color: #212529;
+}
+
+/* Modal improvements */
+.modal-xl {
+ max-width: 1200px;
+}
{% endblock %}
@@ -672,6 +713,9 @@ function showResourceManagement(licenseId) {
const license = currentLicenses[licenseId];
if (!license) return;
+ // Speichere License-ID im Modal für späteren Zugriff
+ document.getElementById('resourceManagementModal').dataset.licenseId = licenseId;
+
// Lade aktuelle Ressourcen-Informationen
fetch(`/api/license/${licenseId}/resources`)
.then(response => response.json())
@@ -775,7 +819,62 @@ function showResourceManagement(licenseId) {
content += `
+
+
+
Neue Ressourcen zuweisen
+
+ Wählen Sie verfügbare Ressourcen aus, um sie dieser Lizenz zuzuweisen.
+
+
+
+
+
+
Mehrfachauswahl mit Strg/Cmd + Klick
+
+
+
+
+
+
+
+
+
Mehrfachauswahl mit Strg/Cmd + Klick
+
+
+
+
+
+
+
+
+
Mehrfachauswahl mit Strg/Cmd + Klick
+
+
+
+
+
+
+
+
+
Das Quarantäne-setzen einer Ressource entfernt sie von der Lizenz und markiert sie als problematisch.
`;
@@ -783,6 +882,20 @@ function showResourceManagement(licenseId) {
document.getElementById('resourceManagementContent').innerHTML = content;
const modal = new bootstrap.Modal(document.getElementById('resourceManagementModal'));
modal.show();
+
+ // Lade verfügbare Ressourcen
+ loadAvailableResources(licenseId);
+
+ // Add event listeners for selection changes after resources are loaded
+ setTimeout(() => {
+ ['availableDomains', 'availableIpv4s', 'availablePhones'].forEach(selectId => {
+ const select = document.getElementById(selectId);
+ if (select) {
+ select.addEventListener('change', updateSelectionCounter);
+ }
+ });
+ updateSelectionCounter();
+ }, 500);
}
})
.catch(error => {
@@ -801,9 +914,187 @@ function quarantineResource(resourceId, resourceValue) {
alert('Diese Funktion wird noch implementiert');
}
-// Dummy-Funktion für Speichern (wird später implementiert)
+// Lade verfügbare Ressourcen
+function loadAvailableResources(licenseId) {
+ // Hole show_test Parameter aus der URL
+ const urlParams = new URLSearchParams(window.location.search);
+ const showTest = urlParams.get('show_test') === 'true';
+
+ // Lade verfügbare Domains
+ fetch(`/api/resources/check-availability?type=domain&count=200&show_test=${showTest}`)
+ .then(response => response.json())
+ .then(data => {
+ const select = document.getElementById('availableDomains');
+ select.innerHTML = '';
+ if (data.available && data.available.length > 0) {
+ data.available.forEach(resource => {
+ const option = document.createElement('option');
+ option.value = resource.id;
+ option.textContent = resource.value;
+ select.appendChild(option);
+ });
+ // Zeige Anzahl verfügbarer Ressourcen
+ const label = select.parentElement.querySelector('.form-label');
+ label.innerHTML = `🌐 Domains hinzufügen (${data.available.length} verfügbar)`;
+ } else {
+ select.innerHTML = '
';
+ }
+ });
+
+ // Lade verfügbare IPv4s
+ fetch(`/api/resources/check-availability?type=ipv4&count=200&show_test=${showTest}`)
+ .then(response => response.json())
+ .then(data => {
+ const select = document.getElementById('availableIpv4s');
+ select.innerHTML = '';
+ if (data.available && data.available.length > 0) {
+ data.available.forEach(resource => {
+ const option = document.createElement('option');
+ option.value = resource.id;
+ option.textContent = resource.value;
+ select.appendChild(option);
+ });
+ // Zeige Anzahl verfügbarer Ressourcen
+ const label = select.parentElement.querySelector('.form-label');
+ label.innerHTML = `📡 IPv4-Adressen hinzufügen (${data.available.length} verfügbar)`;
+ } else {
+ select.innerHTML = '
';
+ }
+ });
+
+ // Lade verfügbare Telefonnummern
+ fetch(`/api/resources/check-availability?type=phone&count=200&show_test=${showTest}`)
+ .then(response => response.json())
+ .then(data => {
+ const select = document.getElementById('availablePhones');
+ select.innerHTML = '';
+ if (data.available && data.available.length > 0) {
+ data.available.forEach(resource => {
+ const option = document.createElement('option');
+ option.value = resource.id;
+ option.textContent = resource.value;
+ select.appendChild(option);
+ });
+ // Zeige Anzahl verfügbarer Ressourcen
+ const label = select.parentElement.querySelector('.form-label');
+ label.innerHTML = `📱 Telefonnummern hinzufügen (${data.available.length} verfügbar)`;
+ } else {
+ select.innerHTML = '
';
+ }
+ });
+}
+
+// Alle Optionen in einer Kategorie auswählen
+function selectAllInCategory(selectId) {
+ const select = document.getElementById(selectId);
+ for (let i = 0; i < select.options.length; i++) {
+ if (!select.options[i].disabled) {
+ select.options[i].selected = true;
+ }
+ }
+ updateSelectionCounter();
+}
+
+// Auswahl in einer Kategorie aufheben
+function deselectAllInCategory(selectId) {
+ const select = document.getElementById(selectId);
+ for (let i = 0; i < select.options.length; i++) {
+ select.options[i].selected = false;
+ }
+ updateSelectionCounter();
+}
+
+// Update selection counter
+function updateSelectionCounter() {
+ const domainsCount = document.getElementById('availableDomains').selectedOptions.length;
+ const ipv4sCount = document.getElementById('availableIpv4s').selectedOptions.length;
+ const phonesCount = document.getElementById('availablePhones').selectedOptions.length;
+ const totalCount = domainsCount + ipv4sCount + phonesCount;
+
+ const counter = document.getElementById('selectionCounter');
+ if (counter) {
+ counter.textContent = `${totalCount} Ressourcen ausgewählt`;
+
+ // Update save button state
+ const saveBtn = document.getElementById('saveResourcesBtn');
+ if (saveBtn) {
+ saveBtn.disabled = totalCount === 0;
+ if (totalCount === 0) {
+ saveBtn.classList.add('disabled');
+ } else {
+ saveBtn.classList.remove('disabled');
+ }
+ }
+ }
+}
+
+// Speichere Ressourcen-Änderungen
function saveResourceChanges() {
- alert('Diese Funktion wird noch implementiert');
+ const modal = document.getElementById('resourceManagementModal');
+ const licenseId = modal.dataset.licenseId || currentLicenses[Object.keys(currentLicenses)[0]].id;
+
+ // Sammle ausgewählte Ressourcen
+ const selectedDomains = Array.from(document.getElementById('availableDomains').selectedOptions).map(opt => opt.value);
+ const selectedIpv4s = Array.from(document.getElementById('availableIpv4s').selectedOptions).map(opt => opt.value);
+ const selectedPhones = Array.from(document.getElementById('availablePhones').selectedOptions).map(opt => opt.value);
+
+ const allResources = [...selectedDomains, ...selectedIpv4s, ...selectedPhones];
+
+ if (allResources.length === 0) {
+ alert('Bitte wählen Sie mindestens eine Ressource aus.');
+ return;
+ }
+
+ // Disable save button and show loading state
+ const saveBtn = document.getElementById('saveResourcesBtn');
+ const originalBtnText = saveBtn.innerHTML;
+ saveBtn.disabled = true;
+ saveBtn.innerHTML = '
Wird gespeichert...';
+
+ // API-Call zum Zuweisen der Ressourcen
+ fetch('/api/resources/allocate', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ },
+ body: JSON.stringify({
+ license_id: licenseId,
+ resource_ids: allResources
+ })
+ })
+ .then(response => response.json())
+ .then(data => {
+ if (data.success) {
+ // Show success message with details
+ const domainCount = selectedDomains.length;
+ const ipv4Count = selectedIpv4s.length;
+ const phoneCount = selectedPhones.length;
+
+ let message = `✅ ${data.allocated} Ressourcen erfolgreich zugewiesen!\n\n`;
+ if (domainCount > 0) message += `🌐 ${domainCount} Domains\n`;
+ if (ipv4Count > 0) message += `📡 ${ipv4Count} IPv4-Adressen\n`;
+ if (phoneCount > 0) message += `📱 ${phoneCount} Telefonnummern`;
+
+ alert(message);
+
+ // Modal schließen und Ansicht aktualisieren
+ bootstrap.Modal.getInstance(modal).hide();
+ if (currentCustomerId) {
+ loadCustomerLicenses(currentCustomerId);
+ }
+ } else {
+ alert('❌ ' + (data.message || 'Fehler beim Zuweisen der Ressourcen'));
+ }
+ })
+ .catch(error => {
+ console.error('Error allocating resources:', error);
+ alert('❌ Fehler beim Zuweisen der Ressourcen');
+ })
+ .finally(() => {
+ // Restore button state
+ saveBtn.disabled = false;
+ saveBtn.innerHTML = originalBtnText;
+ });
}
// Geräte-Verwaltung anzeigen