/* 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 = [];
},
});
})();