// WOL Manager JavaScript let scanModal, addModal, editModal; // Initialize on page load window.onload = function() { scanModal = document.getElementById('scanModal'); addModal = document.getElementById('addModal'); editModal = document.getElementById('editModal'); refreshComputers(); }; function showMessage(message, type) { const messageArea = document.getElementById('message-area'); messageArea.innerHTML = `
${message}
`; setTimeout(() => { messageArea.innerHTML = ''; }, 5000); } function refreshComputers() { fetch('/api/computers') .then(response => response.json()) .then(computers => { displayComputers(computers); }) .catch(error => { showMessage('Eroare la încărcarea calculatoarelor: ' + error.message, 'error'); }); } function displayComputers(computers) { const tbody = document.getElementById('computers-tbody'); const noComputersDiv = document.getElementById('no-computers'); if (computers.length === 0) { tbody.innerHTML = ''; noComputersDiv.style.display = 'block'; return; } noComputersDiv.style.display = 'none'; tbody.innerHTML = computers.map(computer => ` ${computer.name} ${computer.ip || '-'} ${computer.mac} `).join(''); } function wakeComputer(mac, name, ip) { showMessage(`Se trimite magic packet pentru ${name}...`, 'success'); fetch('/api/wake', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({mac: mac, name: name, ip: ip}) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage(result.message, 'success'); setTimeout(refreshComputers, 2000); } else { showMessage(result.message, 'error'); } }) .catch(error => { showMessage('Eroare la trezirea calculatorului: ' + error.message, 'error'); }); } function wakeAllComputers() { showMessage('Se trezesc toate calculatoarele...', 'success'); fetch('/api/wake-all', { method: 'POST', headers: { 'Content-Type': 'application/json', } }) .then(response => response.json()) .then(data => { let message = 'Comenzi trimise:
'; data.results.forEach(result => { message += `• ${result.name}: ${result.result.message}
`; }); showMessage(message, 'success'); setTimeout(refreshComputers, 3000); }) .catch(error => { showMessage('Eroare la trezirea calculatoarelor: ' + error.message, 'error'); }); } function openAddModal() { addModal.style.display = 'block'; } function closeAddModal() { addModal.style.display = 'none'; document.getElementById('computerName').value = ''; document.getElementById('computerMac').value = ''; document.getElementById('computerIp').value = ''; } function addComputer() { const name = document.getElementById('computerName').value; const mac = document.getElementById('computerMac').value; const ip = document.getElementById('computerIp').value; if (!name || !mac) { showMessage('Numele și MAC-ul sunt obligatorii!', 'error'); return; } fetch('/api/add', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({name: name, mac: mac, ip: ip}) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage(result.message, 'success'); closeAddModal(); refreshComputers(); } else { showMessage(result.message, 'error'); } }) .catch(error => { showMessage('Eroare la adăugarea calculatorului: ' + error.message, 'error'); }); } function toggleCustomNetwork() { const select = document.getElementById('networkSelect'); const customInput = document.getElementById('customNetwork'); if (select.value === 'custom') { customInput.style.display = 'inline'; customInput.focus(); } else { customInput.style.display = 'none'; } } function getSelectedNetwork() { const select = document.getElementById('networkSelect'); const customInput = document.getElementById('customNetwork'); if (select.value === 'custom') { return customInput.value.trim(); } else { return select.value; } } function scanNetwork() { scanModal.style.display = 'block'; document.getElementById('scan-loading').style.display = 'block'; document.getElementById('scan-results').innerHTML = ''; const network = getSelectedNetwork(); const requestData = network ? { network: network } : {}; // Get current computers list to compare with scan results Promise.all([ fetch('/api/computers').then(response => response.json()), fetch('/api/scan', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestData) }).then(response => response.json()) ]) .then(([existingComputers, result]) => { document.getElementById('scan-loading').style.display = 'none'; if (result.success) { if (result.computers && result.computers.length > 0) { displayScanResults(result.computers, existingComputers); if (result.message) { // Afișează mesajul deasupra tabelului document.getElementById('scan-results').innerHTML = `
${result.message}
` + document.getElementById('scan-results').innerHTML; } } else if (result.message) { document.getElementById('scan-results').innerHTML = `
${result.message}
`; } } else { document.getElementById('scan-results').innerHTML = `
${result.message}
`; } }) .catch(error => { document.getElementById('scan-loading').style.display = 'none'; document.getElementById('scan-results').innerHTML = `
Eroare la scanare: ${error.message}
`; }); } function triggerWindowsScan() { scanModal.style.display = 'block'; document.getElementById('scan-loading').style.display = 'block'; document.getElementById('scan-results').innerHTML = ''; const network = getSelectedNetwork(); const requestData = network ? { network: network } : {}; showMessage('Declanșând scanul Windows...', 'success'); // Get current computers list to compare with scan results Promise.all([ fetch('/api/computers').then(response => response.json()), fetch('/api/scan/windows', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(requestData) }).then(response => response.json()) ]) .then(([existingComputers, data]) => { document.getElementById('scan-loading').style.display = 'none'; if (data.success && data.computers) { showMessage(data.message || 'Scan Windows completat cu succes!', 'success'); displayScanResults(data.computers, existingComputers); } else { let message = data.message || 'Scanul Windows a eșuat'; if (data.instructions) { message += '

Instrucțiuni:
' + data.instructions; if (data.commands) { message += '
Comenzi disponibile:'; data.commands.forEach(cmd => { message += `
${cmd}`; }); } } showMessage(message, 'error'); document.getElementById('scan-results').innerHTML = '
' + '

Scanul Windows nu poate fi executat din container

' + '

Pentru a scana rețeaua Windows și obține MAC addresses:

' + '
    ' + '
  1. Deschide Command Prompt sau PowerShell ca Administrator pe Windows
  2. ' + '
  3. Navighează la directorul proiectului WOL Manager
  4. ' + '
  5. Rulează una din comenzile de mai jos:
  6. ' + '
' + '
' + (data.commands ? data.commands.map(cmd => `
${cmd}
`).join('') : 'scripts\\scan-network.bat') + '
' + '

După rularea comenzii, apasă "Scanează Rețeaua" pentru a vedea rezultatele.

' + '
'; } }) .catch(error => { document.getElementById('scan-loading').style.display = 'none'; showMessage('Eroare la declanșarea scanului Windows: ' + error.message, 'error'); console.error('Error:', error); }); } function displayScanResults(computers, existingComputers = []) { if (computers.length === 0) { document.getElementById('scan-results').innerHTML = '
Nu s-au găsit calculatoare în rețea
'; return; } // Create a set of existing MAC addresses for quick lookup (normalize to lowercase) const existingMACs = new Set(existingComputers.map(comp => comp.mac.toLowerCase())); let html = `
`; computers.forEach((computer, index) => { const computerMAC = computer.mac.toLowerCase(); const deviceExists = existingMACs.has(computerMAC); const rowClass = deviceExists ? 'device-exists' : ''; const checkboxDisabled = deviceExists ? 'disabled' : ''; const buttonDisabled = deviceExists ? 'disabled' : ''; const buttonTitle = deviceExists ? 'Device-ul există deja în sistem' : 'Adaugă calculatorul'; html += ` `; }); html += '
Selectează IP MAC Hostname Status Acțiune
${computer.ip} ${computer.mac} ${computer.hostname} ${computer.status}
'; document.getElementById('scan-results').innerHTML = html; } function toggleSelectAll() { const selectAllCheckbox = document.getElementById('selectAll'); const deviceCheckboxes = document.querySelectorAll('.device-checkbox:not(:disabled)'); deviceCheckboxes.forEach(checkbox => { checkbox.checked = selectAllCheckbox.checked; }); updateAddButton(); } function updateAddButton() { const deviceCheckboxes = document.querySelectorAll('.device-checkbox:not(:disabled)'); const checkedBoxes = document.querySelectorAll('.device-checkbox:checked:not(:disabled)'); const addButton = document.querySelector('.add-selected-btn'); const selectAllCheckbox = document.getElementById('selectAll'); // Enable/disable the "Add Selected" button if (addButton) { addButton.disabled = checkedBoxes.length === 0; addButton.textContent = checkedBoxes.length > 0 ? `➕ Adaugă Selectate (${checkedBoxes.length})` : '➕ Adaugă Selectate'; } // Update "Select All" checkbox state (only consider enabled checkboxes) if (selectAllCheckbox) { if (checkedBoxes.length === 0) { selectAllCheckbox.indeterminate = false; selectAllCheckbox.checked = false; } else if (checkedBoxes.length === deviceCheckboxes.length) { selectAllCheckbox.indeterminate = false; selectAllCheckbox.checked = true; } else { selectAllCheckbox.indeterminate = true; } } } function addSelectedFromScan() { const checkedBoxes = document.querySelectorAll('.device-checkbox:checked:not(:disabled)'); if (checkedBoxes.length === 0) { showMessage('Nu ai selectat niciun dispozitiv!', 'error'); return; } const devices = Array.from(checkedBoxes).map(checkbox => ({ name: checkbox.dataset.hostname, mac: checkbox.dataset.mac, ip: checkbox.dataset.ip })); // Show progress message showMessage(`Se adaugă ${devices.length} dispozitive...`, 'success'); // Add devices one by one let addedCount = 0; let failedCount = 0; let duplicateCount = 0; let failedDevices = []; let duplicateDevices = []; const addDevice = (device, index) => { return fetch('/api/add', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(device) }) .then(response => response.json()) .then(result => { if (result.success) { addedCount++; } else { // Verifică dacă este o eroare de duplicat if (result.message.includes('există deja')) { duplicateCount++; duplicateDevices.push(`${device.name} (${result.message})`); } else { failedCount++; failedDevices.push(`${device.name}: ${result.message}`); } console.warn(`Failed to add ${device.name}:`, result.message); } }) .catch(error => { failedCount++; failedDevices.push(`${device.name}: ${error.message}`); console.error(`Error adding ${device.name}:`, error); }); }; // Add all devices in parallel Promise.all(devices.map(addDevice)) .then(() => { let message = ''; let messageType = 'success'; if (addedCount > 0 && failedCount === 0 && duplicateCount === 0) { message = `${addedCount} dispozitive adăugate cu succes!`; } else if (addedCount > 0) { message = `${addedCount} dispozitive adăugate cu succes`; if (duplicateCount > 0) { message += `, ${duplicateCount} duplicate ignorate`; } if (failedCount > 0) { message += `, ${failedCount} eșuate`; } message += '.'; if (duplicateCount > 0 || failedCount > 0) { messageType = 'warning'; } } else { if (duplicateCount > 0 && failedCount === 0) { message = `Toate ${duplicateCount} dispozitivele selectate există deja în sistem.`; messageType = 'warning'; } else if (duplicateCount > 0) { message = `${duplicateCount} dispozitive duplicate, ${failedCount} eșuate.`; messageType = 'error'; } else { message = `Toate ${failedCount} dispozitivele au eșuat să fie adăugate.`; messageType = 'error'; } } // Dacă există duplicate sau erori, afișează detalii suplimentare în consolă if (duplicateDevices.length > 0) { console.info('Dispozitive duplicate:', duplicateDevices); } if (failedDevices.length > 0) { console.warn('Dispozitive eșuate:', failedDevices); } showMessage(message, messageType); if (addedCount > 0) { closeScanModal(); refreshComputers(); } }); } function addFromScan(hostname, mac, ip) { // Check if this is called from a disabled button (device already exists) if (event && event.target && event.target.hasAttribute('disabled')) { showMessage('Device-ul există deja în sistem!', 'warning'); return; } fetch('/api/add', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({name: hostname, mac: mac, ip: ip}) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage(result.message, 'success'); closeScanModal(); refreshComputers(); } else { showMessage(result.message, 'error'); } }) .catch(error => { showMessage('Eroare la adăugarea calculatorului: ' + error.message, 'error'); }); } function closeScanModal() { scanModal.style.display = 'none'; } function openEditModal(currentName, currentMac, currentIp) { document.getElementById('editName').value = currentName; document.getElementById('editName').dataset.originalName = currentName; document.getElementById('editMac').value = currentMac; document.getElementById('editIp').value = currentIp || ''; editModal.style.display = 'block'; document.getElementById('editName').focus(); } function closeEditModal() { editModal.style.display = 'none'; document.getElementById('editName').value = ''; document.getElementById('editMac').value = ''; document.getElementById('editIp').value = ''; } function performEdit() { const oldName = document.getElementById('editName').dataset.originalName || document.getElementById('editName').value; const newName = document.getElementById('editName').value.trim(); const newMac = document.getElementById('editMac').value.trim(); const newIp = document.getElementById('editIp').value.trim(); if (!newName) { showMessage('Numele nu poate fi gol!', 'error'); return; } if (!newMac) { showMessage('Adresa MAC nu poate fi goală!', 'error'); return; } // Validare simplă pentru formatul MAC-ului const macPattern = /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/; if (!macPattern.test(newMac)) { showMessage('Formatul MAC-ului este invalid! Folosește formatul XX:XX:XX:XX:XX:XX', 'error'); return; } fetch('/api/edit', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({ old_name: oldName, new_name: newName, new_mac: newMac, new_ip: newIp }) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage(result.message, 'success'); closeEditModal(); refreshComputers(); } else { showMessage(result.message, 'error'); } }) .catch(error => { showMessage('Eroare la editarea calculatorului: ' + error.message, 'error'); }); } function deleteComputer(name, mac) { const displayName = name && name.trim() ? name : `Calculator cu MAC ${mac}`; if (!confirm(`Sigur vrei să ștergi calculatorul "${displayName}"?`)) { return; } fetch('/api/delete', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify({name: name, mac: mac}) }) .then(response => response.json()) .then(result => { if (result.success) { showMessage(result.message, 'success'); refreshComputers(); } else { showMessage(result.message, 'error'); } }) .catch(error => { showMessage('Eroare la ștergerea calculatorului: ' + error.message, 'error'); }); } // Close modals when clicking outside window.onclick = function(event) { if (event.target == addModal) { closeAddModal(); } if (event.target == scanModal) { closeScanModal(); } if (event.target == editModal) { closeEditModal(); } } // Allow Enter key to perform edit document.addEventListener('keydown', function(event) { if (event.key === 'Enter' && editModal.style.display === 'block') { performEdit(); } });