feat: Added Auto Labeling to Montior Tab. When sending hosts from the scan tab, it will bring their hostnames over to the label section. When adding a one off host to the montior tab, it will auto query it's hostname. You can also edit labels by double clicking. Closes #3

This commit is contained in:
2026-10-06 16:49:04 -04:00
parent 8cc8189820
commit c5931c723f
5 changed files with 99 additions and 6 deletions
+1
View File
@@ -3,6 +3,7 @@
### 🐛 Bug Fixes ### 🐛 Bug Fixes
- Status Colors on Monitor tab now reflect status of host. Closes #7 - Status Colors on Monitor tab now reflect status of host. Closes #7
- Removed unused function.
## [0.2.0] - 2026-09-24 ## [0.2.0] - 2026-09-24
### 🚀 Features ### 🚀 Features
+16
View File
@@ -180,3 +180,19 @@ pub async fn monitor_stop() -> Result<(), String> {
} }
Ok(()) Ok(())
} }
#[tauri::command]
pub async fn monitor_update_label(ip: String, label: String) -> Result<(), String> {
let parsed: IpAddr = ip.parse().map_err(|e| format!("Invalid IP: {}", e))?;
let state = get_monitor();
let mut guard = state.lock().await;
if let Some(entry) = guard.entries.get_mut(&parsed) {
entry.label = if label.is_empty() { None } else { Some(label) };
}
Ok(())
}
#[tauri::command]
pub async fn monitor_resolve_host(ip: String) -> Result<Option<String>, String> {
let parsed: IpAddr = ip.parse().map_err(|e| format!("Invalid IP: {}", e))?;
Ok(crate::net::dns::reverse_lookup(parsed).await)
}
+2
View File
@@ -32,6 +32,8 @@ pub fn run() {
commands::updater::check_for_update, commands::updater::check_for_update,
commands::actions::check_privileges, commands::actions::check_privileges,
commands::changelog::get_changelog, commands::changelog::get_changelog,
commands::monitor::monitor_update_label,
commands::monitor::monitor_resolve_host
]) ])
.run(tauri::generate_context!()) .run(tauri::generate_context!())
.expect("error while running tauri application"); .expect("error while running tauri application");
+60 -6
View File
@@ -609,7 +609,7 @@ const sender = (() => {
if (action.startsWith('nmap')) { if (action.startsWith('nmap')) {
nmapTab.setTarget(hosts.map((h) => String(h.ip))); nmapTab.setTarget(hosts.map((h) => String(h.ip)));
} else if (action.startsWith('monitor')) { } else if (action.startsWith('monitor')) {
monitorTab.setTargets(hosts.map(function (h) { return String(h.ip); })); monitorTab.setTargets(hosts);
} }
document.querySelectorAll('.send-menu').forEach((m) => m.hidden = true); document.querySelectorAll('.send-menu').forEach((m) => m.hidden = true);
@@ -675,7 +675,8 @@ const ctxMenu = (() => {
traceroute.run(ip); traceroute.run(ip);
break; break;
case 'send-monitor': case 'send-monitor':
monitorTab.setTargets([ip]); var monHost = table.getAll().find(function (h) { return String(h.ip) === ip; });
monitorTab.setTargets(monHost ? [monHost] : [ip]);
break; break;
case 'send-nmap': case 'send-nmap':
nmapTab.setTarget([ip]); nmapTab.setTarget([ip]);
@@ -967,7 +968,7 @@ const monitorTab = (() => {
return '<tr data-ip="' + ip + '">' return '<tr data-ip="' + ip + '">'
+ '<td>' + ip + '</td>' + '<td>' + ip + '</td>'
+ '<td>' + label + '</td>' + '<td class="editable-label" data-ip="' + ip + '">' + label + '</td>'
+ '<td class="' + statusClass + '">' + e.status + '</td>' + '<td class="' + statusClass + '">' + e.status + '</td>'
+ '<td>' + lastRtt + '</td>' + '<td>' + lastRtt + '</td>'
+ '<td>' + minRtt + '</td>' + '<td>' + minRtt + '</td>'
@@ -994,6 +995,16 @@ const monitorTab = (() => {
try { try {
await invoke('monitor_add_hosts', { hosts: hosts }); await invoke('monitor_add_hosts', { hosts: hosts });
for (var i = 0; i < hosts.length; i++) {
try {
var hostname = await invoke('monitor_resolve_host', { ip: hosts[i].ip });
if (hostname) {
await invoke('monitor_update_label', { ip: hosts[i].ip, label: hostname });
}
} catch (e) { }
}
var updated = await invoke('monitor_get_entries'); var updated = await invoke('monitor_get_entries');
entries = {}; entries = {};
updated.forEach(function (e) { entries[e.ip] = e; }); updated.forEach(function (e) { entries[e.ip] = e; });
@@ -1048,9 +1059,20 @@ const monitorTab = (() => {
} }
} }
function setTargets(ips) { function setTargets(hosts) {
els.input().value = ips.join(', '); var items = hosts.map(function (h) {
// Switch to monitor tab if (typeof h === 'string') return { ip: h, label: null };
return { ip: String(h.ip), label: h.hostname || null };
});
invoke('monitor_add_hosts', { hosts: items }).then(function () {
return invoke('monitor_get_entries');
}).then(function (updated) {
entries = {};
updated.forEach(function (e) { entries[e.ip] = e; });
render();
});
document.querySelectorAll('.tab').forEach(function (t) { t.classList.remove('active'); }); document.querySelectorAll('.tab').forEach(function (t) { t.classList.remove('active'); });
document.querySelectorAll('.view').forEach(function (v) { v.classList.remove('active'); }); document.querySelectorAll('.view').forEach(function (v) { v.classList.remove('active'); });
document.querySelector('[data-tab="monitor"]').classList.add('active'); document.querySelector('[data-tab="monitor"]').classList.add('active');
@@ -1085,6 +1107,38 @@ const monitorTab = (() => {
var btn = e.target.closest('.btn-remove'); var btn = e.target.closest('.btn-remove');
if (btn) removeHost(btn.dataset.ip); if (btn) removeHost(btn.dataset.ip);
}); });
els.body().addEventListener('dblclick', function (e) {
var cell = e.target.closest('.editable-label');
if (!cell) return;
var ip = cell.dataset.ip;
var currentLabel = cell.textContent === '-' ? '' : cell.textContent;
var input = document.createElement('input');
input.type = 'text';
input.value = currentLabel;
input.className = 'label-edit-input';
cell.textContent = '';
cell.appendChild(input);
input.focus();
input.select();
function save() {
var newLabel = input.value.trim();
invoke('monitor_update_label', { ip: ip, label: newLabel }).then(function () {
return invoke('monitor_get_entries');
}).then(function (updated) {
entries = {};
updated.forEach(function (e) { entries[e.ip] = e; });
render();
});
}
input.addEventListener('blur', save);
input.addEventListener('keydown', function (ev) {
if (ev.key === 'Enter') save();
if (ev.key === 'Escape') render();
});
});
setupListeners(); setupListeners();
} }
+20
View File
@@ -1495,3 +1495,23 @@ body {
:root[data-theme="midnight"] .toolbar-circuit { :root[data-theme="midnight"] .toolbar-circuit {
filter: brightness(0.8); filter: brightness(0.8);
} }
.editable-label {
cursor: pointer;
}
.editable-label:hover {
background: var(--cyan-dim);
}
.label-edit-input {
width: 100%;
padding: 2px 6px;
font-family: var(--font-mono);
font-size: 12px;
color: var(--text-primary);
background: var(--bg-primary);
border: 1px solid var(--cyan);
border-radius: var(--radius);
outline: none;
}