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()">&#9776;</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