/* Atlus — Task Manager app */ (function () { 'use strict'; let container = null; let listEl = null; let searchInput = null; let processes = []; let sortCol = 'cpu'; let sortDir = -1; // -1 = desc, 1 = asc let refreshInterval = null; async function loadProcesses() { try { const res = await Atlus.apiFetch('/api/processes'); if (!res.ok) return; processes = await res.json(); renderProcesses(); } catch (e) {} } function renderProcesses() { if (!listEl) return; const query = searchInput ? searchInput.value.toLowerCase() : ''; let filtered = processes; if (query) { filtered = filtered.filter(p => p.name.toLowerCase().includes(query) || String(p.pid).includes(query) || (p.user && p.user.toLowerCase().includes(query)) ); } // Sort filtered.sort((a, b) => { const av = a[sortCol] ?? 0; const bv = b[sortCol] ?? 0; if (typeof av === 'string') return av.localeCompare(bv) * sortDir; return (av - bv) * sortDir; }); // Summary const totalCpu = processes.reduce((s, p) => s + (p.cpu || 0), 0); const totalMem = processes.reduce((s, p) => s + (p.mem || 0), 0); const summaryEl = container.querySelector('.tasks-summary'); if (summaryEl) { summaryEl.innerHTML = `
PROCESSES ${processes.length}
CPU ${totalCpu.toFixed(1)}%
MEM ${totalMem.toFixed(1)}%
`; } listEl.innerHTML = ''; // Header const header = document.createElement('div'); header.className = 'tasks-header'; const cols = [ { key: 'pid', label: 'PID' }, { key: 'name', label: 'NAME' }, { key: 'user', label: 'USER' }, { key: 'cpu', label: 'CPU %' }, { key: 'mem', label: 'MEM %' }, { key: 'status', label: 'STATUS' }, { key: '', label: '' }, ]; cols.forEach(col => { const span = document.createElement('span'); span.textContent = col.label; if (col.key === sortCol) span.classList.add('sorted'); if (col.key) { span.addEventListener('click', () => { if (sortCol === col.key) sortDir *= -1; else { sortCol = col.key; sortDir = -1; } renderProcesses(); }); } header.appendChild(span); }); listEl.appendChild(header); filtered.forEach(proc => { const row = document.createElement('div'); row.className = 'proc-row'; row.innerHTML = ` ${proc.pid} ${proc.name} ${proc.user || '--'} ${(proc.cpu || 0).toFixed(1)} ${(proc.mem || 0).toFixed(1)} ${proc.status} `; const killBtn = row.querySelector('.proc-kill'); killBtn.addEventListener('click', async () => { if (!confirm(`Kill process ${proc.name} (PID ${proc.pid})?`)) return; await Atlus.apiFetch('/api/processes/signal', { method: 'POST', body: { pid: proc.pid, signal: 'SIGTERM' }, }); setTimeout(loadProcesses, 500); }); listEl.appendChild(row); }); } Atlus.registerApp('tasks', { title: 'Task Manager', init(el) { container = el; container.classList.add('app-tasks'); // Summary const summary = document.createElement('div'); summary.className = 'tasks-summary'; container.appendChild(summary); // Toolbar const toolbar = document.createElement('div'); toolbar.className = 'tasks-toolbar'; searchInput = document.createElement('input'); searchInput.className = 'tasks-search'; searchInput.type = 'text'; searchInput.placeholder = 'Filter processes…'; searchInput.addEventListener('input', renderProcesses); toolbar.appendChild(searchInput); container.appendChild(toolbar); // List listEl = document.createElement('div'); listEl.className = 'tasks-list'; container.appendChild(listEl); loadProcesses(); refreshInterval = setInterval(loadProcesses, 3000); }, destroy() { if (refreshInterval) clearInterval(refreshInterval); refreshInterval = null; container = null; listEl = null; searchInput = null; processes = []; }, }); })();