From 389337da0b5495bda21f94e3663cec770afee9d4 Mon Sep 17 00:00:00 2001 From: "DESKTOP-RTLN3BA\\$punk" Date: Fri, 24 Jul 2026 15:09:54 -0700 Subject: [PATCH] feat(sidebar): add missed upload files dialog --- surfsense_web/atoms/documents/folder.atoms.ts | 7 +++ .../layout/ui/sidebar/DocumentsSidebar.tsx | 7 ++- .../components/layout/ui/sidebar/Sidebar.tsx | 54 +++++++++++++++++-- 3 files changed, 63 insertions(+), 5 deletions(-) diff --git a/surfsense_web/atoms/documents/folder.atoms.ts b/surfsense_web/atoms/documents/folder.atoms.ts index 2d381557b..161627d5c 100644 --- a/surfsense_web/atoms/documents/folder.atoms.ts +++ b/surfsense_web/atoms/documents/folder.atoms.ts @@ -26,3 +26,10 @@ export const localExpandedFolderKeysAtom = atomWithStorage(null); + +/** + * Bumped whenever a folder is (un)watched outside DocumentsSidebar (e.g. the + * sidebar-footer "Watch Local Folder" button) so the tree re-reads Electron's + * watched-folder list and shows the sync badge without a reload. + */ +export const watchedFoldersRefreshAtom = atom(0); diff --git a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx index f8b71fd2e..073164bc9 100644 --- a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx @@ -17,7 +17,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import { toast } from "sonner"; import { makeFolderMention, mentionedDocumentsAtom } from "@/atoms/chat/mentioned-documents.atom"; import { deleteDocumentMutationAtom } from "@/atoms/documents/document-mutation.atoms"; -import { expandedFolderIdsAtom } from "@/atoms/documents/folder.atoms"; +import { expandedFolderIdsAtom, watchedFoldersRefreshAtom } from "@/atoms/documents/folder.atoms"; import { agentCreatedDocumentsAtom } from "@/atoms/documents/ui.atoms"; import { openEditorPanelAtom } from "@/atoms/editor/editor-panel.atom"; import { CreateFolderDialog } from "@/components/documents/CreateFolderDialog"; @@ -401,9 +401,12 @@ function AuthenticatedDocumentsSidebarBase({ setWatchedFolderIds(ids); }, [workspaceId, electronAPI]); + // Re-runs when the sidebar-footer "Watch Local Folder" dialog bumps the atom. + const watchedFoldersRefreshTick = useAtomValue(watchedFoldersRefreshAtom); useEffect(() => { + void watchedFoldersRefreshTick; refreshWatchedIds(); - }, [refreshWatchedIds]); + }, [refreshWatchedIds, watchedFoldersRefreshTick]); const { mutateAsync: deleteDocumentMutation } = useAtomValue(deleteDocumentMutationAtom); const [sidebarDocs, setSidebarDocs] = useAtom(mentionedDocumentsAtom); diff --git a/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx b/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx index 0d280dc28..5838e302d 100644 --- a/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/Sidebar.tsx @@ -1,16 +1,22 @@ "use client"; -import { CreditCard, MessageCircleMore, SquarePen, Zap } from "lucide-react"; +import { useSetAtom } from "jotai"; +import { CreditCard, FolderSync, MessageCircleMore, SquarePen, Upload, Zap } from "lucide-react"; import Link from "next/link"; import { useParams } from "next/navigation"; import { useTranslations } from "next-intl"; import { type ReactNode, useMemo, useState } from "react"; +import { watchedFoldersRefreshAtom } from "@/atoms/documents/folder.atoms"; +import { useDocumentUploadDialog } from "@/components/assistant-ui/document-upload-popup"; import { ConnectAgentDialog } from "@/components/mcp/connect-agent-dialog"; +import { FolderWatchDialog } from "@/components/sources/FolderWatchDialog"; import { Button } from "@/components/ui/button"; import { Progress } from "@/components/ui/progress"; import { Skeleton } from "@/components/ui/skeleton"; import { useIsAnonymous } from "@/contexts/anonymous-mode"; -import { getWorkspaceIdParam } from "@/lib/route-params"; +import { useLoginGate } from "@/contexts/login-gate"; +import { usePlatform } from "@/hooks/use-platform"; +import { getWorkspaceIdNumber, getWorkspaceIdParam } from "@/lib/route-params"; import { cn } from "@/lib/utils"; import { SIDEBAR_MIN_WIDTH } from "../../hooks/useSidebarResize"; import type { ChatItem, NavItem, PageUsage, User, Workspace } from "../../types/layout.types"; @@ -355,7 +361,8 @@ export function Sidebar({ )} {!isCollapsed && ( -
+
+
)} @@ -384,6 +391,47 @@ export function Sidebar({ ); } +/** + * Sidebar-footer import actions rendered above "Connect your agent": + * "Watch Local Folder" (desktop app only) and "Upload Files". Both reuse the + * existing dialogs; in anonymous mode they open the login gate instead. + */ +function SidebarImportActions() { + const params = useParams(); + const workspaceId = getWorkspaceIdNumber(params) ?? 0; + const { isDesktop } = usePlatform(); + const isAnonymous = useIsAnonymous(); + const { gate } = useLoginGate(); + const { openDialog: openUploadDialog } = useDocumentUploadDialog(); + const [folderWatchOpen, setFolderWatchOpen] = useState(false); + const bumpWatchedFoldersRefresh = useSetAtom(watchedFoldersRefreshAtom); + + return ( + <> + {isDesktop && ( + (isAnonymous ? gate("watch local folders") : setFolderWatchOpen(true))} + /> + )} + (isAnonymous ? gate("upload files") : openUploadDialog())} + /> + {isDesktop && !isAnonymous && ( + bumpWatchedFoldersRefresh((c) => c + 1)} + /> + )} + + ); +} + function SidebarUsageFooter({ pageUsage, isCollapsed,