'use client'; /** * Add Monitor Dialog Component * * Dialog for selecting sources to monitor for updates. */ import { useState, useEffect } from 'react'; import { Search, Globe, FileText, Check, Clock, Zap } from 'lucide-react'; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { Badge } from '@/components/ui/badge'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from '@/components/ui/select'; import { useCreateMonitor, useMonitors } from '@/lib/hooks/use-monitoring'; import { Checkbox } from '@/components/ui/checkbox'; interface AddMonitorDialogProps { open: boolean; onOpenChange: (open: boolean) => void; } interface SourceAsset { file_path?: string; url?: string; } interface SourceItem { id: string; title: string; source_type?: string; asset_type?: string; asset?: SourceAsset; url?: string; } export function AddMonitorDialog({ open, onOpenChange }: AddMonitorDialogProps) { const [sources, setSources] = useState([]); const [loading, setLoading] = useState(false); const [searchQuery, setSearchQuery] = useState(''); const [selectedSources, setSelectedSources] = useState>(new Set()); const [frequency, setFrequency] = useState<'hourly' | 'daily' | 'weekly'>('daily'); const createMonitor = useCreateMonitor(); const { data: existingMonitors } = useMonitors(); // Fetch available sources useEffect(() => { if (open) { setLoading(true); fetch('/api/sources?limit=100') .then(res => res.json()) .then(data => { setSources(data || []); setLoading(false); }) .catch(err => { console.error('Failed to fetch sources:', err); setLoading(false); }); } }, [open]); // Filter sources that can be monitored (web sources) and not already monitored const monitoredSourceIds = new Set(existingMonitors?.map(m => m.source_id) || []); const availableSources = sources.filter(source => { // Only web-based sources can be monitored (has a URL) const sourceUrl = source.asset?.url || source.url; const isWebSource = source.source_type === 'url' || source.asset_type === 'web' || (sourceUrl && sourceUrl.length > 0); // Check if already being monitored const isAlreadyMonitored = monitoredSourceIds.has(source.id) || monitoredSourceIds.has(`source:${source.id.split(':')[1]}`); // Apply search filter const matchesSearch = !searchQuery || source.title?.toLowerCase().includes(searchQuery.toLowerCase()) || sourceUrl?.toLowerCase().includes(searchQuery.toLowerCase()); return isWebSource && !isAlreadyMonitored && matchesSearch; }); const handleToggleSource = (sourceId: string) => { const newSelected = new Set(selectedSources); if (newSelected.has(sourceId)) { newSelected.delete(sourceId); } else { newSelected.add(sourceId); } setSelectedSources(newSelected); }; const handleSelectAll = () => { if (selectedSources.size === availableSources.length) { setSelectedSources(new Set()); } else { setSelectedSources(new Set(availableSources.map(s => s.id))); } }; const handleAddMonitors = async () => { const sourceIds = Array.from(selectedSources); for (const sourceId of sourceIds) { await createMonitor.mutateAsync({ source_id: sourceId, check_frequency: frequency, enabled: true, }); } setSelectedSources(new Set()); onOpenChange(false); }; const getSourceIcon = (source: SourceItem) => { const hasUrl = source.source_type === 'url' || source.asset?.url || source.url; if (hasUrl) { return ; } return ; }; const getSourceUrl = (source: SourceItem) => { return source.asset?.url || source.url || ''; }; return ( Add Source Monitors Select web sources to monitor for changes. You'll be notified when content updates.
{/* Search and Frequency */}
setSearchQuery(e.target.value)} className="pl-10" />
{/* Source List */} {loading ? (
Loading sources...
) : availableSources.length === 0 ? (

No web sources available

{sources.length === 0 ? 'Add some web sources to your notebooks first' : 'All web sources are already being monitored'}

) : (
{/* Select All Header */}
0} onCheckedChange={handleSelectAll} /> Select All ({availableSources.length} sources)
{/* Source Items */} {availableSources.map((source) => { const sourceUrl = getSourceUrl(source); return (
handleToggleSource(source.id)} > handleToggleSource(source.id)} />
{getSourceIcon(source)}

{source.title || 'Untitled Source'}

{sourceUrl && (

{sourceUrl}

)}
{selectedSources.has(source.id) && ( )}
); })}
)}
{/* Footer */}
{selectedSources.size > 0 ? ( {selectedSources.size} source{selectedSources.size > 1 ? 's' : ''} selected ) : ( Select sources to monitor )}
); }