Add container summary on card face, fix df parsing for wrapped lines, collect OS info, faster startup and refresh
This commit is contained in:
@@ -249,7 +249,7 @@ def collect_all():
|
||||
|
||||
|
||||
def collector_loop():
|
||||
time.sleep(10) # Let the app start up
|
||||
time.sleep(2) # Brief pause to let Flask start
|
||||
while True:
|
||||
try:
|
||||
collect_all()
|
||||
|
||||
@@ -186,13 +186,18 @@ gather_container_stats() {
|
||||
echo "mem_percent=$mem_pct"
|
||||
fi
|
||||
|
||||
# Disk (rootfs)
|
||||
# Disk (rootfs) - merge wrapped lines, find the / mount
|
||||
local disk_info
|
||||
disk_info=$($exec_cmd df -B1 / 2>/dev/null | tail -1)
|
||||
disk_info=$($exec_cmd df -B1 / 2>/dev/null | awk 'NR>1{line=line $0" "} END{print line}')
|
||||
if [ -n "$disk_info" ]; then
|
||||
echo "disk_total=$(echo "$disk_info" | awk '{print $2}')"
|
||||
echo "disk_used=$(echo "$disk_info" | awk '{print $3}')"
|
||||
echo "disk_percent=$(echo "$disk_info" | awk '{gsub(/%/,""); print $5}')"
|
||||
# Extract numbers - find the fields: total used avail percent
|
||||
local d_total d_used d_pct
|
||||
d_total=$(echo "$disk_info" | awk '{for(i=1;i<=NF;i++) if($i+0>0 && $i !~ /%/){print $i; exit}}')
|
||||
d_used=$(echo "$disk_info" | awk '{for(i=1;i<=NF;i++) if($i+0>0 && $i !~ /%/){n++; if(n==2){print $i; exit}}}')
|
||||
d_pct=$(echo "$disk_info" | grep -oE '[0-9]+%' | head -1 | tr -d '%')
|
||||
[ -n "$d_total" ] && echo "disk_total=$d_total"
|
||||
[ -n "$d_used" ] && echo "disk_used=$d_used"
|
||||
[ -n "$d_pct" ] && echo "disk_percent=$d_pct"
|
||||
fi
|
||||
|
||||
# IP
|
||||
@@ -200,6 +205,11 @@ gather_container_stats() {
|
||||
ip=$($exec_cmd hostname -I 2>/dev/null | awk '{print $1}')
|
||||
[ -n "$ip" ] && echo "ip=$ip"
|
||||
|
||||
# OS
|
||||
local os_pretty
|
||||
os_pretty=$($exec_cmd cat /etc/os-release 2>/dev/null | grep PRETTY_NAME | cut -d= -f2 | tr -d '"')
|
||||
[ -n "$os_pretty" ] && echo "os=$os_pretty"
|
||||
|
||||
# Uptime
|
||||
local uptime_s
|
||||
uptime_s=$($exec_cmd cut -d' ' -f1 /proc/uptime 2>/dev/null | cut -d. -f1)
|
||||
@@ -217,8 +227,11 @@ _sudo() {
|
||||
|
||||
# Proxmox LXC (pct)
|
||||
if command -v pct &>/dev/null; then
|
||||
_sudo pct list 2>/dev/null | tail -n +2 | while read -r vmid status _ name _; do
|
||||
[ -z "$vmid" ] && continue
|
||||
_sudo pct list 2>/dev/null | tail -n +2 | while read -r line; do
|
||||
[ -z "$line" ] && continue
|
||||
vmid=$(echo "$line" | awk '{print $1}')
|
||||
status=$(echo "$line" | awk '{print $2}')
|
||||
name=$(echo "$line" | awk '{print $NF}')
|
||||
echo "[container:pct-${vmid}]"
|
||||
echo "type=lxc"
|
||||
echo "platform=proxmox"
|
||||
|
||||
@@ -327,6 +327,63 @@ main {
|
||||
color: #475569;
|
||||
}
|
||||
|
||||
/* --- Container Summary (on card face) --- */
|
||||
|
||||
.ct-summary-list {
|
||||
margin-top: 10px;
|
||||
padding-top: 8px;
|
||||
border-top: 1px solid #334155;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 3px;
|
||||
}
|
||||
|
||||
.ct-summary-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
font-size: 0.7rem;
|
||||
color: #94a3b8;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.status-dot-sm {
|
||||
width: 5px;
|
||||
height: 5px;
|
||||
border-radius: 50%;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.status-dot-sm.online {
|
||||
background: #22c55e;
|
||||
}
|
||||
|
||||
.status-dot-sm.offline {
|
||||
background: #ef4444;
|
||||
}
|
||||
|
||||
.ct-summary-name {
|
||||
font-weight: 600;
|
||||
color: #cbd5e1;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.ct-summary-os {
|
||||
color: #64748b;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.ct-summary-ip {
|
||||
color: #64748b;
|
||||
font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
|
||||
font-size: 0.65rem;
|
||||
white-space: nowrap;
|
||||
margin-left: auto;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
/* --- Container / VM Sub-cards --- */
|
||||
|
||||
.container-grid {
|
||||
|
||||
@@ -63,6 +63,8 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% set containers = d.get('container', []) if d.get('container') else [] %}
|
||||
|
||||
{% if server.is_online %}
|
||||
<div class="usage-bars">
|
||||
<div class="usage-row">
|
||||
@@ -96,6 +98,20 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% if containers %}
|
||||
<div class="ct-summary-list">
|
||||
{% for ct in containers %}
|
||||
{% set ct_up = ct.get('status', '')|lower in ['running', 'started'] %}
|
||||
<div class="ct-summary-item">
|
||||
<span class="status-dot-sm {% if ct_up %}online{% else %}offline{% endif %}"></span>
|
||||
<span class="ct-summary-name">{{ ct.get('name', ct.get('id', '?')) }}</span>
|
||||
{% if ct.get('os') %}<span class="ct-summary-os">{{ ct.get('os') }}</span>{% endif %}
|
||||
{% if ct.get('ip') %}<span class="ct-summary-ip">{{ ct.get('ip') }}</span>{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% else %}
|
||||
<div class="offline-label">Unreachable</div>
|
||||
{% endif %}
|
||||
@@ -254,7 +270,6 @@
|
||||
</div>
|
||||
|
||||
<!-- Containers / VMs -->
|
||||
{% set containers = d.get('container', []) if d.get('container') else [] %}
|
||||
{% if containers %}
|
||||
<div class="detail-section wide">
|
||||
<h4>Containers & VMs</h4>
|
||||
@@ -396,16 +411,10 @@
|
||||
if (card) toggleDetails(card);
|
||||
}
|
||||
|
||||
// Auto-refresh without full page reload if a card is expanded,
|
||||
// otherwise do a simple reload
|
||||
setInterval(function() {
|
||||
if (document.querySelector('.server-card.expanded')) {
|
||||
// A card is open - reload page preserving hash
|
||||
location.reload();
|
||||
} else {
|
||||
location.reload();
|
||||
}
|
||||
}, 60000);
|
||||
// If no servers have data yet, refresh quickly; otherwise every 60s
|
||||
const hasData = document.querySelectorAll('.server-card').length > 0;
|
||||
const refreshMs = hasData ? 60000 : 5000;
|
||||
setInterval(function() { location.reload(); }, refreshMs);
|
||||
|
||||
// Restore state on load
|
||||
restoreExpanded();
|
||||
|
||||
Reference in New Issue
Block a user