92 lines
3.4 KiB
JavaScript
92 lines
3.4 KiB
JavaScript
async function fetchJSON(url, opts) {
|
|
const res = await fetch(url, opts);
|
|
return res.json();
|
|
}
|
|
|
|
async function loadStatuses() {
|
|
const table = document.getElementById('servicesTable');
|
|
table.innerHTML = '<tr><td colspan="4">Loading...</td></tr>';
|
|
try {
|
|
const data = await fetchJSON('/api/statuses');
|
|
table.innerHTML = '';
|
|
for (const r of data.results || []) {
|
|
const tr = document.createElement('tr');
|
|
const activeLine = r.parsed?.active || 'Unknown';
|
|
const isRunning = /Active:\s+active/i.test(activeLine) && /\(running\)/i.test(activeLine);
|
|
const isFailed = /Active:\s+(failed|inactive)/i.test(activeLine) || /\(dead\)/i.test(activeLine);
|
|
const statusClass = isRunning ? 'ok' : (isFailed ? 'bad' : '');
|
|
const portsText = Array.isArray(r.ports) && r.ports.length ? r.ports.join(', ') : '';
|
|
tr.innerHTML = `
|
|
<td>${r.name}</td>
|
|
<td><span class=\"status ${statusClass}\">${activeLine}</span></td>
|
|
<td>${portsText}</td>
|
|
<td>${r.parsed?.pid || ''}</td>
|
|
<td class=\"controls\">
|
|
<button data-name=\"${r.name}\" class=\"view-logs\">View Logs</button>
|
|
<button data-name=\"${r.name}\" class=\"view-status\">Raw Status</button>
|
|
</td>
|
|
`;
|
|
table.appendChild(tr);
|
|
}
|
|
wireButtons();
|
|
} catch (err) {
|
|
table.innerHTML = `<tr><td colspan="4">Error: ${err}</td></tr>`;
|
|
}
|
|
}
|
|
|
|
function wireButtons() {
|
|
document.querySelectorAll('.view-logs').forEach(btn => {
|
|
btn.addEventListener('click', async () => {
|
|
const name = btn.getAttribute('data-name');
|
|
const data = await fetchJSON(`/api/logs?name=${encodeURIComponent(name)}&n=100`);
|
|
document.getElementById('logs').value = data.logs || JSON.stringify(data, null, 2);
|
|
});
|
|
});
|
|
document.querySelectorAll('.view-status').forEach(btn => {
|
|
btn.addEventListener('click', async () => {
|
|
const name = btn.getAttribute('data-name');
|
|
const data = await fetchJSON(`/api/status?name=${encodeURIComponent(name)}`);
|
|
document.getElementById('logs').value = data.raw || JSON.stringify(data, null, 2);
|
|
});
|
|
});
|
|
}
|
|
|
|
async function addService() {
|
|
const nameInput = document.getElementById('serviceName');
|
|
const name = nameInput.value.trim();
|
|
if (!name.endsWith('.service')) {
|
|
alert('Service name must end with .service');
|
|
return;
|
|
}
|
|
const data = await fetchJSON('/api/services', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ name }),
|
|
});
|
|
nameInput.value = '';
|
|
await loadStatuses();
|
|
}
|
|
|
|
let autoRefreshTimer = null;
|
|
|
|
function updateAutoRefresh() {
|
|
const enabled = document.getElementById('autoRefreshToggle').checked;
|
|
const intervalSec = Number(document.getElementById('autoRefreshInterval').value || '10');
|
|
if (autoRefreshTimer) {
|
|
clearInterval(autoRefreshTimer);
|
|
autoRefreshTimer = null;
|
|
}
|
|
if (enabled) {
|
|
autoRefreshTimer = setInterval(loadStatuses, intervalSec * 1000);
|
|
}
|
|
}
|
|
|
|
window.addEventListener('DOMContentLoaded', () => {
|
|
document.getElementById('refresh').addEventListener('click', loadStatuses);
|
|
document.getElementById('addService').addEventListener('click', addService);
|
|
document.getElementById('autoRefreshToggle').addEventListener('change', updateAutoRefresh);
|
|
document.getElementById('autoRefreshInterval').addEventListener('change', updateAutoRefresh);
|
|
loadStatuses();
|
|
updateAutoRefresh();
|
|
});
|