From e0edfef5fcce0d40e09505dd871a4f44bf7dad4a Mon Sep 17 00:00:00 2001 From: CREDO23 Date: Sun, 28 Dec 2025 16:48:34 +0200 Subject: [PATCH] feat(ui): add multiple folder selection with checkboxes to Google Drive tree - Replace single folder selection with multi-select checkboxes - Remove cascading auto-select for clearer UX - Each folder must be selected individually - Visual indicators for selected folders --- .../connectors/google-drive-folder-tree.tsx | 118 +++++++++++------- 1 file changed, 72 insertions(+), 46 deletions(-) diff --git a/surfsense_web/components/connectors/google-drive-folder-tree.tsx b/surfsense_web/components/connectors/google-drive-folder-tree.tsx index 22ef97556..793fdc750 100644 --- a/surfsense_web/components/connectors/google-drive-folder-tree.tsx +++ b/surfsense_web/components/connectors/google-drive-folder-tree.tsx @@ -15,6 +15,7 @@ import { } from "lucide-react"; import { useState } from "react"; import { Button } from "@/components/ui/button"; +import { Checkbox } from "@/components/ui/checkbox"; import { ScrollArea } from "@/components/ui/scroll-area"; import { cn } from "@/lib/utils"; import { authenticatedFetch } from "@/lib/auth-utils"; @@ -36,10 +37,15 @@ interface ItemTreeNode { isLoading: boolean; } +interface SelectedFolder { + id: string; + name: string; +} + interface GoogleDriveFolderTreeProps { connectorId: number; - selectedFolderId: string | null; - onSelectFolder: (folderId: string, folderName: string) => void; + selectedFolders: SelectedFolder[]; + onSelectFolders: (folders: SelectedFolder[]) => void; } // Helper to get appropriate icon for file type @@ -59,25 +65,32 @@ function getFileIcon(mimeType: string, className: string = "h-4 w-4") { return ; } -// Helper to format file size -function formatFileSize(bytes: number | undefined): string { - if (!bytes) return ""; - if (bytes < 1024) return `${bytes} B`; - if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`; - if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`; - return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`; -} - export function GoogleDriveFolderTree({ connectorId, - selectedFolderId, - onSelectFolder, + selectedFolders, + onSelectFolders, }: GoogleDriveFolderTreeProps) { const [rootItems, setRootItems] = useState([]); const [itemStates, setItemStates] = useState>(new Map()); const [isLoadingRoot, setIsLoadingRoot] = useState(false); const [isInitialized, setIsInitialized] = useState(false); + // Helper to check if a folder is selected + const isFolderSelected = (folderId: string): boolean => { + return selectedFolders.some((f) => f.id === folderId); + }; + + // Handle folder checkbox toggle + const toggleFolderSelection = (folderId: string, folderName: string) => { + if (isFolderSelected(folderId)) { + // Remove from selection + onSelectFolders(selectedFolders.filter((f) => f.id !== folderId)); + } else { + // Add to selection + onSelectFolders([...selectedFolders, { id: folderId, name: folderName }]); + } + }; + // Load root items (folders and files) on mount const loadRootItems = async () => { if (isInitialized) return; // Already loaded @@ -215,7 +228,7 @@ export function GoogleDriveFolderTree({ const isExpanded = state?.isExpanded || false; const isLoading = state?.isLoading || false; const children = state?.children; - const isSelected = selectedFolderId === item.id; + const isSelected = isFolderSelected(item.id); const isFolder = item.isFolder; // Separate folders and files for children @@ -224,15 +237,13 @@ export function GoogleDriveFolderTree({ return (
- + isFolder && toggleFolder(item)} + > + {item.name} + +
{/* Render children if expanded (folders first, then files) */} {isExpanded && isFolder && children && (
{/* Render folders first */} {childFolders.map((child) => renderItem(child, level + 1))} - + {/* Render files */} {childFiles.map((child) => renderItem(child, level + 1))} - + {/* Empty state */} {children.length === 0 && ( -
- Empty folder -
+
Empty folder
)}
)} @@ -302,17 +328,17 @@ export function GoogleDriveFolderTree({
{/* My Drive Header (always visible, selectable) */}
- + toggleFolderSelection("root", "My Drive")}> + My Drive + +
{/* Loading indicator */}