herowebv/src/agentui/templates/processes.html
2025-05-31 11:15:44 +03:00

159 lines
5.8 KiB
HTML

<html>
<head>
<title>Hero Agent UI - Processes</title>
<link rel="stylesheet" href="/static/css/style.css">
</head>
<body>
<header>
<h1>System Processes</h1>
<nav>
<a href="/">Dashboard</a>
<a href="/processes" class="active">Processes</a>
<a href="/jobs">Jobs</a>
<a href="/openrpc">OpenRPC</a>
</nav>
</header>
<main>
<div class="processes-container">
<div class="filter-controls">
<input type="text" id="process-search" placeholder="Search processes..." onkeyup="filterProcesses()">
<div class="sort-controls">
<label>Sort by:</label>
<select id="sort-field" onchange="sortProcesses()">
<option value="pid">PID</option>
<option value="name">Name</option>
<option value="cpu">CPU Usage</option>
<option value="memory">Memory Usage</option>
</select>
<button id="sort-direction" onclick="toggleSortDirection()"></button>
</div>
</div>
<table class="data-table" id="processes-table">
<thead>
<tr>
<th>PID</th>
<th>Name</th>
<th>CPU %</th>
<th>Memory (MB)</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@for process in processes
<tr>
<td>@process.pid</td>
<td>@process.name</td>
<td>@process.cpu</td>
<td>@process.memory</td>
<td>
<a href="/processes/@process.pid" class="btn btn-small">Details</a>
<button onclick="killProcess('@process.pid')" class="btn btn-small btn-danger">Kill</button>
</td>
</tr>
@end
</tbody>
</table>
</div>
</main>
<footer>
<p>&copy; 2025 Hero Agent System</p>
</footer>
<script src="/static/js/main.js"></script>
<script>
function killProcess(pid) {
if (confirm('Are you sure you want to kill process ' + pid + '?')) {
fetch(`/api/processes/${pid}/kill`, { method: 'POST' })
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Process killed successfully');
location.reload();
} else {
alert('Failed to kill process');
}
});
}
}
function filterProcesses() {
const input = document.getElementById('process-search');
const filter = input.value.toUpperCase();
const table = document.getElementById('processes-table');
const rows = table.getElementsByTagName('tr');
for (let i = 1; i < rows.length; i++) {
const nameCell = rows[i].getElementsByTagName('td')[1];
if (nameCell) {
const nameValue = nameCell.textContent || nameCell.innerText;
if (nameValue.toUpperCase().indexOf(filter) > -1) {
rows[i].style.display = '';
} else {
rows[i].style.display = 'none';
}
}
}
}
let sortAscending = true;
function toggleSortDirection() {
sortAscending = !sortAscending;
const button = document.getElementById('sort-direction');
button.textContent = sortAscending ? '↑' : '↓';
sortProcesses();
}
function sortProcesses() {
const table = document.getElementById('processes-table');
const rows = Array.from(table.getElementsByTagName('tr')).slice(1);
const sortField = document.getElementById('sort-field').value;
let columnIndex;
let isNumeric = false;
switch (sortField) {
case 'pid':
columnIndex = 0;
isNumeric = true;
break;
case 'name':
columnIndex = 1;
break;
case 'cpu':
columnIndex = 2;
isNumeric = true;
break;
case 'memory':
columnIndex = 3;
isNumeric = true;
break;
default:
columnIndex = 0;
isNumeric = true;
}
rows.sort((a, b) => {
const aValue = a.getElementsByTagName('td')[columnIndex].textContent;
const bValue = b.getElementsByTagName('td')[columnIndex].textContent;
if (isNumeric) {
return sortAscending
? parseFloat(aValue) - parseFloat(bValue)
: parseFloat(bValue) - parseFloat(aValue);
} else {
return sortAscending
? aValue.localeCompare(bValue)
: bValue.localeCompare(aValue);
}
});
const tbody = table.getElementsByTagName('tbody')[0];
rows.forEach(row => tbody.appendChild(row));
}
</script>
</body>
</html>