notification changes

This commit is contained in:
indifferentketchup
2026-04-08 09:22:47 -05:00
parent 4d53ef179f
commit a4fb82620a
9 changed files with 740 additions and 131 deletions

View File

@@ -20,8 +20,7 @@
<a href="#s-behavior">Ticket Behavior</a>
<a href="#s-threads">Staff Threads</a>
<a href="#s-pins">Pin Messages</a>
<a href="#s-surge">Surge Alerts</a>
<a href="#s-patterns">Pattern Detection</a>
<a href="#s-notifications">Notifications</a>
<a href="#s-logging">Logging</a>
<a href="#s-automation">Automation</a>
<a href="#s-appearance">Appearance</a>
@@ -156,44 +155,139 @@
</div></div>
</div>
<!-- 8. Surge Alerts -->
<div class="section" id="s-surge">
<div class="section-header"><h2>Surge Alerts</h2><p>Ticket volume and staffing alerts</p><span class="chevron">&#9660;</span></div>
<div class="section-body"><div class="field-grid">
<div class="field"><label>Surge Role</label><input type="text" data-key="SURGE_ROLE_ID" data-smart="role"></div>
<div class="field"><label>Ticket Surge Count</label><input type="number" data-key="SURGE_TICKET_COUNT"></div>
<div class="field"><label>Ticket Window (min)</label><input type="number" data-key="SURGE_TICKET_WINDOW_MINUTES"></div>
<div class="field"><label>Game Surge Count</label><input type="number" data-key="SURGE_GAME_TICKET_COUNT"></div>
<div class="field"><label>Game Window (min)</label><input type="number" data-key="SURGE_GAME_TICKET_WINDOW_MINUTES"></div>
<div class="field"><label>Stale Count</label><input type="number" data-key="SURGE_STALE_COUNT"></div>
<div class="field"><label>Stale Hours</label><input type="number" data-key="SURGE_STALE_HOURS"></div>
<div class="field"><label>Needs Response Count</label><input type="number" data-key="SURGE_NEEDS_RESPONSE_COUNT"></div>
<div class="field"><label>Needs Response Hours</label><input type="number" data-key="SURGE_NEEDS_RESPONSE_HOURS"></div>
<div class="field"><label>Unclaimed Count</label><input type="number" data-key="SURGE_UNCLAIMED_COUNT"></div>
<div class="field"><label>Unclaimed Minutes</label><input type="number" data-key="SURGE_UNCLAIMED_MINUTES"></div>
<div class="field"><label>Tier 3 Unclaimed (min)</label><input type="number" data-key="SURGE_TIER3_UNCLAIMED_MINUTES"></div>
<div class="field"><label>Cooldown (min)</label><input type="number" data-key="SURGE_COOLDOWN_MINUTES"></div>
<div class="field"><label>DND = Available</label><div class="toggle-wrap"><label class="toggle"><input type="checkbox" data-key="STAFF_DND_COUNTS_AS_AVAILABLE"><span class="slider"></span></label><span>Enabled</span></div></div>
<div class="field"><label>No-Staff Cooldown (min)</label><input type="number" data-key="SURGE_NO_STAFF_COOLDOWN_MINUTES"></div>
<div class="field"><label>No-Staff Ticket Threshold</label><input type="number" data-key="SURGE_NO_STAFF_OPEN_TICKET_THRESHOLD"></div>
<div class="field"><label>Chat Alert Message Count</label><input type="number" data-key="CHAT_ALERT_MESSAGE_COUNT"></div>
<div class="field"><label>Chat No-Response Hours</label><input type="number" data-key="CHAT_ALERT_HOURS_WITHOUT_RESPONSE"></div>
<div class="field"><label>Chat Alert Cooldown (min)</label><input type="number" data-key="CHAT_ALERT_COOLDOWN_MINUTES"></div>
</div></div>
</div>
<!-- 8. Notifications -->
<div class="section" id="s-notifications">
<div class="section-header"><h2>Notifications</h2><p>Threshold milestones and trigger conditions by alert category</p><span class="chevron">&#9660;</span></div>
<div class="section-body">
<style>
#s-notifications .notif-tabs { display:flex; gap:8px; flex-wrap:wrap; margin-bottom:16px; }
#s-notifications .notif-tab-btn { border:1px solid var(--border); background:var(--surface-2); color:var(--text); border-radius:8px; padding:8px 12px; cursor:pointer; }
#s-notifications .notif-tab-btn.active { border-color:var(--accent); color:var(--accent); }
#s-notifications .notif-panel.hidden { display:none; }
#s-notifications .notif-editor { border:1px solid var(--border); border-radius:10px; padding:14px; margin-bottom:14px; background:var(--surface-2); }
#s-notifications .notif-chips { display:flex; gap:8px; flex-wrap:wrap; margin:10px 0; min-height:28px; }
#s-notifications .notif-chip { display:inline-flex; align-items:center; gap:8px; border:1px solid var(--border); background:var(--surface); border-radius:999px; padding:4px 10px; font-size:12px; }
#s-notifications .notif-chip button { border:none; background:transparent; color:var(--text-muted); cursor:pointer; padding:0; line-height:1; font-size:14px; }
#s-notifications .notif-input-row { display:flex; gap:8px; flex-wrap:wrap; align-items:center; }
#s-notifications .notif-input-row input { width:220px; }
#s-notifications .notif-presets { display:flex; gap:8px; flex-wrap:wrap; margin-top:10px; }
#s-notifications .notif-presets button { padding:6px 10px; border-radius:8px; border:1px solid var(--border); background:var(--surface); color:var(--text); cursor:pointer; }
#s-notifications .notif-trigger { margin-top:10px; }
#s-notifications .notif-trigger summary { cursor:pointer; color:var(--text-muted); font-weight:600; margin-bottom:10px; }
</style>
<!-- 9. Pattern Detection -->
<div class="section" id="s-patterns">
<div class="section-header"><h2>Pattern Detection</h2><p>Thresholds for automated pattern alerts</p><span class="chevron">&#9660;</span></div>
<div class="section-body"><div class="field-grid">
<div class="field"><label>Check Interval (min)</label><input type="number" data-key="PATTERN_CHECK_INTERVAL_MINUTES"></div>
<div class="field"><label>User Ticket Threshold</label><input type="number" data-key="PATTERN_USER_TICKET_THRESHOLD"></div>
<div class="field"><label>Game Ticket Threshold</label><input type="number" data-key="PATTERN_GAME_TICKET_THRESHOLD"></div>
<div class="field"><label>Staff Stale Ping Threshold</label><input type="number" data-key="PATTERN_STAFF_STALE_PING_THRESHOLD"></div>
<div class="field"><label>Escalation Threshold</label><input type="number" data-key="PATTERN_ESCALATION_THRESHOLD"></div>
<div class="field"><label>Rapid Close Seconds</label><input type="number" data-key="PATTERN_RAPID_CLOSE_SECONDS"></div>
<div class="field"><label>Unclaimed Hours</label><input type="number" data-key="PATTERN_UNCLAIMED_HOURS"></div>
</div></div>
<input type="hidden" data-key="NOTIFICATION_THRESHOLDS_JSON">
<div class="notif-tabs" role="tablist" aria-label="Notification categories">
<button type="button" class="notif-tab-btn active" data-notif-tab="surge">Surge</button>
<button type="button" class="notif-tab-btn" data-notif-tab="patterns">Patterns</button>
<button type="button" class="notif-tab-btn" data-notif-tab="unclaimed">Unclaimed</button>
<button type="button" class="notif-tab-btn" data-notif-tab="chat">Chat</button>
</div>
<div class="notif-panel" data-notif-panel="surge">
<p class="hint">Surge alerts fire when active ticket conditions cross thresholds — high volume, unclaimed queues, no staff online. Each alert escalates through its threshold list, spacing out pings as the condition persists. The counter resets when the condition clears.</p>
<div class="notif-editor">
<div class="field"><label>Alert key</label><select class="notif-alert-select" data-notif-category="surge"></select></div>
<div class="hint notif-alert-description" data-notif-description="surge"></div>
<div class="notif-chips" data-notif-chips="surge"></div>
<div class="notif-input-row">
<input type="text" class="notif-threshold-input" data-notif-input="surge" placeholder="15m, 1h, 1d6h, 2d6h, 5">
<button type="button" class="notif-add-btn" data-notif-add="surge">Add</button>
</div>
<div class="notif-presets" data-notif-presets="surge"></div>
</div>
<details class="notif-trigger">
<summary>Trigger conditions</summary>
<div class="field-grid">
<div class="field"><label>Surge Role</label><input type="text" data-key="SURGE_ROLE_ID" data-smart="role"></div>
<div class="field"><label>Ticket Surge Count</label><input type="number" data-key="SURGE_TICKET_COUNT"></div>
<div class="field"><label>Ticket Window (min)</label><input type="number" data-key="SURGE_TICKET_WINDOW_MINUTES"></div>
<div class="field"><label>Game Surge Count</label><input type="number" data-key="SURGE_GAME_TICKET_COUNT"></div>
<div class="field"><label>Game Window (min)</label><input type="number" data-key="SURGE_GAME_TICKET_WINDOW_MINUTES"></div>
<div class="field"><label>Stale Count</label><input type="number" data-key="SURGE_STALE_COUNT"></div>
<div class="field"><label>Stale Hours</label><input type="number" data-key="SURGE_STALE_HOURS"></div>
<div class="field"><label>Needs Response Count</label><input type="number" data-key="SURGE_NEEDS_RESPONSE_COUNT"></div>
<div class="field"><label>Needs Response Hours</label><input type="number" data-key="SURGE_NEEDS_RESPONSE_HOURS"></div>
<div class="field"><label>Unclaimed Count</label><input type="number" data-key="SURGE_UNCLAIMED_COUNT"></div>
<div class="field"><label>Unclaimed Minutes</label><input type="number" data-key="SURGE_UNCLAIMED_MINUTES"></div>
<div class="field"><label>Tier 3 Unclaimed (min)</label><input type="number" data-key="SURGE_TIER3_UNCLAIMED_MINUTES"></div>
<div class="field"><label>Cooldown (min)</label><input type="number" data-key="SURGE_COOLDOWN_MINUTES"></div>
<div class="field"><label>DND = Available</label><div class="toggle-wrap"><label class="toggle"><input type="checkbox" data-key="STAFF_DND_COUNTS_AS_AVAILABLE"><span class="slider"></span></label><span>Enabled</span></div></div>
<div class="field"><label>No-Staff Cooldown (min)</label><input type="number" data-key="SURGE_NO_STAFF_COOLDOWN_MINUTES"></div>
<div class="field"><label>No-Staff Ticket Threshold</label><input type="number" data-key="SURGE_NO_STAFF_OPEN_TICKET_THRESHOLD"></div>
</div>
</details>
</div>
<div class="notif-panel hidden" data-notif-panel="patterns">
<p class="hint">Pattern alerts detect trends over time — surges by game, escalation rates, staff behavior. Each alert fires once per threshold crossed within its window (daily/weekly/monthly) and won't repeat until the next window resets.</p>
<div class="notif-editor">
<div class="field"><label>Alert key</label><select class="notif-alert-select" data-notif-category="patterns"></select></div>
<div class="hint notif-alert-description" data-notif-description="patterns"></div>
<div class="notif-chips" data-notif-chips="patterns"></div>
<div class="notif-input-row">
<input type="text" class="notif-threshold-input" data-notif-input="patterns" placeholder="15m, 1h, 1d6h, 2d6h, 5">
<button type="button" class="notif-add-btn" data-notif-add="patterns">Add</button>
</div>
<div class="notif-presets" data-notif-presets="patterns"></div>
</div>
<details class="notif-trigger">
<summary>Trigger conditions</summary>
<div class="field-grid">
<div class="field"><label>Check Interval (min)</label><input type="number" data-key="PATTERN_CHECK_INTERVAL_MINUTES"></div>
<div class="field"><label>User Ticket Threshold</label><input type="number" data-key="PATTERN_USER_TICKET_THRESHOLD"></div>
<div class="field"><label>Game Ticket Threshold</label><input type="number" data-key="PATTERN_GAME_TICKET_THRESHOLD"></div>
<div class="field"><label>Staff Stale Ping Threshold</label><input type="number" data-key="PATTERN_STAFF_STALE_PING_THRESHOLD"></div>
<div class="field"><label>Escalation Threshold</label><input type="number" data-key="PATTERN_ESCALATION_THRESHOLD"></div>
<div class="field"><label>Rapid Close Seconds</label><input type="number" data-key="PATTERN_RAPID_CLOSE_SECONDS"></div>
<div class="field"><label>Unclaimed Hours</label><input type="number" data-key="PATTERN_UNCLAIMED_HOURS"></div>
</div>
</details>
</div>
<div class="notif-panel hidden" data-notif-panel="unclaimed">
<p class="hint">Per-ticket reminders sent to staff notification channels when a ticket remains unclaimed. Each threshold fires once per ticket. Escalating a ticket resets the threshold list so reminders restart for the new tier.</p>
<div class="notif-editor">
<div class="field"><label>Alert key</label><select class="notif-alert-select" data-notif-category="unclaimed"></select></div>
<div class="hint notif-alert-description" data-notif-description="unclaimed"></div>
<div class="notif-chips" data-notif-chips="unclaimed"></div>
<div class="notif-input-row">
<input type="text" class="notif-threshold-input" data-notif-input="unclaimed" placeholder="15m, 1h, 1d6h, 2d6h, 5">
<button type="button" class="notif-add-btn" data-notif-add="unclaimed">Add</button>
</div>
<div class="notif-presets" data-notif-presets="unclaimed"></div>
</div>
<details class="notif-trigger">
<summary>Trigger conditions</summary>
<div class="field-grid">
<div class="field full-width"><p class="hint">Unclaimed notifications use threshold milestones only.</p></div>
</div>
</details>
</div>
<div class="notif-panel hidden" data-notif-panel="chat">
<p class="hint">Monitors configured chat channels for unresponded user messages. Fires at escalating intervals while the condition persists. Resets when a staff member responds.</p>
<div class="notif-editor">
<div class="field"><label>Alert key</label><select class="notif-alert-select" data-notif-category="chat"></select></div>
<div class="hint notif-alert-description" data-notif-description="chat"></div>
<div class="notif-chips" data-notif-chips="chat"></div>
<div class="notif-input-row">
<input type="text" class="notif-threshold-input" data-notif-input="chat" placeholder="15m, 1h, 1d6h, 2d6h, 5">
<button type="button" class="notif-add-btn" data-notif-add="chat">Add</button>
</div>
<div class="notif-presets" data-notif-presets="chat"></div>
</div>
<details class="notif-trigger">
<summary>Trigger conditions</summary>
<div class="field-grid">
<div class="field"><label>Chat Alert Message Count</label><input type="number" data-key="CHAT_ALERT_MESSAGE_COUNT"></div>
<div class="field"><label>Chat No-Response Hours</label><input type="number" data-key="CHAT_ALERT_HOURS_WITHOUT_RESPONSE"></div>
<div class="field"><label>Chat Alert Cooldown (min)</label><input type="number" data-key="CHAT_ALERT_COOLDOWN_MINUTES"></div>
</div>
</details>
</div>
</div>
</div>
<!-- 10. Logging -->