import { html, nothing } from 'lit'; import { LightElement } from '../../lib/base.js'; import { formatDate, formatElapsed } from './utils.js'; export class RunningTasksSection extends LightElement { static properties = { _jobs: { state: true }, _error: { state: true }, _tick: { state: true }, _killing: { state: true }, }; constructor() { super(); this._jobs = []; this._error = null; this._tick = 0; this._killing = new Set(); this._timer = null; this._pollTimer = null; } connectedCallback() { super.connectedCallback(); this._timer = setInterval(() => { this._tick++; }, 1000); this._pollTimer = setInterval(() => this.load(), 10000); } disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._timer); clearInterval(this._pollTimer); } async load() { this._error = null; try { const res = await fetch('/api/cron/jobs'); if (!res.ok) throw new Error(`HTTP ${res.status}`); const all = await res.json(); this._jobs = all.filter(j => j.running_session_id != null); } catch (e) { this._error = e.message; } } async _kill(job) { const confirmed = window.confirm( `Terminate task "${job.title}"?\n\nThe task will be stopped immediately and recorded as failed.` ); if (!confirmed) return; this._killing = new Set([...this._killing, job.id]); try { const res = await fetch(`/api/cron/jobs/${job.id}/kill`, { method: 'POST' }); if (!res.ok) { const text = await res.text(); throw new Error(text || `HTTP ${res.status}`); } await this.load(); } catch (e) { this._error = `Failed to terminate task: ${e.message}`; } finally { const next = new Set(this._killing); next.delete(job.id); this._killing = next; } } _kindLabel(job) { if (job.kind === 'cron' && !job.single_run) return html`cron`; if (job.kind === 'cron' && job.single_run) return html`one-shot`; return html`async`; } _renderCard(job) { const killing = this._killing.has(job.id); return html`
${job.title} ${this._kindLabel(job)} running
${job.description ? html`
${job.description}
` : nothing}
${formatElapsed(job.running_since)} since ${formatDate(job.running_since)}
Agent ${job.agent_id}
`; } render() { void this._tick; // drives re-render every second for live elapsed time return html`

Running Tasks

${this._jobs.length} running
${this._error ? html`
${this._error}
` : nothing} ${this._jobs.length === 0 ? html`

No tasks currently running.

` : html`
${this._jobs.map(j => this._renderCard(j))}
`}
`; } }