"use client"; import { X } from "lucide-react"; import { useCallback, useEffect, useMemo, useState } from "react"; import { toast } from "sonner"; import { Button } from "@/components/ui/button"; import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Spinner } from "@/components/ui/spinner"; import { Switch } from "@/components/ui/switch"; import { documentsApiService } from "@/lib/apis/documents-api.service"; import { getSupportedExtensionsSet } from "@/lib/supported-extensions"; export interface SelectedFolder { path: string; name: string; } interface FolderWatchDialogProps { open: boolean; onOpenChange: (open: boolean) => void; searchSpaceId: number; onSuccess?: () => void; initialFolder?: SelectedFolder | null; } const DEFAULT_EXCLUDE_PATTERNS = [ ".git", "node_modules", "__pycache__", ".DS_Store", ".obsidian", ".trash", ]; export function FolderWatchDialog({ open, onOpenChange, searchSpaceId, onSuccess, initialFolder, }: FolderWatchDialogProps) { const [selectedFolder, setSelectedFolder] = useState(null); const [shouldSummarize, setShouldSummarize] = useState(false); const [submitting, setSubmitting] = useState(false); useEffect(() => { if (open && initialFolder) { setSelectedFolder(initialFolder); } }, [open, initialFolder]); const supportedExtensions = useMemo(() => Array.from(getSupportedExtensionsSet()), []); const handleSelectFolder = useCallback(async () => { const api = window.electronAPI; if (!api?.selectFolder) return; const folderPath = await api.selectFolder(); if (!folderPath) return; const folderName = folderPath.split("/").pop() || folderPath.split("\\").pop() || folderPath; setSelectedFolder({ path: folderPath, name: folderName }); }, []); const handleSubmit = useCallback(async () => { if (!selectedFolder) return; const api = window.electronAPI; if (!api) return; setSubmitting(true); try { const result = await documentsApiService.folderIndex(searchSpaceId, { folder_path: selectedFolder.path, folder_name: selectedFolder.name, search_space_id: searchSpaceId, enable_summary: shouldSummarize, file_extensions: supportedExtensions, }); const rootFolderId = (result as { root_folder_id?: number })?.root_folder_id ?? null; await api.addWatchedFolder({ path: selectedFolder.path, name: selectedFolder.name, excludePatterns: DEFAULT_EXCLUDE_PATTERNS, fileExtensions: supportedExtensions, rootFolderId, searchSpaceId, active: true, }); toast.success(`Watching folder: ${selectedFolder.name}`); setSelectedFolder(null); setShouldSummarize(false); onOpenChange(false); onSuccess?.(); } catch (err) { toast.error((err as Error)?.message || "Failed to watch folder"); } finally { setSubmitting(false); } }, [ selectedFolder, searchSpaceId, shouldSummarize, supportedExtensions, onOpenChange, onSuccess, ]); const handleOpenChange = useCallback( (nextOpen: boolean) => { if (!nextOpen && !submitting) { setSelectedFolder(null); setShouldSummarize(false); } onOpenChange(nextOpen); }, [onOpenChange, submitting] ); return ( Watch Local Folder Select a folder to sync and watch for changes.
{selectedFolder ? (

{selectedFolder.name}

{selectedFolder.path}

) : ( )} {selectedFolder && ( <>

Enable AI Summary

Improves search quality but adds latency

)}
); }