big update

This commit is contained in:
KingKDot
2026-05-21 09:51:12 -05:00
parent 24a023f400
commit b693cbbbf5
23 changed files with 2011 additions and 251 deletions
+82 -8
View File
@@ -13,6 +13,12 @@ let sortField = "cpu";
let sortDirection = "desc";
let searchTerm = "";
const procIconCache = new Map();
const procIconQueue = [];
let procIconFlushScheduled = false;
const PROC_ICON_BATCH_SIZE = 32;
const PROC_ICON_BATCH_DELAY_MS = 60;
const statusEl = document.getElementById("status-indicator");
const processCountEl = document.getElementById("process-count");
const processListEl = document.getElementById("process-list");
@@ -107,6 +113,9 @@ function handleMessage(msg) {
case "process_list_result":
handleProcessList(msg);
break;
case "process_icon_result":
handleProcessIconResult(msg);
break;
case "command_result":
handleCommandResult(msg);
break;
@@ -148,6 +157,7 @@ function handleProcessList(msg) {
updateStatus("connected", "Connected");
buildProcessTree();
renderProcesses();
requestProcessIcons(processes);
}
function buildProcessTree() {
@@ -314,22 +324,31 @@ function rowInnerHtml(proc, depth) {
}
let nameColor = "text-slate-200";
let iconClass = "fa-microchip";
let iconColor = "text-blue-400";
let fallbackIcon = "fa-microchip";
let fallbackColor = "text-blue-400";
if (proc.type === "system") {
nameColor = "text-purple-400";
iconColor = "text-purple-400";
fallbackColor = "text-purple-400";
} else if (proc.type === "service") {
nameColor = "text-cyan-400";
iconColor = "text-cyan-400";
fallbackColor = "text-cyan-400";
} else if (proc.type === "own") {
nameColor = "text-green-300";
iconColor = "text-green-400";
fallbackColor = "text-green-400";
}
if (proc.self) {
nameColor = "text-yellow-300 font-semibold";
iconClass = "fa-crosshairs";
iconColor = "text-yellow-400";
fallbackIcon = "fa-crosshairs";
fallbackColor = "text-yellow-400";
}
const iconKey = procIconKey(proc);
const cached = iconKey ? procIconCache.get(iconKey) : null;
let procIcon;
if (cached && cached.blobUrl) {
procIcon = `<span class="inline-flex w-4 h-4 items-center justify-center shrink-0" data-proc-icon-key="${escapeHtml(iconKey)}"><img src="${cached.blobUrl}" class="w-4 h-4 object-contain pointer-events-none" alt="" draggable="false"></span>`;
} else {
procIcon = `<span class="inline-flex w-4 h-4 items-center justify-center shrink-0"${iconKey ? ` data-proc-icon-key="${escapeHtml(iconKey)}"` : ""}><i class="fa-solid ${fallbackIcon} ${fallbackColor}"></i></span>`;
}
const selfBadge = proc.self
@@ -339,7 +358,7 @@ function rowInnerHtml(proc, depth) {
return `
<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 ${iconClass} ${iconColor}"></i>
${indent}${treeIcon}${procIcon}
<span class="truncate ${nameColor}">${escapeHtml(proc.name)}</span>${selfBadge}
</div>
<div class="col-span-2 text-sm ${cpuColor} font-semibold">${displayCpu.toFixed(1)}%</div>
@@ -615,6 +634,61 @@ setInterval(() => {
}
}, 3000);
function procIconKey(proc) {
if (!proc.exePath) return null;
return proc.exePath.toLowerCase();
}
function requestProcessIcons(procs) {
for (const proc of procs) {
const key = procIconKey(proc);
if (!key) continue;
if (procIconCache.has(key)) continue;
procIconCache.set(key, { pending: true });
procIconQueue.push({ key, path: proc.exePath });
}
if (procIconQueue.length > 0) scheduleProcIconFlush();
}
function scheduleProcIconFlush() {
if (procIconFlushScheduled) return;
procIconFlushScheduled = true;
setTimeout(flushProcIconQueue, PROC_ICON_BATCH_DELAY_MS);
}
function flushProcIconQueue() {
procIconFlushScheduled = false;
if (procIconQueue.length === 0) return;
const batch = procIconQueue.splice(0, PROC_ICON_BATCH_SIZE);
send({ type: "process_icon", items: batch });
if (procIconQueue.length > 0) scheduleProcIconFlush();
}
function handleProcessIconResult(msg) {
const items = Array.isArray(msg.icons) ? msg.icons : [];
for (const item of items) {
if (!item || !item.key) continue;
const entry = procIconCache.get(item.key) || {};
entry.pending = false;
if (item.png && item.png.length > 0) {
const blob = new Blob([item.png], { type: "image/png" });
entry.blobUrl = URL.createObjectURL(blob);
} else {
entry.failed = true;
}
procIconCache.set(item.key, entry);
applyProcIconToDom(item.key, entry);
}
}
function applyProcIconToDom(key, entry) {
if (!entry || !entry.blobUrl) return;
const escaped = (typeof CSS !== "undefined" && CSS.escape) ? CSS.escape(key) : key.replace(/"/g, '\\"');
document.querySelectorAll(`[data-proc-icon-key="${escaped}"]`).forEach((el) => {
el.innerHTML = `<img src="${entry.blobUrl}" class="w-4 h-4 object-contain pointer-events-none" alt="" draggable="false">`;
});
}
updateStatus("connecting", "Connecting...");
checkFeatureAccess("processes", clientId).then(ok => ok && connect());
updateSortIndicators();