const API_BASE = window.location.origin; // ── Fetch ───────────────────────────────────────────────────────────────────── async function fetchTasks() { const res = await fetch(`${API_BASE}/api/tasks`); if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json(); } // ── Render ──────────────────────────────────────────────────────────────────── function formatDate(iso) { if (!iso) return ''; return new Date(iso).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }); } function createTaskCard(task) { const card = document.createElement('div'); card.className = 'task-card'; card.dataset.taskId = task.id; // Header: name + state badge const header = document.createElement('div'); header.className = 'task-card-header'; const name = document.createElement('span'); name.className = 'task-name'; name.textContent = task.name; const badge = document.createElement('span'); badge.className = 'state-badge'; badge.dataset.state = task.state; badge.textContent = task.state.replace(/_/g, ' '); header.append(name, badge); card.appendChild(header); // Meta: priority + created_at const meta = document.createElement('div'); meta.className = 'task-meta'; if (task.priority) { const prio = document.createElement('span'); prio.textContent = task.priority; meta.appendChild(prio); } if (task.created_at) { const when = document.createElement('span'); when.textContent = formatDate(task.created_at); meta.appendChild(when); } if (meta.children.length) card.appendChild(meta); // Description (truncated via CSS) if (task.description) { const desc = document.createElement('div'); desc.className = 'task-description'; desc.textContent = task.description; card.appendChild(desc); } // Footer: Run button (only for PENDING / FAILED) if (task.state === 'PENDING' || task.state === 'FAILED') { const footer = document.createElement('div'); footer.className = 'task-card-footer'; const btn = document.createElement('button'); btn.className = 'btn-run'; btn.textContent = 'Run'; btn.addEventListener('click', () => handleRun(task.id, btn, footer)); footer.appendChild(btn); card.appendChild(footer); } return card; } function renderTaskList(tasks) { const container = document.querySelector('.task-list'); if (!tasks || tasks.length === 0) { container.innerHTML = '