async function fetchJSON(url, opts) { const res = await fetch(url, opts); return res.json(); } async function loadStatuses() { const table = document.getElementById('servicesTable'); table.innerHTML = 'Loading...'; 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 = ` ${r.name} ${activeLine} ${portsText} ${r.parsed?.pid || ''} `; table.appendChild(tr); } wireButtons(); } catch (err) { table.innerHTML = `Error: ${err}`; } } 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(); });