Diff -- /var/www/vhosts/3dshawn.com/site1/TEMPLATES/site.html
Diff
/var/www/vhosts/3dshawn.com/site1/TEMPLATES/site.html
modified on local at 2026-07-12 01:04:50
Added
+349
lines
Removed
-75
lines
Context
69
unchanged
Blobs
from 89bfad940ccd
to 1076cfffee64
to 1076cfffee64
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 | <span class="page-eyebrow"><span class="dot"></span> Site view</span> | |
| 2 | <a href="/sites.cgi" style="color:var(--accent-hi);text-decoration:none;font-size:12px">← All sites</a> | |
| 3 | <span class="page-eyebrow" style="margin-top:8px"><span class="dot"></span> Site view</span> | |
| 3 | 4 | <h1 class="page-title">$scan_name</h1> |
| 4 | 5 | <p class="page-subtitle"> |
| 5 | 6 | <code class="mono dim">$scan_path</code> |
| 6 | 7 | · on <strong>$server_name</strong> <span class="dim">($server_kind)</span> |
| 7 | 8 | · retention: <strong>$retention_h</strong> |
| 8 | 9 | </p> |
| 9 | 10 | </div> |
| 10 | 11 | |
| 11 | 12 | [if:$has_error] |
| 12 | 13 | <div class="module glow-rose"><div class="module-body">$error_msg</div></div> |
| 13 | 14 | [/if] |
| 14 | 15 | |
| 15 | 16 | [if:!$has_error] |
| 17 | [if:$saved_id] | |
| 18 | <div class="banner banner-ok" style="margin:0 0 16px;padding:10px 14px;border-radius:10px;background:rgba(52,211,153,.10);border:1px solid rgba(52,211,153,.35);color:#a7f3d0;font-size:13px"> | |
| 19 | Snapshot saved as named release #$saved_id. Visible in <a href="/named_releases.cgi" style="color:#a7f3d0;font-weight:700">Named releases</a> and in this site's Releases panel below. | |
| 20 | </div> | |
| 21 | [/if] | |
| 22 | ||
| 16 | 23 | <div class="ds-guide"> |
| 17 | 24 | <div class="dsg-icon">i</div> |
| 18 | 25 | <div> |
| 19 | <span class="dsg-title">Everything for this site, one screen.</span> | |
| 20 | Filtered KPIs, 90-day rhythm, recent activity, hotspots to consider pinning, and the named releases scoped here. Use the quick-action chips to jump to <a href="$changes_url">full file changes</a>, <a href="$pin_url">bulk-pin hotspots</a>, or <a href="$export_url">CSV export</a> for this site alone. | |
| 26 | <span class="dsg-title">The deep dive.</span> | |
| 27 | Every stat we have on this monitor. Configuration + storage math + activity breakdown + hotspots + drift + restores + cross-site dedup + compile results. Use quick actions to jump to | |
| 28 | <a href="$changes_url">full file changes</a>, | |
| 29 | <a href="$pin_url">pin hotspots</a>, or | |
| 30 | <a href="$export_url">CSV export</a> for this site alone. | |
| 21 | 31 | </div> |
| 22 | 32 | </div> |
| 23 | 33 | |
| 24 | <!-- KPIs --> | |
| 25 | <div class="dash-grid" style="grid-template-columns:repeat(4,1fr);margin-bottom:16px"> | |
| 34 | <!-- ============ HERO KPIs ============ --> | |
| 35 | <div class="dash-grid" style="grid-template-columns:repeat(5,1fr);margin-bottom:16px"> | |
| 26 | 36 | <div class="module glow-teal"> |
| 27 | 37 | <div class="module-head"><div class="left"><div class="module-title">Last 24h</div></div></div> |
| 28 | <div class="module-body kpi kpi-teal"><div class="num">$kpi_24h</div><div class="lbl">changes captured</div></div> | |
| 38 | <div class="module-body kpi kpi-teal"> | |
| 39 | <div class="num">$kpi_24h<span class="ds-trend ds-trend-$trend_class">$trend_txt</span></div> | |
| 40 | <div class="lbl">changes captured</div> | |
| 41 | <div class="sub">prior 24h: $kpi_24h_prev</div> | |
| 42 | </div> | |
| 29 | 43 | </div> |
| 30 | 44 | <div class="module glow-emerald"> |
| 31 | 45 | <div class="module-head"><div class="left"><div class="module-title">Last 7 days</div></div></div> |
| 32 | <div class="module-body kpi kpi-emerald"><div class="num">$kpi_7d</div><div class="lbl">changes captured</div></div> | |
| 46 | <div class="module-body kpi kpi-emerald"><div class="num">$kpi_7d</div><div class="lbl">changes</div><div class="sub">30d: $kpi_30d</div></div> | |
| 33 | 47 | </div> |
| 34 | 48 | <div class="module glow-sky"> |
| 35 | 49 | <div class="module-head"><div class="left"><div class="module-title">Active files</div></div></div> |
| 36 | <div class="module-body kpi kpi-sky"><div class="num">$kpi_active</div><div class="lbl">distinct files, not deleted</div></div> | |
| 50 | <div class="module-body kpi kpi-sky"><div class="num">$kpi_active</div><div class="lbl">not deleted</div><div class="sub">all ever seen: $kpi_all_files</div></div> | |
| 37 | 51 | </div> |
| 38 | 52 | <div class="module glow-amber"> |
| 39 | <div class="module-head"><div class="left"><div class="module-title">Lifetime</div></div></div> | |
| 40 | <div class="module-body kpi kpi-amber"><div class="num">$kpi_all</div><div class="lbl">total captures ever</div></div> | |
| 53 | <div class="module-head"><div class="left"><div class="module-title">Storage</div></div></div> | |
| 54 | <div class="module-body kpi kpi-amber"><div class="num">$bytes_gz_h</div><div class="lbl">on disk (gzipped)</div><div class="sub">$dedup_ratio dedup / $savings_pct saved</div></div> | |
| 55 | </div> | |
| 56 | <div class="module glow-rose"> | |
| 57 | <div class="module-head"><div class="left"><div class="module-title">Lifetime captures</div></div></div> | |
| 58 | <div class="module-body kpi kpi-rose"><div class="num">$kpi_lifetime</div><div class="lbl">total rows</div><div class="sub">since $first_captured</div></div> | |
| 41 | 59 | </div> |
| 42 | 60 | </div> |
| 43 | 61 | |
| 44 | <!-- 90-day timeline --> | |
| 62 | <!-- ============ 90-DAY TIMELINE ============ --> | |
| 45 | 63 | <div class="module glow-teal" style="margin-bottom:16px"> |
| 46 | 64 | <div class="module-head"><div class="left"> |
| 47 | <div class="module-title">Activity, last 90 days<span class="ds-help" data-help-title="This site only" data-help-body="Just this monitor's captures — unlike the main dashboard which stacks the whole portfolio."></span></div> | |
| 65 | <div class="module-title">Activity, last 90 days<span class="ds-help" data-help-title="This monitor only" data-help-body="Just this site's captures — the main dashboard timeline stacks the whole portfolio."></span></div> | |
| 48 | 66 | <span class="module-subtitle">Click any day to filter file changes to that date.</span> |
| 67 | </div></div> | |
| 68 | <div class="module-body">$timeline_svg</div> | |
| 69 | </div> | |
| 70 | ||
| 71 | <!-- ============ CONFIGURATION + SERVER + STATUS ============ --> | |
| 72 | <div class="dash-grid" style="grid-template-columns:1fr 1fr;margin-bottom:16px"> | |
| 73 | <div class="module glow-sky"> | |
| 74 | <div class="module-head"><div class="left"><div class="module-title">Configuration<span class="ds-help" data-help-title="Scan behavior" data-help-body="Ignore list is UNION'd with the global settings. File-type filter here overrides the global if set. Max size + retention likewise fall back to global defaults when unset."></span></div></div></div> | |
| 75 | <div class="module-body"> | |
| 76 | <table class="tbl"> | |
| 77 | <tbody> | |
| 78 | <tr><td style="width:170px"><strong>Path watched</strong></td><td class="mono">$scan_path</td></tr> | |
| 79 | <tr><td><strong>Ignore list</strong></td><td class="mono dim" style="font-size:11px">$ignore_list</td></tr> | |
| 80 | <tr><td><strong>File-type filter</strong></td><td class="mono dim">$file_type_filter</td></tr> | |
| 81 | <tr><td><strong>Max file size</strong></td><td class="mono">$max_file_size_h</td></tr> | |
| 82 | <tr><td><strong>Retention</strong></td><td class="mono">$retention_h</td></tr> | |
| 83 | <tr><td><strong>Last scan tick</strong></td><td class="mono dim"><span class="ts" data-ts="$last_scanned_epoch" data-fmt="relative">$last_scanned_h</span></td></tr> | |
| 84 | </tbody> | |
| 85 | </table> | |
| 86 | </div> | |
| 87 | </div> | |
| 88 | <div class="module glow-emerald"> | |
| 89 | <div class="module-head"><div class="left"><div class="module-title">Server / reach</div></div></div> | |
| 90 | <div class="module-body"> | |
| 91 | <table class="tbl"> | |
| 92 | <tbody> | |
| 93 | <tr><td style="width:170px"><strong>Server name</strong></td><td>$server_name</td></tr> | |
| 94 | <tr><td><strong>Kind</strong></td><td>$server_kind</td></tr> | |
| 95 | <tr><td><strong>Status</strong></td><td>$server_status</td></tr> | |
| 96 | [if:$is_agent] | |
| 97 | <tr><td><strong>SSH reach</strong></td><td class="mono">$ssh_user@$ssh_host:$ssh_port</td></tr> | |
| 98 | [/if] | |
| 99 | <tr><td><strong>Last heartbeat</strong></td><td class="mono dim"><span class="ts" data-ts="$heartbeat_epoch" data-fmt="relative">$heartbeat_h</span></td></tr> | |
| 100 | <tr><td><strong>First capture</strong></td><td class="mono dim">$first_captured</td></tr> | |
| 101 | <tr><td><strong>Last capture</strong></td><td class="mono dim"><span class="ts" data-ts="$last_captured_epoch" data-fmt="relative">$last_captured</span></td></tr> | |
| 102 | </tbody> | |
| 103 | </table> | |
| 104 | </div> | |
| 105 | </div> | |
| 106 | </div> | |
| 107 | ||
| 108 | <!-- ============ ACTIVITY BREAKDOWN + STORAGE MATH ============ --> | |
| 109 | <div class="dash-grid" style="grid-template-columns:1fr 1fr;margin-bottom:16px"> | |
| 110 | <div class="module glow-amber"> | |
| 111 | <div class="module-head"><div class="left"><div class="module-title">Activity breakdown<span class="ds-help" data-help-title="Change kinds" data-help-body="Every FILE_CHANGES row is one of these. <strong>Added</strong> = file first seen. <strong>Modified</strong> = SHA changed. <strong>Deleted</strong> = file no longer present. <strong>ts-only</strong> = mtime touched but bytes identical -- usually noise."></span></div></div></div> | |
| 112 | <div class="module-body"> | |
| 113 | <table class="tbl"> | |
| 114 | <tbody> | |
| 115 | <tr><td><strong>Added</strong></td><td class="mono" style="color:var(--accent-ok)">$n_added</td></tr> | |
| 116 | <tr><td><strong>Modified</strong></td><td class="mono" style="color:var(--accent-warn)">$n_modified</td></tr> | |
| 117 | <tr><td><strong>Deleted</strong></td><td class="mono" style="color:var(--accent-danger)">$n_deleted</td></tr> | |
| 118 | <tr><td><strong>Timestamp-only</strong></td><td class="mono dim">$n_ts_only</td></tr> | |
| 119 | <tr><td><strong>Total lifetime</strong></td><td class="mono"><strong>$kpi_lifetime</strong></td></tr> | |
| 120 | </tbody> | |
| 121 | </table> | |
| 122 | </div> | |
| 123 | </div> | |
| 124 | <div class="module glow-sky"> | |
| 125 | <div class="module-head"><div class="left"><div class="module-title">Storage math<span class="ds-help" data-help-title="How storage works" data-help-body="Content is SHA-256 addressed and gzipped. If 100 captures of the same file share identical content, they share one BLOB_STORE row plus a ref-count. This is why the raw-vs-on-disk ratio is usually 3-10x."></span></div></div></div> | |
| 126 | <div class="module-body"> | |
| 127 | <table class="tbl"> | |
| 128 | <tbody> | |
| 129 | <tr><td><strong>Unique blobs</strong></td><td class="mono">$unique_blobs</td></tr> | |
| 130 | <tr><td><strong>Total refs</strong></td><td class="mono">$ref_total</td></tr> | |
| 131 | <tr><td><strong>Raw content (all versions)</strong></td><td class="mono">$bytes_raw_h</td></tr> | |
| 132 | <tr><td><strong>On disk (gzipped)</strong></td><td class="mono" style="color:var(--accent-hi)">$bytes_gz_h</td></tr> | |
| 133 | <tr><td><strong>Dedup ratio</strong></td><td class="mono" style="color:var(--accent-ok)">$dedup_ratio</td></tr> | |
| 134 | <tr><td><strong>Savings</strong></td><td class="mono" style="color:var(--accent-ok)">$savings_pct</td></tr> | |
| 135 | </tbody> | |
| 136 | </table> | |
| 137 | </div> | |
| 138 | </div> | |
| 139 | </div> | |
| 140 | ||
| 141 | <!-- ============ QUICK SAVE VERSION ============ --> | |
| 142 | <div class="module glow-emerald" style="margin-bottom:16px"> | |
| 143 | <div class="module-head"><div class="left"> | |
| 144 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"/><polyline points="17 21 17 13 7 13 7 21"/><polyline points="7 3 7 8 15 8"/></svg></div> | |
| 145 | <div class="module-title">Save current state as a version<span class="ds-help" data-help-title="What this does" data-help-body="Creates a new Named Release scoped to this site AND explicitly pins every current-latest file. Auto-purge will keep those exact blobs forever. Great for "shipped v3.0" snapshots."></span></div> | |
| 146 | <span class="module-subtitle">One-click bookmark of every current-latest file on this site.</span> | |
| 49 | 147 | </div></div> |
| 50 | 148 | <div class="module-body"> |
| 51 | $timeline_svg | |
| 149 | <form method="post" action="/site.cgi?mid=$mid" style="display:flex;gap:10px;align-items:end;flex-wrap:wrap"> | |
| 150 | <input type="hidden" name="save_snapshot" value="1"> | |
| 151 | <label style="flex:1;min-width:180px;display:flex;flex-direction:column;gap:4px"> | |
| 152 | <span class="rb-label">Version label</span> | |
| 153 | <input type="text" name="version_label" required placeholder="e.g. v1.0, stable Nov-2026" | |
| 154 | style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12.5px"> | |
| 155 | </label> | |
| 156 | <label style="width:160px;display:flex;flex-direction:column;gap:4px"> | |
| 157 | <span class="rb-label">Internal name</span> | |
| 158 | <input type="text" name="name" placeholder="auto" | |
| 159 | style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:var(--mono);font-size:12.5px"> | |
| 160 | </label> | |
| 161 | <label style="width:120px;display:flex;flex-direction:column;gap:4px"> | |
| 162 | <span class="rb-label">Tier</span> | |
| 163 | <select name="tier" style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-size:12.5px"> | |
| 164 | <option value="draft">Draft</option> | |
| 165 | <option value="working">Working</option> | |
| 166 | <option value="stable">Stable</option> | |
| 167 | </select> | |
| 168 | </label> | |
| 169 | <button type="submit" class="tr-chip is-active" style="border:none;padding:8px 18px">Save snapshot</button> | |
| 170 | </form> | |
| 52 | 171 | </div> |
| 53 | 172 | </div> |
| 54 | 173 | |
| 55 | <div class="dash-grid" style="grid-template-columns:2fr 1fr;margin-bottom:16px"> | |
| 56 | <!-- Recent activity --> | |
| 174 | <!-- ============ RECENT + HOTSPOTS ============ --> | |
| 175 | <div class="dash-grid" style="grid-template-columns:3fr 2fr;margin-bottom:16px"> | |
| 57 | 176 | <div class="module glow-teal"> |
| 58 | 177 | <div class="module-head"><div class="left"> |
| 59 | 178 | <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> |
| 60 | <div class="module-title">Recent changes<span class="ds-help" data-help-title="Programmer view" data-help-body="Made an edit that got overwritten? Find it here, click <strong>Restore</strong> to write it back — or open the diff, copy the exact lines you need, and paste them into the current version manually. Every restore backs up the current file first."></span></div> | |
| 61 | <span class="module-subtitle">Last 40 captures on this monitor. Click a row to open the diff. "Restore" writes the captured version back to disk.</span> | |
| 62 | </div> | |
| 63 | <a href="$changes_url" class="tr-chip" style="margin-left:auto">See all →</a> | |
| 64 | </div> | |
| 65 | <div class="module-body tight" style="max-height:640px;overflow:auto"> | |
| 179 | <div class="module-title">Recent changes<span class="ds-help" data-help-title="Programmer story" data-help-body="Made an edit that got overwritten? Find it here, click <strong>Restore</strong> to write it back — or open the diff, copy the exact lines you need."></span></div> | |
| 180 | <span class="module-subtitle">Last 25 captures. Click a row to open its diff.</span> | |
| 181 | </div><a href="$changes_url" class="tr-chip" style="margin-left:auto">See all →</a></div> | |
| 182 | <div class="module-body tight" style="max-height:520px;overflow:auto"> | |
| 66 | 183 | [if:$has_recent] |
| 67 | 184 | <table class="tbl"> |
| 68 | <thead><tr> | |
| 69 | <th style="width:90px">Status</th> | |
| 70 | <th>File</th> | |
| 71 | <th style="width:80px">Blob</th> | |
| 72 | <th style="width:150px">When</th> | |
| 73 | <th style="width:70px">Restore</th> | |
| 74 | </tr></thead> | |
| 185 | <thead><tr><th style="width:90px">Status</th><th>File</th><th style="width:90px">Blob</th><th style="width:150px">When</th><th style="width:70px">Restore</th></tr></thead> | |
| 75 | 186 | <tbody> |
| 76 | 187 | [loop:@recent] |
| 77 | 188 | <tr> |
| 78 | 189 | <td><span class="pill $status_pill">$status</span>[if:$is_ts_only] <span class="pill pill-mute" style="font-size:9px">ts</span>[/if]</td> |
| 79 | 190 | <td class="mono" style="font-size:11.5px"><a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$file_short</a></td> |
| 80 | 191 | <td class="mono dim">$blob_short</td> |
| 81 | 192 | <td class="mono dim"><span class="ts" data-ts="$ts_epoch" data-fmt="relative">$date_time</span></td> |
| 82 | 193 | <td>[if:$can_restore]<a href="$restore_url" class="tr-chip" style="padding:2px 8px;font-size:10.5px">Restore</a>[/if]</td> |
| 83 | 194 | </tr> |
| 84 | 195 | [/loop] |
| 85 | 196 | </tbody> |
| 86 | 197 | </table> |
| 87 | 198 | [/if] |
| 88 | [if:!$has_recent]<div style="padding:36px 14px;text-align:center;color:var(--text-dim)">Nothing captured yet.</div>[/if] | |
| 89 | 199 | </div> |
| 90 | 200 | </div> |
| 91 | 201 | |
| 92 | <!-- Hotspots + releases --> | |
| 93 | <div> | |
| 94 | <div class="module glow-amber" style="margin-bottom:16px"> | |
| 95 | <div class="module-head"><div class="left"> | |
| 96 | <div class="module-title">Hotspots (30d)</div> | |
| 97 | <span class="module-subtitle">Files edited most often on this site. Pin them to freeze current state.</span> | |
| 98 | </div> | |
| 99 | <a href="$pin_url" class="tr-chip" style="margin-left:auto">Pin these →</a> | |
| 100 | </div> | |
| 101 | <div class="module-body tight"> | |
| 102 | [if:$has_hotspots] | |
| 103 | <table class="tbl"> | |
| 104 | <thead><tr><th>File</th><th style="width:60px">Ct</th></tr></thead> | |
| 105 | <tbody> | |
| 106 | [loop:@hotspots] | |
| 107 | <tr> | |
| 108 | <td class="mono" style="font-size:11.5px"><a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$file_short</a></td> | |
| 109 | <td class="mono" style="color:var(--accent-warn);font-weight:700">$ct</td> | |
| 110 | </tr> | |
| 111 | [/loop] | |
| 112 | </tbody> | |
| 113 | </table> | |
| 114 | [/if] | |
| 115 | [if:!$has_hotspots]<div style="padding:24px 14px;text-align:center;color:var(--text-dim);font-size:12.5px">No activity in the last 30 days.</div>[/if] | |
| 116 | </div> | |
| 202 | <div class="module glow-amber"> | |
| 203 | <div class="module-head"><div class="left"> | |
| 204 | <div class="module-title">Hotspots (30d)</div> | |
| 205 | <span class="module-subtitle">Top-10 most edited on this site.</span> | |
| 206 | </div> | |
| 207 | <a href="$pin_url" class="tr-chip" style="margin-left:auto">Pin these →</a></div> | |
| 208 | <div class="module-body tight" style="max-height:520px;overflow:auto"> | |
| 209 | [if:$has_hotspots] | |
| 210 | <table class="tbl"> | |
| 211 | <thead><tr><th>File</th><th style="width:60px">Ct</th><th style="width:120px">Latest</th></tr></thead> | |
| 212 | <tbody> | |
| 213 | [loop:@hotspots] | |
| 214 | <tr> | |
| 215 | <td class="mono" style="font-size:11.5px"><a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$file_short</a></td> | |
| 216 | <td class="mono" style="color:var(--accent-warn);font-weight:700">$ct</td> | |
| 217 | <td class="mono dim"><span class="ts" data-ts="$latest_epoch" data-fmt="relative">-</span></td> | |
| 218 | </tr> | |
| 219 | [/loop] | |
| 220 | </tbody> | |
| 221 | </table> | |
| 222 | [/if] | |
| 117 | 223 | </div> |
| 224 | </div> | |
| 225 | </div> | |
| 118 | 226 | |
| 119 | <div class="module glow-emerald"> | |
| 120 | <div class="module-head"><div class="left"> | |
| 121 | <div class="module-title">Releases & stable versions<span class="ds-help" data-help-title="Versions for this site" data-help-body="Portfolio-wide releases + releases scoped to this site or its server. Stable-tier releases are highlighted in green. Click <strong>Restore</strong> to roll every pinned file in that release back to the pinned state."></span></div> | |
| 122 | <span class="module-subtitle">Save a working / stable version below; roll back with one click.</span> | |
| 123 | </div></div> | |
| 124 | <div class="module-body tight"> | |
| 125 | [if:$has_releases] | |
| 126 | <table class="tbl"> | |
| 127 | <thead><tr><th>Version</th><th style="width:70px">Tier</th><th style="width:70px"></th></tr></thead> | |
| 128 | <tbody> | |
| 129 | [loop:@releases] | |
| 130 | <tr> | |
| 131 | <td><strong>$label</strong><div class="dim" style="font-size:11px">$description</div></td> | |
| 132 | <td><span class="pill $tier_pill" style="font-size:9.5px">$tier</span></td> | |
| 133 | <td><a href="$restore_url" class="tr-chip" style="padding:2px 8px;font-size:10.5px">Restore</a></td> | |
| 134 | </tr> | |
| 135 | [/loop] | |
| 136 | </tbody> | |
| 137 | </table> | |
| 227 | <!-- ============ RELEASES + DELETIONS ============ --> | |
| 228 | <div class="dash-grid" style="grid-template-columns:1fr 1fr;margin-bottom:16px"> | |
| 229 | <div class="module glow-emerald"> | |
| 230 | <div class="module-head"><div class="left"> | |
| 231 | <div class="module-title">Releases & stable versions<span class="ds-help" data-help-title="Scoped + portfolio" data-help-body="Releases scoped to this monitor, its parent server, or portfolio-wide. Stable-tier releases are highlighted."></span></div> | |
| 232 | <span class="module-subtitle">One-click roll-back.</span> | |
| 233 | </div> | |
| 234 | <a href="/named_releases.cgi" class="tr-chip" style="margin-left:auto">Manage →</a></div> | |
| 235 | <div class="module-body tight" style="max-height:400px;overflow:auto"> | |
| 236 | [if:$has_releases] | |
| 237 | <table class="tbl"> | |
| 238 | <thead><tr><th>Version</th><th style="width:70px">Tier</th><th style="width:60px">Pins</th><th style="width:70px"></th></tr></thead> | |
| 239 | <tbody> | |
| 240 | [loop:@releases] | |
| 241 | <tr> | |
| 242 | <td><strong>$label</strong><div class="dim" style="font-size:11px">$description</div></td> | |
| 243 | <td><span class="pill $tier_pill" style="font-size:9.5px">$tier</span></td> | |
| 244 | <td class="mono">$pin_ct</td> | |
| 245 | <td><a href="$restore_url" class="tr-chip" style="padding:2px 8px;font-size:10.5px">Restore</a></td> | |
| 246 | </tr> | |
| 247 | [/loop] | |
| 248 | </tbody> | |
| 249 | </table> | |
| 250 | [/if] | |
| 251 | [if:!$has_releases]<div style="padding:20px 14px;text-align:center;color:var(--text-dim);font-size:12px">No releases yet. Save one using the form above.</div>[/if] | |
| 252 | </div> | |
| 253 | </div> | |
| 254 | ||
| 255 | <div class="module glow-rose"> | |
| 256 | <div class="module-head"><div class="left"> | |
| 257 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/></svg></div> | |
| 258 | <div class="module-title">Deletion log<span class="ds-help" data-help-title="Something got deleted?" data-help-body="Every file this monitor saw disappear. Click <strong>Restore</strong> to write the last captured content back to disk."></span></div> | |
| 259 | <span class="module-subtitle">Last 10 deletions -- restore the last-known content in one click.</span> | |
| 260 | </div></div> | |
| 261 | <div class="module-body tight" style="max-height:400px;overflow:auto"> | |
| 262 | [if:$has_deletions] | |
| 263 | <table class="tbl"> | |
| 264 | <thead><tr><th>File</th><th style="width:150px">Deleted</th><th style="width:70px"></th></tr></thead> | |
| 265 | <tbody> | |
| 266 | [loop:@deletions] | |
| 267 | <tr> | |
| 268 | <td class="mono" style="font-size:11.5px"><a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$file_short</a></td> | |
| 269 | <td class="mono dim"><span class="ts" data-ts="$ts_epoch" data-fmt="relative">$date_time</span></td> | |
| 270 | <td>[if:$can_restore]<a href="$restore_url" class="tr-chip" style="padding:2px 8px;font-size:10.5px">Restore</a>[/if]</td> | |
| 271 | </tr> | |
| 272 | [/loop] | |
| 273 | </tbody> | |
| 274 | </table> | |
| 275 | [/if] | |
| 276 | [if:!$has_deletions]<div style="padding:20px 14px;text-align:center;color:var(--text-dim);font-size:12px">Nothing deleted here. Good.</div>[/if] | |
| 277 | </div> | |
| 278 | </div> | |
| 279 | </div> | |
| 280 | ||
| 281 | <!-- ============ COMPILE + DRIFT ============ --> | |
| 282 | <div class="dash-grid" style="grid-template-columns:1fr 1fr;margin-bottom:16px"> | |
| 283 | <div class="module glow-warn"> | |
| 284 | <div class="module-head"><div class="left"> | |
| 285 | <div class="module-title">Compile-check summary<span class="ds-help" data-help-title="How compile-check works" data-help-body="Runs when you press <strong>Test compile</strong> on the diff viewer. Perl / node / bash / python / JSON. Results cached on BLOB_STORE so we don't re-check the same blob."></span></div> | |
| 286 | <span class="module-subtitle">Blobs on this site where we've run a syntax check.</span> | |
| 287 | </div></div> | |
| 288 | <div class="module-body"> | |
| 289 | [if:$has_compile_data] | |
| 290 | <div style="display:flex;gap:16px;margin-bottom:10px"> | |
| 291 | <div><div style="font-size:22px;color:var(--accent-ok);font-weight:800">$cc_ok</div><div class="dim" style="font-size:10.5px;text-transform:uppercase;letter-spacing:1.2px">Clean</div></div> | |
| 292 | <div><div style="font-size:22px;color:var(--accent-danger);font-weight:800">$cc_err</div><div class="dim" style="font-size:10.5px;text-transform:uppercase;letter-spacing:1.2px">Errors</div></div> | |
| 293 | <div><div style="font-size:22px;color:var(--text-dim);font-weight:800">$cc_checked</div><div class="dim" style="font-size:10.5px;text-transform:uppercase;letter-spacing:1.2px">Total</div></div> | |
| 294 | </div> | |
| 295 | [if:$has_compile_errors] | |
| 296 | <div class="dim" style="text-transform:uppercase;letter-spacing:1.2px;font-size:10.5px;margin-bottom:6px;color:var(--accent-danger)">Files with syntax errors</div> | |
| 297 | <div style="max-height:220px;overflow:auto"> | |
| 298 | <table class="tbl"> | |
| 299 | <tbody> | |
| 300 | [loop:@compile_errors] | |
| 301 | <tr> | |
| 302 | <td class="mono" style="font-size:11px"><a href="$diff_url" style="color:var(--accent-danger-hi);text-decoration:none">$file_short</a> | |
| 303 | <div class="dim" style="font-size:10.5px;font-family:var(--mono)">$msg</div> | |
| 304 | </td> | |
| 305 | </tr> | |
| 306 | [/loop] | |
| 307 | </tbody> | |
| 308 | </table> | |
| 309 | </div> | |
| 138 | 310 | [/if] |
| 139 | [if:!$has_releases]<div style="padding:20px 14px;text-align:center;color:var(--text-dim);font-size:12px">No releases yet. <a href="/named_releases.cgi" style="color:var(--accent-hi)">Save one now</a>.</div>[/if] | |
| 140 | </div> | |
| 311 | [/if] | |
| 312 | [if:!$has_compile_data]<div class="dim" style="padding:14px 4px;font-size:12.5px">No compile checks run for this site yet. Open a diff and press <strong>Test compile</strong> to check any Perl / JS / Python / Bash file.</div>[/if] | |
| 313 | </div> | |
| 314 | </div> | |
| 315 | ||
| 316 | <div class="module glow-rose"> | |
| 317 | <div class="module-head"><div class="left"> | |
| 318 | <div class="module-title">Pin drift on this site<span class="ds-help" data-help-title="What drift means" data-help-body="A file was pinned in a Named Release. Someone (or a scanner) modified it, so the current SHA no longer matches the pinned SHA. Click Fix to restore the release to the pinned state."></span></div> | |
| 319 | <span class="module-subtitle">Pinned files here that no longer match their pinned SHA.</span> | |
| 320 | </div></div> | |
| 321 | <div class="module-body tight" style="max-height:320px;overflow:auto"> | |
| 322 | [if:$has_drift] | |
| 323 | <table class="tbl"> | |
| 324 | <thead><tr><th>File</th><th style="width:150px">Release</th><th style="width:150px">Detected</th><th style="width:60px"></th></tr></thead> | |
| 325 | <tbody> | |
| 326 | [loop:@drift] | |
| 327 | <tr> | |
| 328 | <td class="mono" style="font-size:11px">$file_short<div class="dim mono" style="font-size:10px">$pinned_short → $current_short</div></td> | |
| 329 | <td class="dim">$release_name</td> | |
| 330 | <td class="mono dim"><span class="ts" data-ts="$detected_epoch" data-fmt="relative">$detected_h</span></td> | |
| 331 | <td><a href="$restore_url" class="tr-chip" style="padding:2px 8px;font-size:10.5px">Fix</a></td> | |
| 332 | </tr> | |
| 333 | [/loop] | |
| 334 | </tbody> | |
| 335 | </table> | |
| 336 | [/if] | |
| 337 | [if:!$has_drift]<div class="dim" style="padding:14px 4px;font-size:12.5px">No pinned files are drifting. All pins are in-sync.</div>[/if] | |
| 338 | </div> | |
| 339 | </div> | |
| 340 | </div> | |
| 341 | ||
| 342 | <!-- ============ CROSS-SITE + LONGEVITY + RESTORES ============ --> | |
| 343 | <div class="dash-grid" style="grid-template-columns:1fr 1fr 1fr;margin-bottom:16px"> | |
| 344 | <div class="module glow-teal"> | |
| 345 | <div class="module-head"><div class="left"> | |
| 346 | <div class="module-title">Shared with other sites<span class="ds-help" data-help-title="Cross-site dedup" data-help-body="Blobs from this site's captures that are byte-identical to captures on other sites. Great for spotting shared templates or copy-paste code. Click a blob to sync it across sites."></span></div> | |
| 347 | <span class="module-subtitle">Byte-identical content this site shares.</span> | |
| 348 | </div></div> | |
| 349 | <div class="module-body tight" style="max-height:400px;overflow:auto"> | |
| 350 | [if:$has_shared] | |
| 351 | <table class="tbl"> | |
| 352 | <thead><tr><th style="width:60px">Sites</th><th>Blob</th><th style="width:70px">Size</th></tr></thead> | |
| 353 | <tbody> | |
| 354 | [loop:@shared_blobs] | |
| 355 | <tr> | |
| 356 | <td class="mono" style="color:var(--accent-hi);font-weight:700">$site_ct</td> | |
| 357 | <td class="mono" style="font-size:11px"><a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$sha_short</a> | |
| 358 | <div class="dim" style="font-size:10.5px">$scans_h</div> | |
| 359 | </td> | |
| 360 | <td class="mono dim">$size_h</td> | |
| 361 | </tr> | |
| 362 | [/loop] | |
| 363 | </tbody> | |
| 364 | </table> | |
| 365 | [/if] | |
| 366 | [if:!$has_shared]<div class="dim" style="padding:14px 4px;font-size:12.5px">No byte-identical files with other monitors.</div>[/if] | |
| 367 | </div> | |
| 368 | </div> | |
| 369 | ||
| 370 | <div class="module glow-sky"> | |
| 371 | <div class="module-head"><div class="left"> | |
| 372 | <div class="module-title">Longest-lived files</div> | |
| 373 | <span class="module-subtitle">Files this monitor has watched the longest.</span> | |
| 374 | </div></div> | |
| 375 | <div class="module-body tight" style="max-height:400px;overflow:auto"> | |
| 376 | [if:$has_longevity] | |
| 377 | <table class="tbl"> | |
| 378 | <thead><tr><th>File</th><th style="width:60px">Days</th><th style="width:60px">Ct</th></tr></thead> | |
| 379 | <tbody> | |
| 380 | [loop:@longevity] | |
| 381 | <tr> | |
| 382 | <td class="mono" style="font-size:11.5px"><a href="$diff_url" style="color:var(--accent-hi);text-decoration:none">$file_short</a></td> | |
| 383 | <td class="mono">$days_tracked</td> | |
| 384 | <td class="mono">$ct</td> | |
| 385 | </tr> | |
| 386 | [/loop] | |
| 387 | </tbody> | |
| 388 | </table> | |
| 389 | [/if] | |
| 390 | [if:!$has_longevity]<div class="dim" style="padding:14px 4px;font-size:12.5px">Nothing tracked yet.</div>[/if] | |
| 391 | </div> | |
| 392 | </div> | |
| 393 | ||
| 394 | <div class="module glow-amber"> | |
| 395 | <div class="module-head"><div class="left"> | |
| 396 | <div class="module-title">Restore log for this site</div> | |
| 397 | <span class="module-subtitle">Recent restore actions that touched this monitor's path.</span> | |
| 398 | </div></div> | |
| 399 | <div class="module-body tight" style="max-height:400px;overflow:auto"> | |
| 400 | [if:$has_restores] | |
| 401 | <table class="tbl"> | |
| 402 | <thead><tr><th style="width:80px">Result</th><th>File</th><th style="width:120px">When</th></tr></thead> | |
| 403 | <tbody> | |
| 404 | [loop:@restores] | |
| 405 | <tr> | |
| 406 | <td><span class="pill $status_pill">$status</span></td> | |
| 407 | <td class="mono" style="font-size:11px">$file_short<div class="dim" style="font-size:10px">by $restored_by · $sha_short</div></td> | |
| 408 | <td class="mono dim"><span class="ts" data-ts="$restored_epoch" data-fmt="relative">$restored_h</span></td> | |
| 409 | </tr> | |
| 410 | [/loop] | |
| 411 | </tbody> | |
| 412 | </table> | |
| 413 | [/if] | |
| 414 | [if:!$has_restores]<div class="dim" style="padding:14px 4px;font-size:12.5px">No restore actions on this site's path yet.</div>[/if] | |
| 141 | 415 | </div> |
| 142 | 416 | </div> |
| 143 | 417 | </div> |
| 144 | 418 | [/if] |