From 1190ee9449626f921af250ce2d88969cca7f6a9a Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Mon, 27 Apr 2026 21:17:47 +0530 Subject: [PATCH] feat(sidebar): separate DesktopLocalTabContent component for reducing bundle size in web --- .../ui/sidebar/DesktopLocalTabContent.tsx | 187 ++++++++++++++ .../layout/ui/sidebar/DocumentsSidebar.tsx | 229 ++++-------------- 2 files changed, 233 insertions(+), 183 deletions(-) create mode 100644 surfsense_web/components/layout/ui/sidebar/DesktopLocalTabContent.tsx diff --git a/surfsense_web/components/layout/ui/sidebar/DesktopLocalTabContent.tsx b/surfsense_web/components/layout/ui/sidebar/DesktopLocalTabContent.tsx new file mode 100644 index 000000000..6fd4e48f8 --- /dev/null +++ b/surfsense_web/components/layout/ui/sidebar/DesktopLocalTabContent.tsx @@ -0,0 +1,187 @@ +"use client"; + +import { Folder, FolderPlus, Search, X } from "lucide-react"; +import { useRef, useState } from "react"; +import { Input } from "@/components/ui/input"; +import { Separator } from "@/components/ui/separator"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuLabel, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; +import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; +import { useDebouncedValue } from "@/hooks/use-debounced-value"; +import { LocalFilesystemBrowser } from "./LocalFilesystemBrowser"; + +const getFolderDisplayName = (rootPath: string): string => + rootPath.split(/[\\/]/).at(-1) || rootPath; + +interface DesktopLocalTabContentProps { + localRootPaths: string[]; + canAddMoreLocalRoots: boolean; + maxLocalFilesystemRoots: number; + searchSpaceId: number; + onPickFilesystemRoot: () => Promise | void; + onRemoveFilesystemRoot: (rootPath: string) => Promise | void; + onClearFilesystemRoots: () => Promise | void; + onOpenLocalFile: (localFilePath: string) => void; + electronAvailable: boolean; +} + +export function DesktopLocalTabContent({ + localRootPaths, + canAddMoreLocalRoots, + maxLocalFilesystemRoots, + searchSpaceId, + onPickFilesystemRoot, + onRemoveFilesystemRoot, + onClearFilesystemRoots, + onOpenLocalFile, + electronAvailable, +}: DesktopLocalTabContentProps) { + const [localSearch, setLocalSearch] = useState(""); + const debouncedLocalSearch = useDebouncedValue(localSearch, 250); + const localSearchInputRef = useRef(null); + + return ( +
+
+
+ {localRootPaths.length > 0 ? ( + + + + + + + Selected folders + + + {localRootPaths.map((rootPath) => ( + event.preventDefault()} + className="group h-8 gap-1.5 px-1.5 text-sm text-foreground" + > + + + {getFolderDisplayName(rootPath)} + + + + ))} + + { + void onClearFilesystemRoots(); + }} + > + Clear all folders + + + + ) : ( +
+ + No local folders selected +
+ )} + + {electronAvailable ? ( + + + + + + + + {canAddMoreLocalRoots + ? "Add folder" + : `You can add up to ${maxLocalFilesystemRoots} folders`} + + + ) : null} +
+
+
+
+
+
+ setLocalSearch(e.target.value)} + placeholder="Search local files" + type="text" + aria-label="Search local files" + /> + {Boolean(localSearch) && ( + + )} +
+
+ +
+ ); +} diff --git a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx index 3b747b15a..5b9157b28 100644 --- a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx @@ -6,19 +6,17 @@ import { ChevronLeft, ChevronRight, FileText, - Folder, - FolderPlus, FolderClock, Laptop, Lock, Paperclip, - Search, Server, Trash2, Unplug, Upload, X, } from "lucide-react"; +import dynamic from "next/dynamic"; import Link from "next/link"; import { useParams } from "next/navigation"; import { useTranslations } from "next-intl"; @@ -49,7 +47,6 @@ import { EXPORT_FILE_EXTENSIONS } from "@/components/shared/ExportMenuItems"; import { DEFAULT_EXCLUDE_PATTERNS, FolderWatchDialog, - type SelectedFolder, } from "@/components/sources/FolderWatchDialog"; import { AlertDialog, @@ -63,18 +60,8 @@ import { } from "@/components/ui/alert-dialog"; import { Avatar, AvatarFallback, AvatarGroup } from "@/components/ui/avatar"; import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; import { Drawer, DrawerContent, DrawerHandle, DrawerTitle } from "@/components/ui/drawer"; -import { Input } from "@/components/ui/input"; import { Skeleton } from "@/components/ui/skeleton"; -import { Separator } from "@/components/ui/separator"; import { Spinner } from "@/components/ui/spinner"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip"; @@ -84,7 +71,7 @@ import { getConnectorIcon } from "@/contracts/enums/connectorIcons"; import type { DocumentTypeEnum } from "@/contracts/types/document.types"; import { useDebouncedValue } from "@/hooks/use-debounced-value"; import { useMediaQuery } from "@/hooks/use-media-query"; -import { useElectronAPI } from "@/hooks/use-platform"; +import { usePlatform, useElectronAPI } from "@/hooks/use-platform"; import { anonymousChatApiService } from "@/lib/apis/anonymous-chat-api.service"; import { documentsApiService } from "@/lib/apis/documents-api.service"; import { foldersApiService } from "@/lib/apis/folders-api.service"; @@ -93,9 +80,13 @@ import { authenticatedFetch } from "@/lib/auth-utils"; import { uploadFolderScan } from "@/lib/folder-sync-upload"; import { getSupportedExtensionsSet } from "@/lib/supported-extensions"; import { queries } from "@/zero/queries/index"; -import { LocalFilesystemBrowser } from "./LocalFilesystemBrowser"; import { SidebarSlideOutPanel } from "./SidebarSlideOutPanel"; +const DesktopLocalTabContent = dynamic( + () => import("./DesktopLocalTabContent").then((mod) => mod.DesktopLocalTabContent), + { ssr: false } +); + const NON_DELETABLE_DOCUMENT_TYPES: readonly string[] = ["SURFSENSE_DOCS"]; const LOCAL_FILESYSTEM_TRUST_KEY = "surfsense.local-filesystem-trust.v1"; const MAX_LOCAL_FILESYSTEM_ROOTS = 10; @@ -142,9 +133,6 @@ interface WatchedFolderEntry { active: boolean; } -const getFolderDisplayName = (rootPath: string): string => - rootPath.split(/[\\/]/).at(-1) || rootPath; - const SHOWCASE_CONNECTORS = [ { type: "GOOGLE_DRIVE_CONNECTOR", label: "Google Drive" }, { type: "GOOGLE_GMAIL_CONNECTOR", label: "Gmail" }, @@ -170,25 +158,40 @@ interface DocumentsSidebarProps { export function DocumentsSidebar(props: DocumentsSidebarProps) { const isAnonymous = useIsAnonymous(); + const { isDesktop } = usePlatform(); if (isAnonymous) { return ; } - return ; + return isDesktop ? ( + + ) : ( + + ); } -function AuthenticatedDocumentsSidebar({ +function AuthenticatedDesktopDocumentsSidebar(props: DocumentsSidebarProps) { + return ; +} + +function AuthenticatedWebDocumentsSidebar(props: DocumentsSidebarProps) { + return ; +} + +function AuthenticatedDocumentsSidebarBase({ open, onOpenChange, isDocked = false, onDockedChange, embedded = false, headerAction, -}: DocumentsSidebarProps) { + desktopFeaturesEnabled, +}: DocumentsSidebarProps & { desktopFeaturesEnabled: boolean }) { const t = useTranslations("documents"); const tSidebar = useTranslations("sidebar"); const params = useParams(); const isMobile = !useMediaQuery("(min-width: 640px)"); - const electronAPI = useElectronAPI(); + const platformElectronAPI = useElectronAPI(); + const electronAPI = desktopFeaturesEnabled ? platformElectronAPI : null; const searchSpaceId = Number(params.search_space_id); const setConnectorDialogOpen = useSetAtom(connectorDialogOpenAtom); const setRightPanelCollapsed = useSetAtom(rightPanelCollapsedAtom); @@ -198,9 +201,6 @@ function AuthenticatedDocumentsSidebar({ const [search, setSearch] = useState(""); const debouncedSearch = useDebouncedValue(search, 250); - const [localSearch, setLocalSearch] = useState(""); - const debouncedLocalSearch = useDebouncedValue(localSearch, 250); - const localSearchInputRef = useRef(null); const [activeTypes, setActiveTypes] = useState([]); const [filesystemSettings, setFilesystemSettings] = useState(null); const [localTrustDialogOpen, setLocalTrustDialogOpen] = useState(false); @@ -208,7 +208,7 @@ function AuthenticatedDocumentsSidebar({ const [watchedFolderIds, setWatchedFolderIds] = useState>(new Set()); const [folderWatchOpen, setFolderWatchOpen] = useAtom(folderWatchDialogOpenAtom); const [watchInitialFolder, setWatchInitialFolder] = useAtom(folderWatchInitialFolderAtom); - const isElectron = typeof window !== "undefined" && !!window.electronAPI; + const isElectron = desktopFeaturesEnabled && typeof window !== "undefined" && !!window.electronAPI; useEffect(() => { if (!electronAPI?.getAgentFilesystemSettings) return; @@ -1180,161 +1180,24 @@ function AuthenticatedDocumentsSidebar({ ); const localContent = ( -
-
-
- {localRootPaths.length > 0 ? ( - - - - - - - Selected folders - - - {localRootPaths.map((rootPath) => ( - event.preventDefault()} - className="group h-8 gap-1.5 px-1.5 text-sm text-foreground" - > - - - {getFolderDisplayName(rootPath)} - - - - ))} - - { - void handleClearFilesystemRoots(); - }} - > - Clear all folders - - - - ) : ( -
- - No local folders selected -
- )} - - {electronAPI ? ( - - - - - - - - {canAddMoreLocalRoots - ? "Add folder" - : `You can add up to ${MAX_LOCAL_FILESYSTEM_ROOTS} folders`} - - - ) : ( - - )} -
-
-
-
-
-
- setLocalSearch(e.target.value)} - placeholder="Search local files" - type="text" - aria-label="Search local files" - /> - {Boolean(localSearch) && ( - - )} -
-
- { - openEditorPanel({ - kind: "local_file", - localFilePath, - title: localFilePath.split("/").pop() || localFilePath, - searchSpaceId, - }); - }} - /> -
+ { + openEditorPanel({ + kind: "local_file", + localFilePath, + title: localFilePath.split("/").pop() || localFilePath, + searchSpaceId, + }); + }} + electronAvailable={!!electronAPI} + /> ); const documentsContent = ( @@ -1428,7 +1291,7 @@ function AuthenticatedDocumentsSidebar({ {cloudContent} - {localContent} + {currentFilesystemTab === "local" ? localContent : null} ) : (