added on local at 2026-07-13 16:46:16
| 1 | <div class="page-head"> | |
| 2 | <span class="page-eyebrow" style="background:rgba(244,63,94,.10);border-color:rgba(244,63,94,.30);color:var(--accent-danger-hi)"><span class="dot" style="background:var(--accent-danger-hi);box-shadow:0 0 10px var(--accent-danger-hi)"></span> Danger zone</span> | |
| 3 | <h1 class="page-title">Reset captured data</h1> | |
| 4 | <p class="page-subtitle">Wipe every captured file change, schema diff, blob, release, and audit log — keep every configuration setting. After the wipe, the scanners re-run immediately so the next capture is a fresh baseline. Nothing on your monitored servers is touched.</p> | |
| 5 | </div> | |
| 6 | ||
| 7 | [if:$did_reset] | |
| 8 | ||
| 9 | <div class="module glow-emerald"> | |
| 10 | <div class="module-head"><div class="left"> | |
| 11 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg></div> | |
| 12 | <div class="module-title">Reset complete</div> | |
| 13 | <span class="module-subtitle">$total_wiped rows removed. Fresh scans have been kicked off — check back in ~30 seconds to see the new baseline.</span> | |
| 14 | </div></div> | |
| 15 | <div class="module-body"> | |
| 16 | [if:$has_backup] | |
| 17 | <div class="ds-guide" style="background:rgba(52,211,153,.06);border-color:rgba(52,211,153,.25)"> | |
| 18 | <div class="dsg-icon" style="background:rgba(52,211,153,.15);border-color:rgba(52,211,153,.4);color:var(--accent-ok)">✓</div> | |
| 19 | <div> | |
| 20 | <span class="dsg-title" style="color:var(--accent-ok)">Backup safe</span> | |
| 21 | Everything you wiped was captured first at:<br> | |
| 22 | <code style="font-size:11.5px">$backup_path</code> | |
| 23 | </div> | |
| 24 | </div> | |
| 25 | [/if] | |
| 26 | ||
| 27 | <h3 style="margin:16px 0 8px;font-size:13px;color:var(--text)">Steps performed</h3> | |
| 28 | <ol style="margin:0;padding-left:22px;font-size:12.5px;color:var(--text-dim)"> | |
| 29 | [loop:@steps]<li>$text</li>[/loop] | |
| 30 | </ol> | |
| 31 | ||
| 32 | <div style="margin-top:20px;display:flex;gap:10px"> | |
| 33 | <a href="/dashboard.cgi" class="tr-chip is-active" style="border:none;padding:9px 22px">Go to dashboard</a> | |
| 34 | <a href="/file_changes.cgi?tr=24h" class="tr-chip">See file changes</a> | |
| 35 | <a href="/sites.cgi" class="tr-chip">Sites list</a> | |
| 36 | </div> | |
| 37 | </div> | |
| 38 | </div> | |
| 39 | ||
| 40 | [/if] | |
| 41 | ||
| 42 | [if:!$did_reset] | |
| 43 | ||
| 44 | <div class="ds-guide" style="background:rgba(244,63,94,.05);border-color:rgba(244,63,94,.25)"> | |
| 45 | <div class="dsg-icon" style="background:rgba(244,63,94,.15);border-color:rgba(244,63,94,.4);color:var(--accent-danger-hi)">!</div> | |
| 46 | <div> | |
| 47 | <span class="dsg-title" style="color:var(--accent-danger-hi)">This is irreversible.</span> | |
| 48 | Every captured change, blob, release, and audit-log entry will be removed — <strong>$grand_total rows total</strong>. Your files, database schemas, and servers are not touched; only DriftSense's captures are cleared. A backup will be written to <code>site_backups/</code> first, so a mistake is recoverable via <code>mysql < backup.sql</code> if needed. | |
| 49 | </div> | |
| 50 | </div> | |
| 51 | ||
| 52 | <div class="dash-grid" style="grid-template-columns:1fr 1fr;margin-top:16px"> | |
| 53 | <div class="module glow-rose"> | |
| 54 | <div class="module-head"><div class="left"> | |
| 55 | <div class="module-icon" style="color:var(--accent-danger-hi);background:rgba(244,63,94,.10);border-color:rgba(244,63,94,.30)"><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> | |
| 56 | <div class="module-title">Will be wiped</div> | |
| 57 | <span class="module-subtitle">$wipe_ct tables · $grand_total rows total</span> | |
| 58 | </div></div> | |
| 59 | <div class="module-body tight" style="max-height:340px;overflow:auto"> | |
| 60 | <table class="tbl"> | |
| 61 | <thead><tr><th>Table</th><th class="mono" style="width:110px">Rows</th></tr></thead> | |
| 62 | <tbody> | |
| 63 | [loop:@wipe_tables] | |
| 64 | <tr> | |
| 65 | <td class="mono" style="font-size:11.5px;color:var(--accent-danger-hi)">$name</td> | |
| 66 | <td class="mono">$count</td> | |
| 67 | </tr> | |
| 68 | [/loop] | |
| 69 | </tbody> | |
| 70 | </table> | |
| 71 | </div> | |
| 72 | </div> | |
| 73 | <div class="module glow-emerald"> | |
| 74 | <div class="module-head"><div class="left"> | |
| 75 | <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><polyline points="20 6 9 17 4 12"/></svg></div> | |
| 76 | <div class="module-title">Will be kept</div> | |
| 77 | <span class="module-subtitle">$keep_ct config tables · every setting preserved</span> | |
| 78 | </div></div> | |
| 79 | <div class="module-body tight" style="max-height:340px;overflow:auto"> | |
| 80 | <table class="tbl"> | |
| 81 | <thead><tr><th>Table</th></tr></thead> | |
| 82 | <tbody> | |
| 83 | [loop:@keep_tables] | |
| 84 | <tr><td class="mono" style="font-size:11.5px;color:var(--accent-ok)">$name</td></tr> | |
| 85 | [/loop] | |
| 86 | </tbody> | |
| 87 | </table> | |
| 88 | </div> | |
| 89 | </div> | |
| 90 | </div> | |
| 91 | ||
| 92 | <div class="module glow-rose" style="margin-top:16px"> | |
| 93 | <div class="module-head"><div class="left"> | |
| 94 | <div class="module-title">Step 1 — Type to arm</div> | |
| 95 | <span class="module-subtitle">Type <strong style="color:var(--accent-danger-hi);font-family:var(--mono)">WIPE</strong> below. The button unlocks when the word matches exactly.</span> | |
| 96 | </div></div> | |
| 97 | <div class="module-body" style="display:flex;gap:12px;align-items:center;flex-wrap:wrap"> | |
| 98 | <input type="text" id="rs_type" placeholder="type WIPE to arm" autocomplete="off" spellcheck="false" | |
| 99 | oninput="dsResetType(this.value)" | |
| 100 | style="flex:1 1 260px;padding:11px 14px;background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;font-family:var(--mono);font-size:14px;letter-spacing:.05em"> | |
| 101 | <button type="button" id="rs_open" disabled onclick="dsResetOpenModal()" | |
| 102 | class="tr-chip is-active" | |
| 103 | style="border:none;padding:11px 26px;background:var(--accent-danger);border-color:var(--accent-danger);color:#fff;opacity:.35;pointer-events:none"> | |
| 104 | Review & wipe → | |
| 105 | </button> | |
| 106 | <a href="/settings.cgi" class="tr-chip" style="padding:11px 18px">Cancel</a> | |
| 107 | </div> | |
| 108 | </div> | |
| 109 | ||
| 110 | <!-- =============== MODAL OVERLAY =============== --> | |
| 111 | <div id="dsResetModal" class="ds-modal" role="dialog" aria-modal="true" aria-labelledby="dsResetTitle" aria-hidden="true"> | |
| 112 | <div class="ds-modal-backdrop" onclick="dsResetCloseModal()"></div> | |
| 113 | <div class="ds-modal-card"> | |
| 114 | <div class="ds-modal-glow"></div> | |
| 115 | <div class="ds-modal-head"> | |
| 116 | <div class="ds-modal-icon"> | |
| 117 | <svg viewBox="0 0 24 24" width="24" height="24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg> | |
| 118 | </div> | |
| 119 | <div> | |
| 120 | <div class="ds-modal-eyebrow">Final confirmation</div> | |
| 121 | <h2 id="dsResetTitle" class="ds-modal-title">Wipe all captured data?</h2> | |
| 122 | </div> | |
| 123 | <button type="button" class="ds-modal-x" onclick="dsResetCloseModal()" aria-label="Close"> | |
| 124 | <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> | |
| 125 | </button> | |
| 126 | </div> | |
| 127 | <div class="ds-modal-body"> | |
| 128 | <div class="ds-modal-stat-row"> | |
| 129 | <div class="ds-modal-stat"> | |
| 130 | <div class="ds-modal-stat-num" style="color:var(--accent-danger-hi)">$grand_total</div> | |
| 131 | <div class="ds-modal-stat-lbl">rows will be deleted</div> | |
| 132 | </div> | |
| 133 | <div class="ds-modal-stat"> | |
| 134 | <div class="ds-modal-stat-num">$wipe_ct</div> | |
| 135 | <div class="ds-modal-stat-lbl">tables emptied</div> | |
| 136 | </div> | |
| 137 | <div class="ds-modal-stat"> | |
| 138 | <div class="ds-modal-stat-num" style="color:var(--accent-ok)">$keep_ct</div> | |
| 139 | <div class="ds-modal-stat-lbl">config tables kept</div> | |
| 140 | </div> | |
| 141 | </div> | |
| 142 | ||
| 143 | <ul class="ds-modal-checks"> | |
| 144 | <li><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="var(--accent-ok)" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg> Automatic mysqldump backup is written first to <code>site_backups/</code></li> | |
| 145 | <li><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="var(--accent-ok)" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg> Your monitors, servers, alert rules, and watch-list are preserved</li> | |
| 146 | <li><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="var(--accent-ok)" stroke-width="2.5"><polyline points="20 6 9 17 4 12"/></svg> Fresh scans kick immediately after the wipe — new baseline in seconds</li> | |
| 147 | <li><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="var(--accent-danger-hi)" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Named releases and their pinned blob history will be lost forever</li> | |
| 148 | <li><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="var(--accent-danger-hi)" stroke-width="2.5"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg> Restore log + pin drift audit trail will be gone</li> | |
| 149 | </ul> | |
| 150 | ||
| 151 | <label class="ds-modal-ack"> | |
| 152 | <input type="checkbox" id="rs_ack" onchange="dsResetAckToggle()"> | |
| 153 | <span>I understand this cannot be undone.</span> | |
| 154 | </label> | |
| 155 | </div> | |
| 156 | <div class="ds-modal-foot"> | |
| 157 | <button type="button" class="tr-chip" onclick="dsResetCloseModal()" style="padding:10px 18px">Cancel</button> | |
| 158 | <form method="post" action="/reset.cgi" style="display:inline;margin:0"> | |
| 159 | <input type="hidden" name="confirm" value="WIPE"> | |
| 160 | <button type="submit" id="rs_final" disabled | |
| 161 | class="tr-chip is-active" | |
| 162 | style="border:none;padding:11px 26px;background:var(--accent-danger);border-color:var(--accent-danger);color:#fff;opacity:.35;pointer-events:none"> | |
| 163 | Yes, wipe everything | |
| 164 | </button> | |
| 165 | </form> | |
| 166 | </div> | |
| 167 | </div> | |
| 168 | </div> | |
| 169 | ||
| 170 | <style> | |
| 171 | /* Type-to-arm button */ | |
| 172 | #rs_open.rs-armed { opacity:1 !important; pointer-events:auto !important; box-shadow:0 0 0 3px rgba(244,63,94,.15); } | |
| 173 | #rs_open.rs-armed:hover { box-shadow:0 0 0 4px rgba(244,63,94,.25), 0 4px 20px rgba(244,63,94,.35); transform:translateY(-1px); } | |
| 174 | #rs_type { transition:border-color .15s, box-shadow .15s; } | |
| 175 | #rs_type.rs-typing-ok { border-color:var(--accent-danger); box-shadow:0 0 0 3px rgba(244,63,94,.15); } | |
| 176 | /* Final button */ | |
| 177 | #rs_final.rs-acked { opacity:1 !important; pointer-events:auto !important; cursor:pointer; } | |
| 178 | #rs_final.rs-acked:hover { box-shadow:0 0 0 4px rgba(244,63,94,.25), 0 6px 24px rgba(244,63,94,.45); transform:translateY(-1px); } | |
| 179 | ||
| 180 | /* Modal */ | |
| 181 | .ds-modal { position:fixed; inset:0; z-index:1000; display:none; align-items:center; justify-content:center; padding:24px; } | |
| 182 | .ds-modal.open { display:flex; animation:dsm-in .18s ease-out; } | |
| 183 | @keyframes dsm-in { from { opacity:0; } to { opacity:1; } } | |
| 184 | .ds-modal-backdrop { position:absolute; inset:0; background:rgba(3,7,16,.72); backdrop-filter:blur(8px); -webkit-backdrop-filter:blur(8px); } | |
| 185 | .ds-modal-card { | |
| 186 | position:relative; z-index:1; | |
| 187 | max-width:640px; width:100%; | |
| 188 | background:linear-gradient(180deg, var(--bg-2) 0%, var(--bg-1) 100%); | |
| 189 | border:1px solid var(--border); | |
| 190 | border-radius:14px; | |
| 191 | box-shadow:0 20px 60px rgba(0,0,0,.6), 0 0 0 1px rgba(244,63,94,.20); | |
| 192 | overflow:hidden; | |
| 193 | animation:dsm-pop .22s cubic-bezier(.16,1.2,.44,1); | |
| 194 | } | |
| 195 | @keyframes dsm-pop { from { transform:translateY(16px) scale(.96); opacity:0; } to { transform:translateY(0) scale(1); opacity:1; } } | |
| 196 | .ds-modal-glow { | |
| 197 | position:absolute; inset:-1px; border-radius:inherit; pointer-events:none; | |
| 198 | background:linear-gradient(135deg, rgba(244,63,94,.35) 0%, transparent 50%); | |
| 199 | filter:blur(18px); opacity:.5; z-index:-1; | |
| 200 | } | |
| 201 | .ds-modal-head { display:flex; align-items:flex-start; gap:14px; padding:20px 22px 12px; border-bottom:1px solid var(--border); background:rgba(244,63,94,.04); } | |
| 202 | .ds-modal-icon { width:44px; height:44px; border-radius:12px; background:rgba(244,63,94,.14); border:1px solid rgba(244,63,94,.35); color:var(--accent-danger-hi); display:grid; place-items:center; flex:0 0 auto; } | |
| 203 | .ds-modal-eyebrow { font-size:10.5px; letter-spacing:.14em; text-transform:uppercase; color:var(--accent-danger-hi); font-weight:700; } | |
| 204 | .ds-modal-title { margin:2px 0 0; font-size:18px; font-weight:700; letter-spacing:-.01em; } | |
| 205 | .ds-modal-x { margin-left:auto; background:transparent; border:1px solid var(--border); color:var(--text-muted); width:30px; height:30px; border-radius:8px; display:grid; place-items:center; cursor:pointer; transition:border-color .12s, color .12s; } | |
| 206 | .ds-modal-x:hover { color:var(--text); border-color:var(--accent-danger); } | |
| 207 | .ds-modal-body { padding:20px 22px; } | |
| 208 | .ds-modal-stat-row { display:grid; grid-template-columns:repeat(3, 1fr); gap:10px; margin-bottom:18px; } | |
| 209 | .ds-modal-stat { padding:14px 12px; background:var(--bg-2); border:1px solid var(--border); border-radius:10px; text-align:center; } | |
| 210 | .ds-modal-stat-num { font-size:22px; font-weight:800; font-family:var(--mono); line-height:1; } | |
| 211 | .ds-modal-stat-lbl { font-size:10.5px; letter-spacing:.05em; text-transform:uppercase; color:var(--text-muted); font-weight:600; margin-top:4px; } | |
| 212 | .ds-modal-checks { list-style:none; padding:0; margin:0 0 16px; display:flex; flex-direction:column; gap:8px; } | |
| 213 | .ds-modal-checks li { display:flex; gap:10px; align-items:flex-start; font-size:12.5px; color:var(--text-dim); line-height:1.45; } | |
| 214 | .ds-modal-checks li svg { flex:0 0 auto; margin-top:3px; } | |
| 215 | .ds-modal-checks li code { color:var(--accent-hi); font-size:11.5px; } | |
| 216 | .ds-modal-ack { display:flex; align-items:center; gap:10px; padding:12px 14px; background:rgba(244,63,94,.06); border:1px solid rgba(244,63,94,.25); border-radius:10px; cursor:pointer; user-select:none; font-size:13px; color:var(--text); } | |
| 217 | .ds-modal-ack input { width:18px; height:18px; accent-color:var(--accent-danger); } | |
| 218 | .ds-modal-foot { display:flex; gap:10px; justify-content:flex-end; padding:14px 22px; border-top:1px solid var(--border); background:rgba(0,0,0,.20); } | |
| 219 | </style> | |
| 220 | <script> | |
| 221 | window.dsResetType = function (v) { | |
| 222 | var input = document.getElementById('rs_type'); | |
| 223 | var btn = document.getElementById('rs_open'); | |
| 224 | var ok = (v === 'WIPE'); | |
| 225 | input.classList.toggle('rs-typing-ok', ok); | |
| 226 | btn.disabled = !ok; | |
| 227 | btn.classList.toggle('rs-armed', ok); | |
| 228 | }; | |
| 229 | window.dsResetOpenModal = function () { | |
| 230 | var m = document.getElementById('dsResetModal'); | |
| 231 | m.classList.add('open'); | |
| 232 | m.setAttribute('aria-hidden', 'false'); | |
| 233 | document.body.style.overflow = 'hidden'; | |
| 234 | // Focus the acknowledge checkbox for keyboard users | |
| 235 | setTimeout(function(){ var a = document.getElementById('rs_ack'); if (a) a.focus(); }, 100); | |
| 236 | }; | |
| 237 | window.dsResetCloseModal = function () { | |
| 238 | var m = document.getElementById('dsResetModal'); | |
| 239 | m.classList.remove('open'); | |
| 240 | m.setAttribute('aria-hidden', 'true'); | |
| 241 | document.body.style.overflow = ''; | |
| 242 | // Reset the ack state so a re-open requires re-confirming | |
| 243 | var a = document.getElementById('rs_ack'); | |
| 244 | if (a) { a.checked = false; dsResetAckToggle(); } | |
| 245 | }; | |
| 246 | window.dsResetAckToggle = function () { | |
| 247 | var acked = document.getElementById('rs_ack').checked; | |
| 248 | var btn = document.getElementById('rs_final'); | |
| 249 | btn.disabled = !acked; | |
| 250 | btn.classList.toggle('rs-acked', acked); | |
| 251 | }; | |
| 252 | // ESC to close | |
| 253 | document.addEventListener('keydown', function (e) { | |
| 254 | if (e.key === 'Escape') { | |
| 255 | var m = document.getElementById('dsResetModal'); | |
| 256 | if (m && m.classList.contains('open')) dsResetCloseModal(); | |
| 257 | } | |
| 258 | }); | |
| 259 | </script> | |
| 260 | ||
| 261 | [/if] |