show running process in process viewer and add limiting to the notification system

This commit is contained in:
KingKDot
2026-05-16 23:19:46 -05:00
parent e2ef4a375f
commit d691c5b804
11 changed files with 207 additions and 3 deletions
+32 -1
View File
@@ -27,6 +27,9 @@ const keywordInput = document.getElementById("keyword-input");
const clipboardEnabledInput = document.getElementById("clipboard-enabled");
const saveKeywordsBtn = document.getElementById("save-keywords");
const keywordHint = document.getElementById("keyword-hint");
const antiSpamMaxHitsInput = document.getElementById("antispam-max-hits");
const antiSpamWindowInput = document.getElementById("antispam-window");
const antiSpamCooldownInput = document.getElementById("antispam-cooldown");
// Webhook section
const webhookEnabledInput = document.getElementById("webhook-enabled");
@@ -476,6 +479,15 @@ async function loadKeywords() {
if (clipboardEnabledInput) {
clipboardEnabledInput.checked = data?.notifications?.clipboardEnabled === true;
}
if (antiSpamMaxHitsInput) {
antiSpamMaxHitsInput.value = data?.notifications?.antiSpamMaxHits ?? 15;
}
if (antiSpamWindowInput) {
antiSpamWindowInput.value = Math.round((data?.notifications?.antiSpamWindowMs ?? 600000) / 60000);
}
if (antiSpamCooldownInput) {
antiSpamCooldownInput.value = Math.round((data?.notifications?.antiSpamCooldownMs ?? 600000) / 60000);
}
} catch {}
}
@@ -484,11 +496,21 @@ function wireKeywordSave() {
saveKeywordsBtn.addEventListener("click", async () => {
const keywords = parseKeywords(keywordInput.value);
const clipboardEnabled = clipboardEnabledInput ? clipboardEnabledInput.checked : false;
const payload = { keywords, clipboardEnabled };
if (antiSpamMaxHitsInput) {
payload.antiSpamMaxHits = Math.max(1, parseInt(antiSpamMaxHitsInput.value, 10) || 15);
}
if (antiSpamWindowInput) {
payload.antiSpamWindowMs = Math.max(1, parseInt(antiSpamWindowInput.value, 10) || 10) * 60000;
}
if (antiSpamCooldownInput) {
payload.antiSpamCooldownMs = Math.max(1, parseInt(antiSpamCooldownInput.value, 10) || 10) * 60000;
}
try {
const res = await fetch("/api/notifications/config", {
method: "PUT",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ keywords, clipboardEnabled }),
body: JSON.stringify(payload),
});
if (!res.ok) {
window.showToast?.("Failed to save keywords", "error", 4000);
@@ -501,6 +523,15 @@ function wireKeywordSave() {
if (clipboardEnabledInput && typeof data?.notifications?.clipboardEnabled === "boolean") {
clipboardEnabledInput.checked = data.notifications.clipboardEnabled;
}
if (antiSpamMaxHitsInput && data?.notifications?.antiSpamMaxHits) {
antiSpamMaxHitsInput.value = data.notifications.antiSpamMaxHits;
}
if (antiSpamWindowInput && data?.notifications?.antiSpamWindowMs) {
antiSpamWindowInput.value = Math.round(data.notifications.antiSpamWindowMs / 60000);
}
if (antiSpamCooldownInput && data?.notifications?.antiSpamCooldownMs) {
antiSpamCooldownInput.value = Math.round(data.notifications.antiSpamCooldownMs / 60000);
}
window.showToast?.("Keywords updated", "success", 3000);
} catch {
window.showToast?.("Failed to save keywords", "error", 4000);
+15 -2
View File
@@ -255,6 +255,9 @@ function createProcessRow(proc, depth = 0) {
if (selectedPid === proc.pid) {
row.classList.add("selected");
}
if (proc.self) {
row.classList.add("self-process");
}
const cpuColor =
proc.cpu > 50
@@ -276,6 +279,7 @@ function createProcessRow(proc, depth = 0) {
}
let nameColor = "text-slate-200";
let iconClass = "fa-microchip";
let iconColor = "text-blue-400";
if (proc.type === "system") {
nameColor = "text-purple-400";
@@ -287,12 +291,21 @@ function createProcessRow(proc, depth = 0) {
nameColor = "text-green-300";
iconColor = "text-green-400";
}
if (proc.self) {
nameColor = "text-yellow-300 font-semibold";
iconClass = "fa-crosshairs";
iconColor = "text-yellow-400";
}
const selfBadge = proc.self
? ' <span class="ml-1 text-[10px] uppercase tracking-wide px-1.5 py-0.5 rounded bg-yellow-500/20 text-yellow-300 border border-yellow-500/40">agent</span>'
: "";
row.innerHTML = `
<div class="col-span-1 text-sm font-mono text-slate-400">${proc.pid}</div>
<div class="col-span-4 flex items-center gap-1 truncate">
${indent}${treeIcon}<i class="fa-solid fa-microchip ${iconColor}"></i>
<span class="truncate ${nameColor}">${escapeHtml(proc.name)}</span>
${indent}${treeIcon}<i class="fa-solid ${iconClass} ${iconColor}"></i>
<span class="truncate ${nameColor}">${escapeHtml(proc.name)}</span>${selfBadge}
</div>
<div class="col-span-2 text-sm ${cpuColor} font-semibold">${proc.cpu.toFixed(1)}%</div>
<div class="col-span-2 text-sm text-slate-400">${memoryStr}</div>
+40
View File
@@ -72,6 +72,46 @@
Monitor clipboard content for keyword matches
</label>
<div class="mt-2 text-xs text-slate-500" id="keyword-hint"></div>
<!-- Anti-Spam Settings -->
<div class="mt-4 pt-4 border-t border-slate-800">
<h3 class="text-sm font-semibold text-slate-300">Anti-Spam Limits</h3>
<p class="text-xs text-slate-500 mt-1">
Block a keyword for a client when it fires too many times in a short window.
</p>
<div class="mt-3 grid grid-cols-1 sm:grid-cols-3 gap-3">
<div>
<label class="block text-xs text-slate-400 mb-1">Max hits before block</label>
<input
id="antispam-max-hits"
type="number"
min="1"
max="10000"
class="w-full rounded-lg bg-slate-950 border border-slate-800 text-slate-100 px-3 py-2 text-sm focus:outline-none focus:border-blue-500"
/>
</div>
<div>
<label class="block text-xs text-slate-400 mb-1">Detection window (minutes)</label>
<input
id="antispam-window"
type="number"
min="1"
max="1440"
class="w-full rounded-lg bg-slate-950 border border-slate-800 text-slate-100 px-3 py-2 text-sm focus:outline-none focus:border-blue-500"
/>
</div>
<div>
<label class="block text-xs text-slate-400 mb-1">Cooldown (minutes)</label>
<input
id="antispam-cooldown"
type="number"
min="1"
max="1440"
class="w-full rounded-lg bg-slate-950 border border-slate-800 text-slate-100 px-3 py-2 text-sm focus:outline-none focus:border-blue-500"
/>
</div>
</div>
</div>
</div>
<!-- Per-user Webhook Delivery -->
+12
View File
@@ -26,6 +26,14 @@
background-color: rgba(59, 130, 246, 0.3);
border-color: rgba(59, 130, 246, 0.6);
}
.process-row.self-process {
background-color: rgba(234, 179, 8, 0.12);
border-color: rgba(234, 179, 8, 0.5);
box-shadow: inset 3px 0 0 0 #facc15;
}
.process-row.self-process.selected {
background-color: rgba(234, 179, 8, 0.28);
}
/* Dark scrollbar styling */
#process-list::-webkit-scrollbar {
width: 12px;
@@ -189,6 +197,10 @@
<i class="fa-solid fa-circle text-slate-200"></i>
<span class="text-slate-400">Other</span>
</div>
<div class="flex items-center gap-1.5">
<i class="fa-solid fa-crosshairs text-yellow-400"></i>
<span class="text-slate-400">Overlord Agent</span>
</div>
</div>
<!-- Process List -->