import { html, nothing } from 'lit'; import { LightElement } from '../../lib/base.js'; import { toString as cronToString } from 'cronstrue'; import { formatDate } from './utils.js'; export class CronJobsSection 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 allJobs = await res.json(); this._jobs = allJobs.filter(j => j.kind === 'cron' && !j.single_run); } catch (e) { this._error = e.message; } } async _delete(job) { if (!confirm(`Delete job "${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; } } async _toggle(job) { try { const res = await fetch(`/api/cron/jobs/${job.id}/toggle`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled: !job.enabled }), }); 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.enabled) return html`disabled`; return html`idle`; } _renderCard(job) { return html`
${job.title} ${this._statusBadge(job)}
${job.description ? html`
${job.description}
` : nothing}
${cronToString(job.cron)} ${job.cron}
Agent ${job.agent_id}
Last run ${formatDate(job.last_run_at)}
Next run ${formatDate(job.next_run_at)}
`; } render() { return html`

Cron Jobs

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

No recurring cron jobs. Ask the agent to create one with execute_task.

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