From 1275a946927f0861ef79e541a1df695ca8f281cb Mon Sep 17 00:00:00 2001 From: Zac Gaetano Date: Sat, 4 Apr 2026 22:40:51 -0400 Subject: [PATCH] Add frontend/src/App.jsx --- frontend/src/App.jsx | 403 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 403 insertions(+) create mode 100644 frontend/src/App.jsx diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx new file mode 100644 index 0000000..2827207 --- /dev/null +++ b/frontend/src/App.jsx @@ -0,0 +1,403 @@ +import React, { useState, useEffect } from 'react'; +import './App.css'; + +const App = () => { + const [tasks, setTasks] = useState([]); + const [selectedTask, setSelectedTask] = useState(null); + const [showForm, setShowForm] = useState(false); + const [formData, setFormData] = useState({ + name: '', + description: '', + prompt: '', + schedule_type: 'manual', + schedule_value: '', + enabled: true + }); + const [systemInfo, setSystemInfo] = useState(null); + const [loading, setLoading] = useState(false); + + // Fetch tasks on component mount + useEffect(() => { + fetchTasks(); + fetchSystemInfo(); + const interval = setInterval(() => { + fetchTasks(); + fetchSystemInfo(); + }, 5000); // Refresh every 5 seconds + return () => clearInterval(interval); + }, []); + + const fetchTasks = async () => { + try { + const response = await fetch('/api/tasks'); + const data = await response.json(); + setTasks(data); + } catch (error) { + console.error('Error fetching tasks:', error); + } + }; + + const fetchSystemInfo = async () => { + try { + const response = await fetch('/api/system/info'); + const data = await response.json(); + setSystemInfo(data); + } catch (error) { + console.error('Error fetching system info:', error); + } + }; + + const handleCreateTask = async (e) => { + e.preventDefault(); + setLoading(true); + + try { + const response = await fetch('/api/tasks', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(formData) + }); + + if (response.ok) { + await fetchTasks(); + setShowForm(false); + setFormData({ + name: '', + description: '', + prompt: '', + schedule_type: 'manual', + schedule_value: '', + enabled: true + }); + } + } catch (error) { + console.error('Error creating task:', error); + } + + setLoading(false); + }; + + const handleRunTask = async (taskId) => { + try { + const response = await fetch(`/api/tasks/${taskId}/run`, { + method: 'POST' + }); + const data = await response.json(); + console.log('Task started:', data); + await fetchTasks(); + } catch (error) { + console.error('Error running task:', error); + } + }; + + const handleDeleteTask = async (taskId) => { + if (confirm('Delete this task?')) { + try { + await fetch(`/api/tasks/${taskId}`, { method: 'DELETE' }); + await fetchTasks(); + setSelectedTask(null); + } catch (error) { + console.error('Error deleting task:', error); + } + } + }; + + const getStatusColor = (status) => { + switch (status) { + case 'running': return '#3498db'; + case 'completed': return '#27ae60'; + case 'failed': return '#e74c3c'; + default: return '#95a5a6'; + } + }; + + return ( +
+
+
+

Claude Persistent Agent

+

Scheduled task management & Claude Code runner

+
+ {systemInfo && ( +
+ + {systemInfo.task_count} tasks +
+ )} +
+ +
+ + +
+ {showForm ? ( +
+

Create New Task

+
+
+ + setFormData({ ...formData, name: e.target.value })} + placeholder="e.g., Daily Backup" + /> +
+ +
+ +