/** * Cron State Store * Manages scheduled task state */ import { defineStore } from 'pinia'; import { ref, computed } from 'vue'; import { hostApiFetch } from '@lib/host-api'; import type { CronJob, CronJobCreateInput, CronJobUpdateInput } from '@lib/cron-types'; export const MOCK_CRON_JOBS: CronJob[] = []; export const useCronStore = defineStore('cron', () => { const jobs = ref([]); const loading = ref(false); const error = ref(null); const safeJobs = computed(() => (Array.isArray(jobs.value) ? jobs.value : [])); const activeJobs = computed(() => safeJobs.value.filter((j) => j.enabled)); const pausedJobs = computed(() => safeJobs.value.filter((j) => !j.enabled)); const failedJobs = computed(() => safeJobs.value.filter((j) => j.lastRun && !j.lastRun.success)); const fetchJobs = async () => { const currentJobs = safeJobs.value; if (currentJobs.length === 0) { loading.value = true; } error.value = null; try { const result = await hostApiFetch('/api/cron/jobs'); jobs.value = result; } catch (err) { error.value = err instanceof Error ? err.message : String(err); // Fallback to mock data on error for demo/development jobs.value = MOCK_CRON_JOBS; } finally { loading.value = false; } }; const createJob = async (input: CronJobCreateInput) => { const job: CronJob = { id: `local-${Date.now()}`, ...input, enabled: input.enabled ?? true, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; try { const result = await hostApiFetch('/api/cron/jobs', { method: 'POST', body: JSON.stringify(input), }); jobs.value = [...safeJobs.value, result]; return result; } catch (err) { console.warn('Failed to create cron job via API, using local fallback:', err); jobs.value = [...safeJobs.value, job]; return job; } }; const updateJob = async (id: string, input: CronJobUpdateInput) => { try { const updatedJob = await hostApiFetch(`/api/cron/jobs/${encodeURIComponent(id)}`, { method: 'PUT', body: JSON.stringify(input), }); jobs.value = safeJobs.value.map((job) => (job.id === id ? updatedJob : job)); } catch (err) { console.warn('Failed to update cron job via API, using local fallback:', err); jobs.value = safeJobs.value.map((job) => job.id === id ? { ...job, ...input, updatedAt: new Date().toISOString() } : job, ); } }; const deleteJob = async (id: string) => { try { await hostApiFetch(`/api/cron/jobs/${encodeURIComponent(id)}`, { method: 'DELETE', }); } catch (err) { console.warn('Failed to delete cron job via API, using local fallback:', err); } jobs.value = safeJobs.value.filter((job) => job.id !== id); }; const toggleJob = async (id: string, enabled: boolean) => { try { await hostApiFetch('/api/cron/toggle', { method: 'POST', body: JSON.stringify({ id, enabled }), }); } catch (err) { console.warn('Failed to toggle cron job via API, using local fallback:', err); } jobs.value = safeJobs.value.map((job) => job.id === id ? { ...job, enabled, updatedAt: new Date().toISOString() } : job, ); }; const triggerJob = async (id: string) => { try { const result = await hostApiFetch('/api/cron/trigger', { method: 'POST', body: JSON.stringify({ id }), }); console.log('Cron trigger result:', result); } catch (err) { console.warn('Failed to trigger cron job via API, using local fallback:', err); } // Update lastRun locally as fallback jobs.value = safeJobs.value.map((job) => job.id === id ? { ...job, lastRun: { time: new Date().toISOString(), success: true, }, updatedAt: new Date().toISOString(), } : job, ); }; return { jobs, loading, error, safeJobs, activeJobs, pausedJobs, failedJobs, fetchJobs, createJob, updateJob, deleteJob, toggleJob, triggerJob, }; });