import { html, nothing } from 'lit'; import { LightElement } from '../../lib/base.js'; import { toString as cronToString } from 'cronstrue'; import { formatDate } from './utils.js'; export class ScheduledTasksSection extends LightElement { static properties = { _jobs: { state: true }, _error: { state: true }, }; constructor() { super(); this._jobs = []; this._error = null; } 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(); // one-shot scheduled or async/immediate, still active (pending or running) this._jobs = all.filter(j => (j.kind !== 'cron' || j.single_run) && (j.enabled || j.running_session_id != null) ); } catch (e) { this._error = e.message; } } async _delete(job) { if (!confirm(`Delete task "${job.title}"?`)) return; try { const res = await fetch(`/api/cron/jobs/${job.id}`, { method: 'DELETE' }); if (!res.ok) throw new Error(await res.text()); await this.load(); } catch (e) { this._error = e.message; } } _statusBadge(job) { if (job.running_session_id != null) return html`running`; if (job.kind === 'cron' && job.single_run) return html`pending`; return html`queued`; } _kindLabel(job) { if (job.kind === 'cron' && job.single_run) return html`one-shot`; if (job.kind === 'async') return html`async`; return nothing; } _renderCard(job) { return html`
${job.title} ${this._kindLabel(job)} ${this._statusBadge(job)}
${job.description ? html`
${job.description}
` : nothing} ${job.kind === 'cron' && job.cron ? html`
${cronToString(job.cron)} ${job.cron}
` : nothing}
Agent ${job.agent_id}
${job.next_run_at ? 'Scheduled at' : 'Created'} ${formatDate(job.next_run_at || job.created_at)}
`; } render() { return html`

Scheduled Tasks

${this._jobs.length} task${this._jobs.length !== 1 ? 's' : ''}
${this._error ? html`
${this._error}
` : nothing} ${this._jobs.length === 0 ? html`

No pending or running tasks.

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