Enhance mobile UI and network scanning experience
- Fix modal scroll issues on mobile devices with proper viewport constraints - Remove status column and apply status colors directly to device names - Reorder columns: IP before MAC for better logical flow - Optimize table layout for mobile with reduced padding and text ellipsis - Implement visual disabled state for existing devices in scan modal - Add intelligent device comparison to prevent duplicate additions - Exclude Docker bridge networks from Linux scanning fallback - Improve scan result handling with better error messaging 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -53,10 +53,9 @@ function displayComputers(computers) {
|
||||
🗑️
|
||||
</button>
|
||||
</td>
|
||||
<td>${computer.name}</td>
|
||||
<td style="font-family: monospace;">${computer.mac}</td>
|
||||
<td class="computer-name ${computer.status}">${computer.name}</td>
|
||||
<td>${computer.ip || '-'}</td>
|
||||
<td><span class="status ${computer.status}">${computer.status}</span></td>
|
||||
<td style="font-family: monospace;">${computer.mac}</td>
|
||||
</tr>
|
||||
`).join('');
|
||||
}
|
||||
@@ -182,20 +181,23 @@ function scanNetwork() {
|
||||
const network = getSelectedNetwork();
|
||||
const requestData = network ? { network: network } : {};
|
||||
|
||||
fetch('/api/scan', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(result => {
|
||||
// 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);
|
||||
displayScanResults(result.computers, existingComputers);
|
||||
if (result.message) {
|
||||
// Afișează mesajul deasupra tabelului
|
||||
document.getElementById('scan-results').innerHTML =
|
||||
@@ -228,20 +230,23 @@ function triggerWindowsScan() {
|
||||
|
||||
showMessage('Declanșând scanul Windows...', 'success');
|
||||
|
||||
fetch('/api/scan/windows', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify(requestData)
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
// 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);
|
||||
displayScanResults(data.computers, existingComputers);
|
||||
} else {
|
||||
let message = data.message || 'Scanul Windows a eșuat';
|
||||
|
||||
@@ -281,13 +286,16 @@ function triggerWindowsScan() {
|
||||
});
|
||||
}
|
||||
|
||||
function displayScanResults(computers) {
|
||||
function displayScanResults(computers, existingComputers = []) {
|
||||
if (computers.length === 0) {
|
||||
document.getElementById('scan-results').innerHTML =
|
||||
'<div class="message error">Nu s-au găsit calculatoare în rețea</div>';
|
||||
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 = `
|
||||
<div class="scan-controls">
|
||||
<label class="select-all-container">
|
||||
@@ -313,22 +321,31 @@ function displayScanResults(computers) {
|
||||
`;
|
||||
|
||||
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 += `
|
||||
<tr>
|
||||
<tr class="${rowClass}">
|
||||
<td>
|
||||
<input type="checkbox" class="device-checkbox"
|
||||
data-hostname="${computer.hostname}"
|
||||
data-mac="${computer.mac}"
|
||||
data-ip="${computer.ip}"
|
||||
onchange="updateAddButton()">
|
||||
onchange="updateAddButton()"
|
||||
${checkboxDisabled}>
|
||||
</td>
|
||||
<td>${computer.ip}</td>
|
||||
<td style="font-family: monospace;">${computer.mac}</td>
|
||||
<td>${computer.hostname}</td>
|
||||
<td><span class="status ${computer.status}">${computer.status}</span></td>
|
||||
<td>
|
||||
<button class="add-btn" onclick="addFromScan('${computer.hostname}', '${computer.mac}', '${computer.ip}')" title="Adaugă calculatorul">
|
||||
➕
|
||||
<button class="add-btn" onclick="addFromScan('${computer.hostname}', '${computer.mac}', '${computer.ip}')"
|
||||
title="${buttonTitle}" ${buttonDisabled}>
|
||||
${deviceExists ? '✓' : '➕'}
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -341,7 +358,7 @@ function displayScanResults(computers) {
|
||||
|
||||
function toggleSelectAll() {
|
||||
const selectAllCheckbox = document.getElementById('selectAll');
|
||||
const deviceCheckboxes = document.querySelectorAll('.device-checkbox');
|
||||
const deviceCheckboxes = document.querySelectorAll('.device-checkbox:not(:disabled)');
|
||||
|
||||
deviceCheckboxes.forEach(checkbox => {
|
||||
checkbox.checked = selectAllCheckbox.checked;
|
||||
@@ -351,8 +368,8 @@ function toggleSelectAll() {
|
||||
}
|
||||
|
||||
function updateAddButton() {
|
||||
const deviceCheckboxes = document.querySelectorAll('.device-checkbox');
|
||||
const checkedBoxes = document.querySelectorAll('.device-checkbox:checked');
|
||||
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');
|
||||
|
||||
@@ -363,7 +380,7 @@ function updateAddButton() {
|
||||
`➕ Adaugă Selectate (${checkedBoxes.length})` : '➕ Adaugă Selectate';
|
||||
}
|
||||
|
||||
// Update "Select All" checkbox state
|
||||
// Update "Select All" checkbox state (only consider enabled checkboxes)
|
||||
if (selectAllCheckbox) {
|
||||
if (checkedBoxes.length === 0) {
|
||||
selectAllCheckbox.indeterminate = false;
|
||||
@@ -378,7 +395,7 @@ function updateAddButton() {
|
||||
}
|
||||
|
||||
function addSelectedFromScan() {
|
||||
const checkedBoxes = document.querySelectorAll('.device-checkbox:checked');
|
||||
const checkedBoxes = document.querySelectorAll('.device-checkbox:checked:not(:disabled)');
|
||||
|
||||
if (checkedBoxes.length === 0) {
|
||||
showMessage('Nu ai selectat niciun dispozitiv!', 'error');
|
||||
@@ -484,6 +501,12 @@ function addSelectedFromScan() {
|
||||
}
|
||||
|
||||
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: {
|
||||
|
||||
Reference in New Issue
Block a user