feat(admin/ui): filters + badges + full inventory dialog with search; CSV export; types tightened; feat(desktop): charts in diagnostics and heartbeat interval settings; feat(agent): normalized software/services; linux lspci/lsusb parsed
This commit is contained in:
parent
e682c6773a
commit
0556502685
4 changed files with 308 additions and 46 deletions
|
|
@ -240,6 +240,60 @@ fn build_inventory_metadata(system: &System) -> serde_json::Value {
|
|||
}
|
||||
}
|
||||
|
||||
// Normalização de software/serviços no topo do inventário
|
||||
if let Some(obj) = inventory.as_object_mut() {
|
||||
// Merge software
|
||||
let mut software: Vec<serde_json::Value> = Vec::new();
|
||||
if let Some(existing) = obj.get("software").and_then(|v| v.as_array()) {
|
||||
software.extend(existing.iter().cloned());
|
||||
}
|
||||
if let Some(ext) = obj.get("extended").and_then(|v| v.as_object()) {
|
||||
// Windows normalize
|
||||
if let Some(win) = ext.get("windows").and_then(|v| v.as_object()) {
|
||||
if let Some(ws) = win.get("software").and_then(|v| v.as_array()) {
|
||||
for item in ws {
|
||||
let name = item.get("DisplayName").or_else(|| item.get("name")).cloned().unwrap_or(json!(null));
|
||||
let version = item.get("DisplayVersion").or_else(|| item.get("version")).cloned().unwrap_or(json!(null));
|
||||
let publisher = item.get("Publisher").cloned().unwrap_or(json!(null));
|
||||
software.push(json!({ "name": name, "version": version, "source": publisher }));
|
||||
}
|
||||
}
|
||||
}
|
||||
// macOS normalize
|
||||
if let Some(macos) = ext.get("macos").and_then(|v| v.as_object()) {
|
||||
if let Some(pkgs) = macos.get("packages").and_then(|v| v.as_array()) {
|
||||
for p in pkgs {
|
||||
software.push(json!({ "name": p, "version": null, "source": "pkgutil" }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !software.is_empty() {
|
||||
obj.insert("software".into(), json!(software));
|
||||
}
|
||||
|
||||
// Merge services
|
||||
let mut services: Vec<serde_json::Value> = Vec::new();
|
||||
if let Some(existing) = obj.get("services").and_then(|v| v.as_array()) {
|
||||
services.extend(existing.iter().cloned());
|
||||
}
|
||||
if let Some(ext) = obj.get("extended").and_then(|v| v.as_object()) {
|
||||
if let Some(win) = ext.get("windows").and_then(|v| v.as_object()) {
|
||||
if let Some(wsvc) = win.get("services").and_then(|v| v.as_array()) {
|
||||
for s in wsvc {
|
||||
let name = s.get("Name").cloned().unwrap_or(json!(null));
|
||||
let status = s.get("Status").cloned().unwrap_or(json!(null));
|
||||
let display = s.get("DisplayName").cloned().unwrap_or(json!(null));
|
||||
services.push(json!({ "name": name, "status": status, "displayName": display }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if !services.is_empty() {
|
||||
obj.insert("services".into(), json!(services));
|
||||
}
|
||||
}
|
||||
|
||||
json!({ "inventory": inventory })
|
||||
}
|
||||
|
||||
|
|
@ -355,6 +409,17 @@ fn collect_linux_extended() -> serde_json::Value {
|
|||
.ok()
|
||||
.map(|out| String::from_utf8_lossy(&out.stdout).to_string())
|
||||
.unwrap_or_default();
|
||||
// Parse básico de lspci/lsusb em listas
|
||||
fn parse_lines_to_list(input: &str) -> Vec<serde_json::Value> {
|
||||
input
|
||||
.lines()
|
||||
.map(|l| l.trim())
|
||||
.filter(|l| !l.is_empty())
|
||||
.map(|l| json!({ "text": l }))
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
let pci_list = parse_lines_to_list(&lspci);
|
||||
let usb_list = parse_lines_to_list(&lsusb);
|
||||
|
||||
// smartctl (se disponível) por disco
|
||||
let mut smart: Vec<serde_json::Value> = Vec::new();
|
||||
|
|
@ -393,6 +458,8 @@ fn collect_linux_extended() -> serde_json::Value {
|
|||
"lsblk": block_json,
|
||||
"lspci": lspci,
|
||||
"lsusb": lsusb,
|
||||
"pciList": pci_list,
|
||||
"usbList": usb_list,
|
||||
"smart": smart,
|
||||
}
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue