Diff -- /var/www/vhosts/3dshawn.com/site1/TEMPLATES/alerts.html

O Operator
Diff

/var/www/vhosts/3dshawn.com/site1/TEMPLATES/alerts.html

modified on local at 2026-07-12 00:35:28

Added
+8
lines
Removed
-0
lines
Context
200
unchanged
Blobs
from 817bbf649595
to 4433ba3e7905
Restore this content →
Unified diff
Naive LCS-based line diff. Additions in emerald, deletions in rose. Both sides decompressed live from BLOB_STORE.
11<div class="page-head">
22 <span class="page-eyebrow"><span class="dot"></span> Notify</span>
33 <h1 class="page-title">Alert rules</h1>
44 <p class="page-subtitle">Route file + schema changes to Slack, Discord, or any HTTP webhook. Rules fire in near-real-time (as the cron dispatcher runs every minute). Every attempt is logged.</p>
5</div>
6
7<div class="ds-guide">
8 <div class="dsg-icon">i</div>
9 <div>
10 <span class="dsg-title">How a rule fires:</span>
11 Two flavors. <strong>Per-row</strong> rules (default) fire on every change that matches the path glob + kind + status filter &mdash; good for "wake me on any deletion". <strong>Frequency</strong> rules (set threshold &gt; 0) fire once when a matching file crosses N changes in M minutes &mdash; good for "wake me when someone edits the payment gateway config 5+ times in an hour". Rate limit protects you from firehoses; every delivery attempt is logged whether it succeeded or failed.
12 </div>
513</div>
614
715<div class="dash-grid" style="grid-template-columns:1fr 1fr;margin-bottom:20px">
816
917 <!-- Rule form -->
1018 <div class="module glow-teal">
1119 <div class="module-head"><div class="left">
1220 <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>
1321 <div class="module-title">[if:$is_edit]Edit rule #$edit_id[/if][if:!$is_edit]New rule[/if]</div>
1422 <span class="module-subtitle">Combine a matcher (kind + path glob) with a delivery target. Save, then wait for the next capture tick.</span>
1523 </div></div>
1624 <div class="module-body">
1725 <form method="post" action="/alerts.cgi" style="display:flex;flex-direction:column;gap:12px">
1826 <input type="hidden" name="op" value="$form_op">
1927 [if:$is_edit]<input type="hidden" name="alert_rule_id" value="$edit_id">[/if]
2028
2129 <label style="display:flex;flex-direction:column;gap:4px">
2230 <span class="rb-label">Name</span>
2331 <input type="text" name="rule_name" value="$rule_name" placeholder="e.g. Prod nginx config changes" required
2432 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px;font-family:inherit">
2533 </label>
2634
2735 <div style="display:flex;gap:12px">
2836 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
2937 <span class="rb-label">Match kind</span>
3038 <select name="match_kind" style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
3139 <option value="either" $mk_either_sel>Either (file + schema)</option>
3240 <option value="file" $mk_file_sel>File changes only</option>
3341 <option value="schema" $mk_schema_sel>Schema DDL only</option>
3442 </select>
3543 </label>
3644 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
3745 <span class="rb-label">Path glob</span>
3846 <input type="text" name="match_path_glob" value="$match_path_glob" placeholder="e.g. /etc/nginx/** or drift_sense.**"
3947 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:12px">
4048 </label>
4149 </div>
4250
4351 <div style="display:flex;gap:12px">
4452 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
4553 <span class="rb-label">Status filter <span class="dim" style="text-transform:none;letter-spacing:0;font-size:10.5px">(files only)</span></span>
4654 <input type="text" name="match_status_list" value="$match_status_list" placeholder="added,modified,deleted"
4755 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:12px">
4856 </label>
4957 <label style="flex:1;display:flex;align-items:center;gap:8px;margin-top:16px">
5058 <input type="checkbox" name="exclude_ts_only" value="1" $exclude_ts_only_checked>
5159 <span style="font-size:12.5px;color:var(--text-dim)">Exclude timestamp-only changes</span>
5260 </label>
5361 </div>
5462
5563 <hr style="border:none;border-top:1px solid var(--border);margin:4px 0">
5664
5765 <div style="display:flex;gap:12px">
5866 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
5967 <span class="rb-label">Delivery</span>
6068 <select name="delivery_kind" style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
6169 <option value="generic_webhook" $dk_generic_webhook_sel>Generic HTTP webhook</option>
6270 <option value="slack" $dk_slack_sel>Slack incoming webhook</option>
6371 <option value="discord" $dk_discord_sel>Discord webhook</option>
6472 <option value="email" $dk_email_sel>Email (not yet implemented)</option>
6573 </select>
6674 </label>
6775 <label style="flex:2;display:flex;flex-direction:column;gap:4px">
6876 <span class="rb-label">Webhook URL</span>
6977 <input type="text" name="delivery_url" value="$delivery_url" placeholder="https://hooks.slack.com/..."
7078 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:11.5px">
7179 </label>
7280 </div>
7381
7482 <div style="display:flex;gap:12px">
7583 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
7684 <span class="rb-label">Rate limit / min</span>
7785 <input type="number" name="rate_limit_per_min" value="$rate_limit_per_min" min="0"
7886 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
7987 </label>
8088 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
8189 <span class="rb-label">Coalesce window (s)</span>
8290 <input type="number" name="coalesce_window_s" value="$coalesce_window_s" min="0"
8391 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
8492 </label>
8593 <label style="flex:1;display:flex;align-items:center;gap:8px;margin-top:16px">
8694 <input type="checkbox" name="is_active" value="1" $is_active_checked>
8795 <span style="font-size:12.5px;color:var(--text-dim)">Rule is active</span>
8896 </label>
8997 </div>
9098
9199 <hr style="border:none;border-top:1px solid var(--border);margin:4px 0">
92100
93101 <div class="rb-label" style="margin-bottom:-4px">Frequency mode <span class="dim" style="text-transform:none;letter-spacing:0;font-size:10.5px">&mdash; when threshold &gt; 0, this rule fires whenever a matching file crosses N changes in M minutes (instead of firing per row)</span></div>
94102 <div style="display:flex;gap:12px">
95103 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
96104 <span class="rb-label">Threshold (changes)</span>
97105 <input type="number" name="frequency_threshold" value="$frequency_threshold" min="0"
98106 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
99107 </label>
100108 <label style="flex:1;display:flex;flex-direction:column;gap:4px">
101109 <span class="rb-label">Window (minutes)</span>
102110 <input type="number" name="frequency_window_min" value="$frequency_window_min" min="1"
103111 style="background:var(--bg-1);color:var(--text);border:1px solid var(--border);border-radius:8px;padding:8px 12px">
104112 </label>
105113 </div>
106114
107115 <div style="display:flex;gap:8px;justify-content:flex-end;margin-top:8px">
108116 [if:$is_edit]<a href="/alerts.cgi" class="tr-chip">Cancel</a>[/if]
109117 <button type="submit" class="tr-chip is-active" style="border:none">[if:$is_edit]Save changes[/if][if:!$is_edit]Create rule[/if]</button>
110118 </div>
111119 </form>
112120 </div>
113121 </div>
114122
115123 <!-- Delivery history -->
116124 <div class="module glow-emerald">
117125 <div class="module-head"><div class="left">
118126 <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg></div>
119127 <div class="module-title">Recent deliveries</div>
120128 <span class="module-subtitle">Last 30 fire attempts across every rule. Audit trail for compliance / debugging.</span>
121129 </div></div>
122130 <div class="module-body tight" style="max-height:520px;overflow:auto">
123131 [if:$has_deliveries]
124132 <table class="tbl">
125133 <thead><tr>
126134 <th style="width:80px">Status</th>
127135 <th>Rule / target</th>
128136 <th style="width:120px">Result</th>
129137 <th style="width:150px">When</th>
130138 </tr></thead>
131139 <tbody>
132140 [loop:@deliveries]
133141 <tr>
134142 <td><span class="pill $delivery_pill">$delivery_status</span></td>
135143 <td class="mono" style="font-size:11.5px"><a href="$source_url" style="color:var(--accent-hi);text-decoration:none">$summary_h</a></td>
136144 <td class="dim mono" style="font-size:11px">$err_h</td>
137145 <td class="mono dim"><span class="ts" data-ts="$fired_epoch" data-fmt="relative">$fired_at</span></td>
138146 </tr>
139147 [/loop]
140148 </tbody>
141149 </table>
142150 [/if]
143151 [if:!$has_deliveries]
144152 <div style="padding:36px 14px;text-align:center;color:var(--text-dim);font-size:13.5px">
145153 No deliveries yet. Create a rule and wait for a change to fire it.
146154 </div>
147155 [/if]
148156 </div>
149157 </div>
150158</div>
151159
152160<!-- Rule list -->
153161<div class="module glow-sky">
154162 <div class="module-head"><div class="left">
155163 <div class="module-icon"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" stroke-width="2"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg></div>
156164 <div class="module-title">Rules</div>
157165 <span class="module-subtitle">Click a row to edit. Deactivating a rule stops it firing but keeps its history.</span>
158166 </div></div>
159167 <div class="module-body tight">
160168 [if:$has_rules]
161169 <table class="tbl">
162170 <thead><tr>
163171 <th style="width:80px">Status</th>
164172 <th>Name</th>
165173 <th>Matches</th>
166174 <th style="width:110px">Delivery</th>
167175 <th>Target</th>
168176 <th style="width:70px">Fires</th>
169177 <th style="width:150px">Last fired</th>
170178 <th style="width:60px">Actions</th>
171179 </tr></thead>
172180 <tbody>
173181 [loop:@rules]
174182 <tr>
175183 <td><span class="pill $status_pill">$status_label</span></td>
176184 <td><a href="$edit_url" style="color:var(--accent-hi);text-decoration:none">$rule_name</a></td>
177185 <td class="mono dim" style="font-size:11.5px">$match_kind &middot; $match_glob_h</td>
178186 <td><span class="pill $kind_pill">$delivery_kind</span></td>
179187 <td class="mono dim" style="font-size:11px">$url_h</td>
180188 <td class="mono">$fire_count</td>
181189 <td class="mono dim"><span class="ts" data-ts="$last_fired_epoch" data-fmt="relative">$last_fired_h</span></td>
182190 <td>
183191 <form method="post" action="/alerts.cgi" style="display:inline">
184192 <input type="hidden" name="op" value="toggle">
185193 <input type="hidden" name="alert_rule_id" value="$alert_rule_id">
186194 <button type="submit" class="tr-chip" title="Toggle active" style="padding:3px 8px;font-size:11px">⏻</button>
187195 </form>
188196 </td>
189197 </tr>
190198 [/loop]
191199 </tbody>
192200 </table>
193201 [/if]
194202 [if:!$has_rules]
195203 <div style="padding:36px 14px;text-align:center;color:var(--text-dim);font-size:13.5px">
196204 No rules yet. Use the form above to create your first.
197205 </div>
198206 [/if]
199207 </div>
200208</div>