import { useCallback, useEffect, useMemo, useState } from "react"; import { api, type ManualTaskInput, type ServerRecord, type TaskRecord } from "../api/client"; import FilterBar, { type Filters } from "../components/FilterBar"; import ServerGroup from "../components/ServerGroup"; import TaskForm from "../components/TaskForm"; export default function Dashboard() { const [servers, setServers] = useState([]); const [tasks, setTasks] = useState([]); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const [filters, setFilters] = useState({ serverId: undefined, scheduleType: undefined, search: "", includeStale: false, }); const [formOpen, setFormOpen] = useState(false); const [editingTask, setEditingTask] = useState(null); const loadServers = useCallback(() => { return api.servers .list() .then((res) => setServers(res.servers)) .catch((err) => setError(String(err))); }, []); const loadTasks = useCallback(() => { return api.tasks .list(filters) .then((res) => { setTasks(res.tasks); setError(null); }) .catch((err) => setError(String(err))); }, [filters]); useEffect(() => { loadServers(); }, [loadServers]); useEffect(() => { setLoading(true); const handle = setTimeout(() => { loadTasks().finally(() => setLoading(false)); }, 200); return () => clearTimeout(handle); }, [loadTasks]); const groups = useMemo(() => { const byServer = new Map(); for (const task of tasks) { const entry = byServer.get(task.serverId) ?? { serverId: task.serverId, serverName: task.serverName, tasks: [], }; entry.tasks.push(task); byServer.set(task.serverId, entry); } return [...byServer.values()]; }, [tasks]); function openAddForm() { setEditingTask(null); setFormOpen(true); } function openEditForm(task: TaskRecord) { setEditingTask(task); setFormOpen(true); } function closeForm() { setFormOpen(false); setEditingTask(null); } async function handleFormSubmit(data: ManualTaskInput) { if (editingTask) { await api.tasks.update(editingTask.id, data); } else { await api.tasks.create(data); } closeForm(); await loadTasks(); } async function handleDelete(task: TaskRecord) { if (!confirm(`Delete "${task.name}"?`)) return; try { await api.tasks.remove(task.id); await loadTasks(); } catch (err) { setError(String(err)); } } return (
{formOpen && ( )} {error &&
{error}
} {loading &&
Loading tasks…
} {!loading && groups.length === 0 && (
No scheduled tasks found yet. Install the agent on a server to auto-report cron/systemd tasks, or use "Add task" above for things like Docker-based backup jobs.
)} {groups.map((group) => ( ))}
); }