Development #8
@@ -3,6 +3,7 @@
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- Status Colors on Monitor tab now reflect status of host. Closes #7
|
||||
- Removed unused function.
|
||||
## [0.2.0] - 2026-09-24
|
||||
|
||||
### 🚀 Features
|
||||
|
||||
@@ -180,3 +180,19 @@ pub async fn monitor_stop() -> Result<(), String> {
|
||||
}
|
||||
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::actions::check_privileges,
|
||||
commands::changelog::get_changelog,
|
||||
commands::monitor::monitor_update_label,
|
||||
commands::monitor::monitor_resolve_host
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
+60
-6
@@ -609,7 +609,7 @@ const sender = (() => {
|
||||
if (action.startsWith('nmap')) {
|
||||
nmapTab.setTarget(hosts.map((h) => String(h.ip)));
|
||||
} 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);
|
||||
@@ -675,7 +675,8 @@ const ctxMenu = (() => {
|
||||
traceroute.run(ip);
|
||||
break;
|
||||
case 'send-monitor':
|
||||
monitorTab.setTargets([ip]);
|
||||
var monHost = table.getAll().find(function (h) { return String(h.ip) === ip; });
|
||||
monitorTab.setTargets(monHost ? [monHost] : [ip]);
|
||||
break;
|
||||
case 'send-nmap':
|
||||
nmapTab.setTarget([ip]);
|
||||
@@ -967,7 +968,7 @@ const monitorTab = (() => {
|
||||
|
||||
return '<tr data-ip="' + ip + '">'
|
||||
+ '<td>' + ip + '</td>'
|
||||
+ '<td>' + label + '</td>'
|
||||
+ '<td class="editable-label" data-ip="' + ip + '">' + label + '</td>'
|
||||
+ '<td class="' + statusClass + '">' + e.status + '</td>'
|
||||
+ '<td>' + lastRtt + '</td>'
|
||||
+ '<td>' + minRtt + '</td>'
|
||||
@@ -994,6 +995,16 @@ const monitorTab = (() => {
|
||||
|
||||
try {
|
||||
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');
|
||||
entries = {};
|
||||
updated.forEach(function (e) { entries[e.ip] = e; });
|
||||
@@ -1048,9 +1059,20 @@ const monitorTab = (() => {
|
||||
}
|
||||
}
|
||||
|
||||
function setTargets(ips) {
|
||||
els.input().value = ips.join(', ');
|
||||
// Switch to monitor tab
|
||||
function setTargets(hosts) {
|
||||
var items = hosts.map(function (h) {
|
||||
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('.view').forEach(function (v) { v.classList.remove('active'); });
|
||||
document.querySelector('[data-tab="monitor"]').classList.add('active');
|
||||
@@ -1085,6 +1107,38 @@ const monitorTab = (() => {
|
||||
var btn = e.target.closest('.btn-remove');
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -1495,3 +1495,23 @@ body {
|
||||
:root[data-theme="midnight"] .toolbar-circuit {
|
||||
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