Diff -- /var/www/vhosts/3dshawn.com/site1/TEMPLATES/dashboard.html
Diff
/var/www/vhosts/3dshawn.com/site1/TEMPLATES/dashboard.html
modified on local at 2026-07-12 00:02:13
Added
+3
lines
Removed
-1
lines
Context
268
unchanged
Blobs
from 13b6a8ddb8a0
to a0ec3199a428
to a0ec3199a428
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.| 1 | 1 | <div class="page-head"> |
| 2 | 2 | <span class="page-eyebrow"><span class="dot"></span> Overview</span> |
| 3 | 3 | <h1 class="page-title">Dashboard</h1> |
| 4 | 4 | <p class="page-subtitle">Portfolio-wide health at a glance. Every file change, every schema change, every drifted container -- captured silently, restorable to any moment, no workflow discipline required.</p> |
| 5 | 5 | </div> |
| 6 | 6 | |
| 7 | 7 | <!-- KPI row --> |
| 8 | 8 | <div class="dash-grid"> |
| 9 | 9 | <div class="module glow-teal"> |
| 10 | 10 | <div class="module-head"><div class="left"> |
| 11 | 11 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/></svg></div> |
| 12 | 12 | <div class="module-title">File changes</div> |
| 13 | 13 | <span class="module-subtitle">Captured in the last 24 hours across every monitored path on every server.</span> |
| 14 | 14 | </div></div> |
| 15 | 15 | <div class="module-body kpi kpi-teal"> |
| 16 | 16 | <div class="num">$kpi_file_today</div> |
| 17 | 17 | <div class="lbl">Last 24h</div> |
| 18 | 18 | <div class="sub">All watched paths + containers</div> |
| 19 | 19 | </div> |
| 20 | 20 | </div> |
| 21 | 21 | |
| 22 | 22 | <div class="module glow-amber"> |
| 23 | 23 | <div class="module-head"><div class="left"> |
| 24 | 24 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v6c0 1.7 4 3 9 3s9-1.3 9-3V5"/><path d="M3 11v6c0 1.7 4 3 9 3s9-1.3 9-3v-6"/></svg></div> |
| 25 | 25 | <div class="module-title">Schema changes</div> |
| 26 | 26 | <span class="module-subtitle">DDL diffs across every monitored DB in the last 7 days -- caught even if no one committed them.</span> |
| 27 | 27 | </div></div> |
| 28 | 28 | <div class="module-body kpi kpi-amber"> |
| 29 | 29 | <div class="num">$kpi_schema_7d</div> |
| 30 | 30 | <div class="lbl">Last 7 days</div> |
| 31 | 31 | <div class="sub">Across all monitored databases</div> |
| 32 | 32 | </div> |
| 33 | 33 | </div> |
| 34 | 34 | |
| 35 | 35 | <div class="module glow-emerald"> |
| 36 | 36 | <div class="module-head"><div class="left"> |
| 37 | 37 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M20 13V7a2 2 0 0 0-2-2h-4l-2-3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h5"/><path d="M14 19l2 2 4-4"/></svg></div> |
| 38 | 38 | <div class="module-title">Named releases</div> |
| 39 | 39 | <span class="module-subtitle">Bookmark moments you've saved. Auto-purge respects these -- their blobs stay forever.</span> |
| 40 | 40 | </div></div> |
| 41 | 41 | <div class="module-body kpi kpi-emerald"> |
| 42 | 42 | <div class="num">$kpi_releases</div> |
| 43 | 43 | <div class="lbl">Bookmarked</div> |
| 44 | 44 | <div class="sub">Point-in-time restore anchors</div> |
| 45 | 45 | </div> |
| 46 | 46 | </div> |
| 47 | 47 | |
| 48 | 48 | <div class="module glow-rose"> |
| 49 | 49 | <div class="module-head"><div class="left"> |
| 50 | 50 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg></div> |
| 51 | 51 | <div class="module-title">Drift alerts</div> |
| 52 | 52 | <span class="module-subtitle">Containers that were supposed to stay immutable but got modified at runtime. Compliance signal.</span> |
| 53 | 53 | </div></div> |
| 54 | 54 | <div class="module-body kpi kpi-rose"> |
| 55 | 55 | <div class="num">$kpi_drifted</div> |
| 56 | 56 | <div class="lbl">Active drift</div> |
| 57 | 57 | <div class="sub">On supposedly-immutable containers</div> |
| 58 | 58 | </div> |
| 59 | 59 | </div> |
| 60 | 60 | </div> |
| 61 | 61 | |
| 62 | 62 | <!-- 90-day activity timeline --> |
| 63 | 63 | <div class="module glow-teal" style="margin-bottom:20px"> |
| 64 | 64 | <div class="module-head"><div class="left"> |
| 65 | 65 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 3v18h18"/><rect x="6" y="12" width="3" height="6"/><rect x="11" y="7" width="3" height="11"/><rect x="16" y="10" width="3" height="8"/></svg></div> |
| 66 | 66 | <div class="module-title">Activity, last 90 days</div> |
| 67 | 67 | <span class="module-subtitle">Every captured change, stacked by kind. Teal is files, amber is schema DDL. Hover for exact daily counts.</span> |
| 68 | 68 | </div></div> |
| 69 | 69 | <div class="module-body" style="padding-top:10px"> |
| 70 | 70 | $timeline_svg |
| 71 | 71 | </div> |
| 72 | 72 | </div> |
| 73 | 73 | |
| 74 | 74 | <!-- ============================ Per-site health ============================ --> |
| 75 | 75 | [if:$has_per_site] |
| 76 | 76 | <div class="module glow-emerald" style="margin-bottom:20px"> |
| 77 | 77 | <div class="module-head"><div class="left"> |
| 78 | 78 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="9"/><rect x="14" y="3" width="7" height="5"/><rect x="14" y="12" width="7" height="9"/><rect x="3" y="16" width="7" height="5"/></svg></div> |
| 79 | 79 | <div class="module-title">Per-site health</div> |
| 80 | 80 | <span class="module-subtitle">One row per active monitor. Sparkline is the last 30 days of change activity. Click a row to drill into that site's file changes.</span> |
| 81 | 81 | </div></div> |
| 82 | 82 | <div class="module-body tight"> |
| 83 | 83 | <table class="tbl"> |
| 84 | 84 | <thead><tr> |
| 85 | 85 | <th style="width:36%">Site / scan</th> |
| 86 | 86 | <th style="width:120px">30-day rhythm</th> |
| 87 | 87 | <th style="width:100px" class="mono">Active files</th> |
| 88 | 88 | <th style="width:100px" class="mono">Captures</th> |
| 89 | 89 | <th style="width:100px" class="mono">Last 24h</th> |
| 90 | 90 | <th style="width:170px">Last change</th> |
| 91 | 91 | </tr></thead> |
| 92 | 92 | <tbody> |
| 93 | 93 | [loop:@per_site] |
| 94 | 94 | <tr> |
| 95 | 95 | <td> |
| 96 | 96 | <a href="$drilldown_url" style="color:var(--accent-hi);text-decoration:none"> |
| 97 | 97 | <strong>$scan_name</strong> |
| 98 | 98 | </a> |
| 99 | 99 | <div class="mono dim" style="font-size:11px">$path_short <span class="pill $kind_pill" style="margin-left:6px;font-size:9.5px">$server_kind</span></div> |
| 100 | 100 | </td> |
| 101 | 101 | <td>$spark_svg</td> |
| 102 | 102 | <td class="mono">$active_files</td> |
| 103 | 103 | <td class="mono">$captured_ct</td> |
| 104 | 104 | <td class="mono" style="color:var(--accent-hi)">$changes_24h</td> |
| 105 | 105 | <td class="mono dim"><span class="ts" data-ts="$last_change_epoch" data-fmt="relative">$last_change_h</span></td> |
| 106 | 106 | </tr> |
| 107 | 107 | [/loop] |
| 108 | 108 | </tbody> |
| 109 | 109 | </table> |
| 110 | 110 | </div> |
| 111 | 111 | </div> |
| 112 | 112 | [/if] |
| 113 | 113 | |
| 114 | 114 | <!-- ============================ Change-frequency ranking ============================ --> |
| 115 | 115 | [if:$has_top_files] |
| 116 | 116 | <div class="dash-grid" style="grid-template-columns:2fr 1fr;margin-bottom:20px"> |
| 117 | 117 | <div class="module glow-amber"> |
| 118 | 118 | <div class="module-head"><div class="left"> |
| 119 | 119 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 17 9 11 13 15 21 7"/><polyline points="14 7 21 7 21 14"/></svg></div> |
| 120 | 120 | <div class="module-title">Change-frequency ranking</div> |
| 121 | 121 | <span class="module-subtitle">Top 20 files by change count in the last 30 days — the "live-config heatmap". Files that show up here are likely candidates for pinning to a Named Release.</span> |
| 122 | </div></div> | |
| 122 | </div> | |
| 123 | <a href="/pin_hotspots.cgi?n=20&days=30" class="tr-chip is-active" style="border:none;margin-left:auto">Pin these →</a> | |
| 124 | </div> | |
| 123 | 125 | <div class="module-body tight" style="max-height:520px;overflow:auto"> |
| 124 | 126 | <table class="tbl"> |
| 125 | 127 | <thead><tr> |
| 126 | 128 | <th style="width:60px">Rank</th> |
| 127 | 129 | <th>File</th> |
| 128 | 130 | <th style="width:120px">Site</th> |
| 129 | 131 | <th style="width:70px">Changes</th> |
| 130 | 132 | <th style="width:150px">Latest</th> |
| 131 | 133 | </tr></thead> |
| 132 | 134 | <tbody> |
| 133 | 135 | [loop:@top_files] |
| 134 | 136 | <tr> |
| 135 | 137 | <td class="mono" style="color:var(--accent-warn)"><strong>#</strong></td> |
| 136 | 138 | <td class="mono" style="font-size:11.5px"><a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$file_short</a></td> |
| 137 | 139 | <td class="dim" style="font-size:11.5px">$scan_name</td> |
| 138 | 140 | <td class="mono" style="color:var(--accent-warn);font-weight:700">$change_ct</td> |
| 139 | 141 | <td class="mono dim"><span class="ts" data-ts="$latest_epoch" data-fmt="relative">$latest_h</span></td> |
| 140 | 142 | </tr> |
| 141 | 143 | [/loop] |
| 142 | 144 | </tbody> |
| 143 | 145 | </table> |
| 144 | 146 | </div> |
| 145 | 147 | </div> |
| 146 | 148 | |
| 147 | 149 | <!-- ============================ Cross-site dedup ============================ --> |
| 148 | 150 | <div class="module glow-teal"> |
| 149 | 151 | <div class="module-head"><div class="left"> |
| 150 | 152 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3"/></svg></div> |
| 151 | 153 | <div class="module-title">Cross-site dedup</div> |
| 152 | 154 | <span class="module-subtitle">Byte-identical files that appear on multiple sites. BLOB_STORE already deduplicates — but seeing this list makes the shared files visible.</span> |
| 153 | 155 | </div></div> |
| 154 | 156 | <div class="module-body tight" style="max-height:520px;overflow:auto"> |
| 155 | 157 | [if:$has_shared_blobs] |
| 156 | 158 | <table class="tbl"> |
| 157 | 159 | <thead><tr><th style="width:60px">Sites</th><th>Blob</th><th style="width:70px">Size</th></tr></thead> |
| 158 | 160 | <tbody> |
| 159 | 161 | [loop:@shared_blobs] |
| 160 | 162 | <tr> |
| 161 | 163 | <td class="mono"><strong style="color:var(--accent-hi)">$site_ct</strong></td> |
| 162 | 164 | <td class="mono" style="font-size:11px"> |
| 163 | 165 | <a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$sha_short</a> |
| 164 | 166 | <div class="dim" style="font-size:10.5px;line-height:1.4">$scans_h</div> |
| 165 | 167 | </td> |
| 166 | 168 | <td class="mono dim">$size_h</td> |
| 167 | 169 | </tr> |
| 168 | 170 | [/loop] |
| 169 | 171 | </tbody> |
| 170 | 172 | </table> |
| 171 | 173 | [/if] |
| 172 | 174 | [if:!$has_shared_blobs] |
| 173 | 175 | <div style="padding:26px 14px;text-align:center;color:var(--text-dim);font-size:12.5px"> |
| 174 | 176 | Nothing shared across sites yet. |
| 175 | 177 | </div> |
| 176 | 178 | [/if] |
| 177 | 179 | </div> |
| 178 | 180 | </div> |
| 179 | 181 | </div> |
| 180 | 182 | [/if] |
| 181 | 183 | |
| 182 | 184 | <!-- Recent activity --> |
| 183 | 185 | <div class="module glow-teal" style="margin-bottom:20px"> |
| 184 | 186 | <div class="module-head"><div class="left"> |
| 185 | 187 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></div> |
| 186 | 188 | <div class="module-title">Recent activity</div> |
| 187 | 189 | <span class="module-subtitle">Newest first. Click any row to open its full diff. File + schema changes merged into one timeline.</span> |
| 188 | 190 | </div></div> |
| 189 | 191 | <div class="module-body tight"> |
| 190 | 192 | [if:$has_recent] |
| 191 | 193 | <table class="tbl"> |
| 192 | 194 | <thead><tr> |
| 193 | 195 | <th style="width:80px">Type</th> |
| 194 | 196 | <th>What</th> |
| 195 | 197 | <th>Detail</th> |
| 196 | 198 | <th style="width:170px">When</th> |
| 197 | 199 | </tr></thead> |
| 198 | 200 | <tbody> |
| 199 | 201 | [loop:@recent] |
| 200 | 202 | <tr> |
| 201 | 203 | <td><span class="pill $kind_pill">$kind</span></td> |
| 202 | 204 | <td class="mono" style="font-size:12.5px"><a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$what</a></td> |
| 203 | 205 | <td class="dim" style="font-size:12.5px">$detail</td> |
| 204 | 206 | <td class="mono dim"><span class="ts" data-ts="$ts_epoch" data-fmt="datetime">$ts</span></td> |
| 205 | 207 | </tr> |
| 206 | 208 | [/loop] |
| 207 | 209 | </tbody> |
| 208 | 210 | </table> |
| 209 | 211 | [/if] |
| 210 | 212 | [if:!$has_recent] |
| 211 | 213 | <div style="padding:36px 14px;text-align:center;color:var(--text-dim);font-size:13.5px"> |
| 212 | 214 | No activity captured yet. Start a file monitor or point at a database in the <a href="[url:file_monitors]" style="color:var(--accent-hi)">config</a> to begin capture. |
| 213 | 215 | </div> |
| 214 | 216 | [/if] |
| 215 | 217 | </div> |
| 216 | 218 | </div> |
| 217 | 219 | |
| 218 | 220 | <div class="dash-grid" style="grid-template-columns:2fr 1fr"> |
| 219 | 221 | <div class="module glow-emerald"> |
| 220 | 222 | <div class="module-head"><div class="left"> |
| 221 | 223 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M9 11l3 3L22 4"/><path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"/></svg></div> |
| 222 | 224 | <div class="module-title">Named releases</div> |
| 223 | 225 | <span class="module-subtitle">Recent bookmarks. Any file blob referenced from a named release is protected from auto-purge.</span> |
| 224 | 226 | </div></div> |
| 225 | 227 | <div class="module-body tight"> |
| 226 | 228 | [if:$has_releases] |
| 227 | 229 | <table class="tbl"> |
| 228 | 230 | <thead><tr><th>Name</th><th>By</th><th style="width:130px">When</th></tr></thead> |
| 229 | 231 | <tbody> |
| 230 | 232 | [loop:@releases] |
| 231 | 233 | <tr> |
| 232 | 234 | <td><strong>$name</strong><div class="dim" style="font-size:11.5px">$description</div></td> |
| 233 | 235 | <td class="dim">$released_by</td> |
| 234 | 236 | <td class="mono dim"><span class="ts" data-ts="$released_epoch" data-fmt="date">$released_h</span></td> |
| 235 | 237 | </tr> |
| 236 | 238 | [/loop] |
| 237 | 239 | </tbody> |
| 238 | 240 | </table> |
| 239 | 241 | [/if] |
| 240 | 242 | [if:!$has_releases] |
| 241 | 243 | <div style="padding:28px 14px;text-align:center;color:var(--text-dim);font-size:13.5px"> |
| 242 | 244 | No named releases yet. Bookmark a moment to protect it from auto-purge. |
| 243 | 245 | </div> |
| 244 | 246 | [/if] |
| 245 | 247 | </div> |
| 246 | 248 | </div> |
| 247 | 249 | |
| 248 | 250 | <div class="module glow-sky"> |
| 249 | 251 | <div class="module-head"><div class="left"> |
| 250 | 252 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="2" width="20" height="8" rx="2"/><rect x="2" y="14" width="20" height="8" rx="2"/></svg></div> |
| 251 | 253 | <div class="module-title">Servers</div> |
| 252 | 254 | <span class="module-subtitle">Central + agent nodes.</span> |
| 253 | 255 | </div></div> |
| 254 | 256 | <div class="module-body tight"> |
| 255 | 257 | <table class="tbl"> |
| 256 | 258 | <thead><tr><th>Name</th><th>Status</th><th class="dim" style="width:100px">Last seen</th></tr></thead> |
| 257 | 259 | <tbody> |
| 258 | 260 | [loop:@servers] |
| 259 | 261 | <tr> |
| 260 | 262 | <td><strong>$server_name</strong> <span class="dim mono" style="font-size:11px">$role</span></td> |
| 261 | 263 | <td><span class="pill $status_pill">$status</span></td> |
| 262 | 264 | <td class="mono dim"><span class="ts" data-ts="$heartbeat_epoch" data-fmt="relative">$last_heartbeat_h</span></td> |
| 263 | 265 | </tr> |
| 264 | 266 | [/loop] |
| 265 | 267 | </tbody> |
| 266 | 268 | </table> |
| 267 | 269 | </div> |
| 268 | 270 | </div> |
| 269 | 271 | </div> |