import React, { useState, useEffect } from 'react'; import { listSchedules, createSchedule, deleteSchedule, ScheduledJob } from '../../schedule'; import BackButton from '../ui/BackButton'; import { ScrollArea } from '../ui/scroll-area'; import MoreMenuLayout from '../more_menu/MoreMenuLayout'; import { Card } from '../ui/card'; import { Button } from '../ui/button'; import { TrashIcon } from '../icons/TrashIcon'; import Plus from '../ui/Plus'; import { CreateScheduleModal, NewSchedulePayload } from './CreateScheduleModal'; import ScheduleDetailView from './ScheduleDetailView'; import cronstrue from 'cronstrue'; interface SchedulesViewProps { onClose: () => void; } const SchedulesView: React.FC = ({ onClose }) => { const [schedules, setSchedules] = useState([]); const [isLoading, setIsLoading] = useState(false); const [isSubmitting, setIsSubmitting] = useState(false); const [apiError, setApiError] = useState(null); const [submitApiError, setSubmitApiError] = useState(null); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [viewingScheduleId, setViewingScheduleId] = useState(null); const fetchSchedules = async () => { setIsLoading(true); setApiError(null); try { const fetchedSchedules = await listSchedules(); setSchedules(fetchedSchedules); } catch (error) { console.error('Failed to fetch schedules:', error); setApiError( error instanceof Error ? error.message : 'An unknown error occurred while fetching schedules.' ); } finally { setIsLoading(false); } }; useEffect(() => { if (viewingScheduleId === null) { fetchSchedules(); } }, [viewingScheduleId]); const handleOpenCreateModal = () => { setSubmitApiError(null); setIsCreateModalOpen(true); }; const handleCloseCreateModal = () => { setIsCreateModalOpen(false); setSubmitApiError(null); }; const handleCreateScheduleSubmit = async (payload: NewSchedulePayload) => { setIsSubmitting(true); setSubmitApiError(null); try { await createSchedule(payload); await fetchSchedules(); setIsCreateModalOpen(false); } catch (error) { console.error('Failed to create schedule:', error); const errorMessage = error instanceof Error ? error.message : 'Unknown error creating schedule.'; setSubmitApiError(errorMessage); } finally { setIsSubmitting(false); } }; const handleDeleteSchedule = async (idToDelete: string) => { if (!window.confirm(`Are you sure you want to delete schedule "${idToDelete}"?`)) return; if (viewingScheduleId === idToDelete) { setViewingScheduleId(null); } setIsLoading(true); setApiError(null); try { await deleteSchedule(idToDelete); await fetchSchedules(); } catch (error) { console.error(`Failed to delete schedule "${idToDelete}":`, error); setApiError( error instanceof Error ? error.message : `Unknown error deleting "${idToDelete}".` ); } finally { setIsLoading(false); } }; const handleNavigateToScheduleDetail = (scheduleId: string) => { setViewingScheduleId(scheduleId); }; const handleNavigateBackFromDetail = () => { setViewingScheduleId(null); }; const getReadableCron = (cronString: string) => { try { return cronstrue.toString(cronString); } catch (e) { console.warn(`Could not parse cron string "${cronString}":`, e); return cronString; } }; if (viewingScheduleId) { return ( ); } return (

Schedules Management

{apiError && (

Error: {apiError}

)}

Existing Schedules

{isLoading && schedules.length === 0 && (

Loading schedules...

)} {!isLoading && !apiError && schedules.length === 0 && (

No schedules found. Create one to get started!

)} {!isLoading && schedules.length > 0 && (
{schedules.map((job) => ( handleNavigateToScheduleDetail(job.id)} >

{job.id}

Source: {job.source}

Schedule: {getReadableCron(job.cron)}

Last Run:{' '} {job.last_run ? new Date(job.last_run).toLocaleString() : 'Never'}

))}
)}
); }; export default SchedulesView;