import time import streamlit as st from app import cfg from app.cache import ( clients, cached_nodes, cached_pods, cached_deployments, cached_namespaces, cached_node_metrics, clear, ) st.set_page_config(page_title=cfg.page_title, page_icon=cfg.page_icon, layout="wide") clients() with st.sidebar: st.title("☸️ k3s Dashboard") auto_refresh = st.toggle("Auto-refresh (15s)", value=False) if st.button("πŸ”„ Refresh now"): clear() st.rerun() namespaces = ["all"] + cached_namespaces() sel_ns = st.selectbox("Namespace", namespaces) view = st.radio("View", ["Overview", "Nodes", "Pods", "Deployments"]) # Auto-refresh: sleep only the time remaining since the last refresh, # not the full TTL on every rerun (which would freeze the UI on sidebar clicks). if auto_refresh: now = time.time() if "last_refresh" not in st.session_state: st.session_state.last_refresh = now elapsed = now - st.session_state.last_refresh remaining = cfg.cache_ttl - elapsed if remaining <= 0: clear() st.session_state.last_refresh = time.time() st.rerun() else: time.sleep(remaining) st.rerun() # ── Views ────────────────────────────────────────────────────────────────────── if view == "Overview": nodes = cached_nodes() pods = cached_pods(sel_ns) deployments = cached_deployments(sel_ns) metrics = cached_node_metrics() ready_nodes = sum(1 for n in nodes if n["ready"]) ready_pods = sum(1 for p in pods if p["ready"]) ready_deps = sum(1 for d in deployments if d["available"] >= d["desired"] > 0) c1, c2, c3 = st.columns(3) c1.metric("Nodes", f"{ready_nodes}/{len(nodes)} ready") c2.metric("Pods", f"{ready_pods}/{len(pods)} ready") c3.metric("Deployments", f"{ready_deps}/{len(deployments)} ready") st.divider() st.subheader("Nodes") st.dataframe(nodes, use_container_width=True) st.subheader("Pods") st.dataframe(pods, use_container_width=True) elif view == "Nodes": nodes = cached_nodes() metrics = cached_node_metrics() st.subheader("Nodes") for node in nodes: m = metrics.get(node["name"], {}) with st.expander(f"{'βœ…' if node['ready'] else '❌'} {node['name']} β€” {node['roles']}"): col1, col2, col3 = st.columns(3) col1.metric("CPU capacity", f"{node['cpu_cap']} cores") col2.metric("Memory capacity", f"{node['mem_cap_mi']:.0f} Mi") col3.metric("Age", node["age"]) if m: col1.metric("CPU usage", m["cpu_usage"]) col2.metric("Memory usage", m["memory_usage"]) st.caption(f"OS: {node['os']} Kubelet: {node['kubelet_version']}") elif view == "Pods": pods = cached_pods(sel_ns) st.subheader(f"Pods β€” {sel_ns}") st.dataframe(pods, use_container_width=True) elif view == "Deployments": deployments = cached_deployments(sel_ns) st.subheader(f"Deployments β€” {sel_ns}") st.dataframe(deployments, use_container_width=True)