import { useEffect, useState } from 'react'; interface Watcher { id: string; path: string; intervalMs: number; enabled: boolean; createdAt: number; active: boolean; lastScan: number; fileCount: number; isScanning: boolean; } const cardStyle: React.CSSProperties = { background: '#16213e', borderRadius: '8px', padding: '1.5rem', marginBottom: '1rem', }; const buttonStyle: React.CSSProperties = { padding: '0.5rem 1rem', background: '#0f3460', color: '#fff', border: 'none', borderRadius: '4px', cursor: 'pointer', marginRight: '0.5rem', }; const dangerButtonStyle: React.CSSProperties = { ...buttonStyle, background: '#7f1d1d', }; const inputStyle: React.CSSProperties = { width: '100%', padding: '0.5rem', marginBottom: '0.5rem', background: '#1a1a2e', border: '1px solid #0f3460', borderRadius: '4px', color: '#fff', }; function formatTimeAgo(timestamp: number): string { if (!timestamp) return 'Never'; const seconds = Math.floor((Date.now() - timestamp) / 1000); if (seconds < 60) return `${seconds}s ago`; const minutes = Math.floor(seconds / 60); if (minutes < 60) return `${minutes}m ago`; const hours = Math.floor(minutes / 60); if (hours < 24) return `${hours}h ago`; return new Date(timestamp).toLocaleDateString(); } export default function Watchers() { const [watchers, setWatchers] = useState([]); const [loading, setLoading] = useState(true); const [showForm, setShowForm] = useState(false); const [editingId, setEditingId] = useState(null); const [formData, setFormData] = useState({ path: '', intervalMs: 30000, enabled: true, }); const [scanning, setScanning] = useState(null); const [scanningAll, setScanningAll] = useState(false); const fetchWatchers = async () => { try { const res = await fetch('/api/watchers'); if (res.ok) { const data = await res.json(); setWatchers(data.watchers || []); } } catch (err) { console.error('Failed to fetch watchers:', err); } finally { setLoading(false); } }; useEffect(() => { fetchWatchers(); const interval = setInterval(fetchWatchers, 5000); return () => clearInterval(interval); }, []); const handleCreate = async (e: React.FormEvent) => { e.preventDefault(); const body = { path: formData.path, intervalMs: formData.intervalMs, enabled: formData.enabled, }; const res = await fetch('/api/watchers', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (res.ok) { setShowForm(false); setFormData({ path: '', intervalMs: 30000, enabled: true }); fetchWatchers(); } }; const handleUpdate = async (e: React.FormEvent) => { e.preventDefault(); if (!editingId) return; const body = { path: formData.path, intervalMs: formData.intervalMs, enabled: formData.enabled, }; const res = await fetch(`/api/watchers/${editingId}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), }); if (res.ok) { setEditingId(null); setFormData({ path: '', intervalMs: 30000, enabled: true }); fetchWatchers(); } }; const handleDelete = async (id: string) => { if (!confirm('Are you sure you want to delete this watcher?')) return; await fetch(`/api/watchers/${id}`, { method: 'DELETE' }); fetchWatchers(); }; const handleScan = async (id: string) => { setScanning(id); try { await fetch(`/api/watchers/${id}/scan`, { method: 'POST' }); fetchWatchers(); } finally { setScanning(null); } }; const handleScanAll = async () => { setScanningAll(true); try { await fetch('/api/watchers/scan-all', { method: 'POST' }); fetchWatchers(); } finally { setScanningAll(false); } }; const handleToggleEnabled = async (id: string, enabled: boolean) => { await fetch(`/api/watchers/${id}`, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ enabled }), }); fetchWatchers(); }; const startEdit = (watcher: Watcher) => { setEditingId(watcher.id); setFormData({ path: watcher.path, intervalMs: watcher.intervalMs, enabled: watcher.enabled, }); setShowForm(false); }; const cancelEdit = () => { setEditingId(null); setFormData({ path: '', intervalMs: 30000, enabled: true }); }; if (loading) return
Loading...
; return (

Watchers

{showForm && (

Add New Watcher

setFormData({ ...formData, path: e.target.value })} required />
setFormData({ ...formData, intervalMs: parseInt(e.target.value) * 1000 || 30000 })} /> seconds
)} {watchers.length === 0 ? (

No watchers configured. Click "Add Watcher" to get started.

) : ( watchers.map((watcher) => (
{editingId === watcher.id ? (

Edit Watcher

setFormData({ ...formData, path: e.target.value })} required />
setFormData({ ...formData, intervalMs: parseInt(e.target.value) * 1000 || 30000 })} /> seconds
) : (

{watcher.path}

Interval: {watcher.intervalMs / 1000}s {' | '} Last scan: {formatTimeAgo(watcher.lastScan)} {watcher.fileCount > 0 && ` | ${watcher.fileCount} files`}

Status:{' '} {watcher.isScanning ? ( Scanning... ) : watcher.active ? ( Active ) : watcher.enabled ? ( Pending ) : ( Disabled )}

)}
)) )}
); }