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:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
|||||||
@@ -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
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1494,4 +1494,24 @@ 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;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user