mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-09-10 21:18:42 -06:00
Load device records on startup and improve storage display
This commit is contained in:
@@ -283,25 +283,40 @@ export default function DeviceDetails({ device, onBack }) {
|
||||
};
|
||||
|
||||
const renderStorage = () => {
|
||||
const parseNum = (val) => {
|
||||
const toNum = (val) => {
|
||||
if (val === undefined || val === null) return undefined;
|
||||
const n = Number(String(val).replace(/[^0-9.]/g, ""));
|
||||
const n = Number(val);
|
||||
return Number.isNaN(n) ? undefined : n;
|
||||
};
|
||||
|
||||
const rows = (details.storage || []).map((d) => {
|
||||
const total = parseNum(d.total);
|
||||
const rawFree = parseNum(d.free);
|
||||
const freePct = rawFree !== undefined
|
||||
? rawFree <= 100
|
||||
? rawFree
|
||||
: total
|
||||
? (rawFree / total) * 100
|
||||
: undefined
|
||||
: undefined;
|
||||
let usage = parseNum(d.usage);
|
||||
if ((usage === undefined || Number.isNaN(usage)) && freePct !== undefined) {
|
||||
usage = 100 - freePct;
|
||||
const total = toNum(d.total);
|
||||
let usage = toNum(d.usage);
|
||||
let freePct;
|
||||
|
||||
if (usage !== undefined) {
|
||||
if (usage <= 1) usage *= 100;
|
||||
freePct = 100 - usage;
|
||||
} else {
|
||||
const freeRaw = toNum(d.free);
|
||||
if (freeRaw !== undefined) {
|
||||
if (freeRaw > 1 && freeRaw > 100 && total) {
|
||||
freePct = (freeRaw / total) * 100;
|
||||
} else if (freeRaw <= 1) {
|
||||
freePct = freeRaw * 100;
|
||||
} else {
|
||||
freePct = freeRaw;
|
||||
}
|
||||
usage = freePct !== undefined ? 100 - freePct : undefined;
|
||||
} else {
|
||||
const usedRaw = toNum(d.used);
|
||||
if (usedRaw !== undefined && total) {
|
||||
usage = (usedRaw / total) * 100;
|
||||
freePct = 100 - usage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
drive: d.drive,
|
||||
disk_type: d.disk_type,
|
||||
@@ -310,8 +325,10 @@ export default function DeviceDetails({ device, onBack }) {
|
||||
free: freePct,
|
||||
};
|
||||
});
|
||||
|
||||
if (!rows.length)
|
||||
return placeholderTable(["Drive Letter", "Disk Type", "Usage", "Total Size", "Free %"]);
|
||||
|
||||
return (
|
||||
<Box sx={{ maxHeight: 400, overflowY: "auto" }}>
|
||||
<Table size="small">
|
||||
|
@@ -165,12 +165,7 @@ export default function DeviceList({ onSelectDevice }) {
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{sorted.map((r, i) => (
|
||||
<TableRow
|
||||
key={r.id || i}
|
||||
hover
|
||||
onClick={() => onSelectDevice && onSelectDevice(r)}
|
||||
sx={{ cursor: onSelectDevice ? "pointer" : "default" }}
|
||||
>
|
||||
<TableRow key={r.id || i} hover>
|
||||
<TableCell>
|
||||
<Box sx={{ display: "flex", alignItems: "center" }}>
|
||||
<Box
|
||||
@@ -187,13 +182,21 @@ export default function DeviceList({ onSelectDevice }) {
|
||||
{r.status}
|
||||
</Box>
|
||||
</TableCell>
|
||||
<TableCell>{r.hostname}</TableCell>
|
||||
<TableCell
|
||||
onClick={() => onSelectDevice && onSelectDevice(r)}
|
||||
sx={{ cursor: onSelectDevice ? "pointer" : "default" }}
|
||||
>
|
||||
{r.hostname}
|
||||
</TableCell>
|
||||
<TableCell>{timeSince(r.lastSeen)}</TableCell>
|
||||
<TableCell>{r.os}</TableCell>
|
||||
<TableCell align="right">
|
||||
<IconButton
|
||||
size="small"
|
||||
onClick={(e) => openMenu(e, r)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
openMenu(e, r);
|
||||
}}
|
||||
sx={{ color: "#ccc" }}
|
||||
>
|
||||
<MoreVertIcon fontSize="small" />
|
||||
|
@@ -398,6 +398,36 @@ def init_db():
|
||||
|
||||
init_db()
|
||||
|
||||
|
||||
def load_agents_from_db():
|
||||
"""Populate registered_agents with any devices stored in the database."""
|
||||
try:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cur = conn.cursor()
|
||||
cur.execute("SELECT hostname, details FROM device_details")
|
||||
for hostname, details_json in cur.fetchall():
|
||||
try:
|
||||
details = json.loads(details_json or "{}")
|
||||
except Exception:
|
||||
details = {}
|
||||
summary = details.get("summary", {})
|
||||
agent_id = summary.get("agent_id") or hostname
|
||||
registered_agents[agent_id] = {
|
||||
"agent_id": agent_id,
|
||||
"hostname": summary.get("hostname") or hostname,
|
||||
"agent_operating_system": summary.get("operating_system")
|
||||
or summary.get("agent_operating_system")
|
||||
or "-",
|
||||
"last_seen": summary.get("last_seen") or 0,
|
||||
"status": "Offline",
|
||||
}
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
print(f"[WARN] Failed to load agents from DB: {e}")
|
||||
|
||||
|
||||
load_agents_from_db()
|
||||
|
||||
@app.route("/api/agents")
|
||||
def get_agents():
|
||||
"""
|
||||
@@ -481,10 +511,20 @@ def set_device_description(hostname: str):
|
||||
|
||||
@app.route("/api/agent/<agent_id>", methods=["DELETE"])
|
||||
def delete_agent(agent_id: str):
|
||||
"""Remove an agent from the in-memory registry."""
|
||||
if agent_id in registered_agents:
|
||||
registered_agents.pop(agent_id, None)
|
||||
agent_configurations.pop(agent_id, None)
|
||||
"""Remove an agent from the registry and database."""
|
||||
info = registered_agents.pop(agent_id, None)
|
||||
agent_configurations.pop(agent_id, None)
|
||||
hostname = info.get("hostname") if info else None
|
||||
if hostname:
|
||||
try:
|
||||
conn = sqlite3.connect(DB_PATH)
|
||||
cur = conn.cursor()
|
||||
cur.execute("DELETE FROM device_details WHERE hostname = ?", (hostname,))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except Exception as e:
|
||||
return jsonify({"error": str(e)}), 500
|
||||
if info:
|
||||
return jsonify({"status": "removed"})
|
||||
return jsonify({"error": "agent not found"}), 404
|
||||
|
||||
|
Reference in New Issue
Block a user