From ed26def7d76ac011075c11e8c1679ed1f7a08abc Mon Sep 17 00:00:00 2001
From: Matthias Nott <mnott@mnsoft.org>
Date: Sat, 21 Feb 2026 16:48:40 +0100
Subject: [PATCH] feat: Clickable stat tiles, view toggle, CPU/memory metrics, restore fix
---
static/index.html | 43 ++++++++++++++++++++++++++++---------------
1 files changed, 28 insertions(+), 15 deletions(-)
diff --git a/static/index.html b/static/index.html
index d39e965..a043346 100644
--- a/static/index.html
+++ b/static/index.html
@@ -13,7 +13,7 @@
#main { flex: 1; display: flex; flex-direction: column; overflow-x: hidden; }
#topbar { background: #111827; border-bottom: 1px solid #1f2937; padding: 0.75rem 1.5rem; display: flex; align-items: center; gap: 1rem; }
#page-content { flex: 1; padding: 1.5rem; overflow-y: auto; }
- .breadcrumb { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: #9ca3af; }
+ .breadcrumb { display: flex; align-items: center; gap: 0.5rem; font-size: 0.875rem; color: #9ca3af; flex-wrap: wrap; }
.breadcrumb a { color: #60a5fa; cursor: pointer; text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
.breadcrumb .sep { color: #4b5563; }
@@ -22,19 +22,28 @@
.sidebar-logo { padding: 1.25rem 1rem; font-size: 1.125rem; font-weight: 700; color: #f3f4f6; border-bottom: 1px solid #1f2937; display: flex; align-items: center; gap: 0.5rem; }
.sidebar-nav { padding: 0.75rem 0.5rem; flex: 1; }
.sidebar-footer { padding: 0.75rem 1rem; border-top: 1px solid #1f2937; font-size: 0.75rem; color: #6b7280; }
- .project-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; }
- .env-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 1rem; }
- .service-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; }
- .stat-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 1rem; }
+ .grid-auto { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1rem; }
+ .grid-stats { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 0.75rem; }
+ .grid-metrics { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1rem; }
.card-clickable { cursor: pointer; transition: border-color 0.2s, transform 0.15s; }
.card-clickable:hover { border-color: #60a5fa; transform: translateY(-1px); }
+ .stat-tile { cursor: pointer; transition: border-color 0.2s, transform 0.1s; }
+ .stat-tile:hover { border-color: #60a5fa; transform: translateY(-2px); }
+ .filter-badge { display: inline-flex; align-items: center; gap: 0.375rem; padding: 0.25rem 0.625rem; border-radius: 9999px; font-size: 0.75rem; font-weight: 600; background: rgba(59,130,246,0.15); color: #60a5fa; border: 1px solid rgba(59,130,246,0.3); }
+ .filter-badge button { background: none; border: none; color: #60a5fa; cursor: pointer; font-size: 0.875rem; padding: 0; line-height: 1; }
+ .filter-badge button:hover { color: #f87171; }
+ .view-toggle { display: flex; background: #1f2937; border-radius: 0.375rem; overflow: hidden; border: 1px solid #374151; }
+ .view-toggle button { background: none; border: none; color: #6b7280; padding: 0.25rem 0.5rem; font-size: 0.75rem; cursor: pointer; display: flex; align-items: center; gap: 0.25rem; }
+ .view-toggle button.active { background: rgba(59,130,246,0.2); color: #60a5fa; }
+ .view-toggle button:hover:not(.active) { color: #d1d5db; }
.mobile-overlay { display: none; position: fixed; inset: 0; background: rgba(0,0,0,0.6); z-index: 40; }
@media (max-width: 768px) {
#sidebar { position: fixed; left: -240px; top: 0; bottom: 0; z-index: 50; transition: left 0.2s; }
#sidebar.open { left: 0; }
.mobile-overlay.open { display: block; }
.hamburger { display: block; }
- .project-grid, .env-grid, .service-grid { grid-template-columns: 1fr; }
+ .grid-auto { grid-template-columns: 1fr; }
+ .grid-stats { grid-template-columns: repeat(2, 1fr); }
}
</style>
</head>
@@ -53,7 +62,6 @@
<!-- App Shell -->
<div id="app" style="display:none;">
- <!-- Mobile overlay -->
<div id="mobile-overlay" class="mobile-overlay" onclick="toggleSidebar()"></div>
<!-- Sidebar -->
@@ -66,10 +74,6 @@
<a class="sidebar-link active" data-page="dashboard" onclick="showPage('dashboard')">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg>
Dashboard
- </a>
- <a class="sidebar-link" data-page="services" onclick="showPage('services')">
- <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2L2 7l10 5 10-5-10-5z"/><path d="M2 17l10 5 10-5"/><path d="M2 12l10 5 10-5"/></svg>
- Services
</a>
<a class="sidebar-link" data-page="backups" onclick="showPage('backups')">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></svg>
@@ -91,17 +95,26 @@
<!-- Main Content -->
<div id="main">
- <!-- Top bar -->
<div id="topbar">
<button class="hamburger" onclick="toggleSidebar()">☰</button>
<div id="breadcrumbs" class="breadcrumb" style="flex:1;"></div>
+ <div id="view-toggle-wrap" style="display:none;">
+ <div class="view-toggle">
+ <button id="btn-view-cards" class="active" onclick="setViewMode('cards')" title="Card view">
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/></svg>
+ Cards
+ </button>
+ <button id="btn-view-table" onclick="setViewMode('table')" title="Table view">
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="3" y1="6" x2="21" y2="6"/><line x1="3" y1="12" x2="21" y2="12"/><line x1="3" y1="18" x2="21" y2="18"/></svg>
+ Table
+ </button>
+ </div>
+ </div>
<div style="display:flex;align-items:center;gap:0.75rem;">
<div id="refresh-indicator" class="refresh-ring paused" title="Auto-refresh"></div>
<button class="btn btn-ghost btn-xs" onclick="refreshCurrentPage()" title="Refresh now">Refresh</button>
</div>
</div>
-
- <!-- Page content -->
<div id="page-content"></div>
</div>
</div>
@@ -121,7 +134,7 @@
</div>
<div class="modal-footer">
<button class="btn btn-ghost btn-sm" onclick="closeLogModal()">Close</button>
- <button class="btn btn-primary btn-sm" id="log-refresh-btn" onclick="refreshLogs()">Refresh</button>
+ <button class="btn btn-primary btn-sm" onclick="refreshLogs()">Refresh</button>
</div>
</div>
</div>
--
Gitblit v1.3.1