diff --git a/surfsense_web/atoms/folder-sync/folder-sync.atoms.ts b/surfsense_web/atoms/folder-sync/folder-sync.atoms.ts new file mode 100644 index 000000000..a9ae2bfcc --- /dev/null +++ b/surfsense_web/atoms/folder-sync/folder-sync.atoms.ts @@ -0,0 +1,12 @@ +import { atom } from "jotai"; + +export interface SelectedFolder { + path: string; + name: string; +} + +// Atom to control the folder watch dialog open state +export const folderWatchDialogOpenAtom = atom(false); + +// Atom to store initial folder selection for the dialog +export const folderWatchInitialFolderAtom = atom(null); diff --git a/surfsense_web/components/assistant-ui/connector-popup/constants/connector-constants.ts b/surfsense_web/components/assistant-ui/connector-popup/constants/connector-constants.ts index 2e92f637b..da6885ffe 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/constants/connector-constants.ts +++ b/surfsense_web/components/assistant-ui/connector-popup/constants/connector-constants.ts @@ -180,9 +180,8 @@ export const OTHER_CONNECTORS = [ { id: "obsidian-connector", title: "Obsidian", - description: "Index your Obsidian vault (self-hosted only)", + description: "Index your Obsidian vault (Local folder scan on Desktop)", connectorType: EnumConnectorName.OBSIDIAN_CONNECTOR, - selfHostedOnly: true, }, ] as const; diff --git a/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts b/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts index 7331549b5..03922c997 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts +++ b/surfsense_web/components/assistant-ui/connector-popup/hooks/use-connector-dialog.ts @@ -1,5 +1,5 @@ import { format } from "date-fns"; -import { useAtom, useAtomValue } from "jotai"; +import { useAtom, useAtomValue, useSetAtom } from "jotai"; import { useCallback, useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { connectorDialogOpenAtom } from "@/atoms/connector-dialog/connector-dialog.atoms"; @@ -33,6 +33,13 @@ import { OAUTH_CONNECTORS, OTHER_CONNECTORS, } from "../constants/connector-constants"; +import { usePlatform } from "@/hooks/use-platform"; +import { isSelfHosted } from "@/lib/env-config"; +import { + folderWatchDialogOpenAtom, + folderWatchInitialFolderAtom, +} from "@/atoms/folder-sync/folder-sync.atoms"; + import { dateRangeSchema, frequencyMinutesSchema, @@ -61,6 +68,11 @@ export const useConnectorDialog = () => { const { mutateAsync: updateConnector } = useAtomValue(updateConnectorMutationAtom); const { mutateAsync: deleteConnector } = useAtomValue(deleteConnectorMutationAtom); const { mutateAsync: createConnector } = useAtomValue(createConnectorMutationAtom); + const setFolderWatchOpen = useSetAtom(folderWatchDialogOpenAtom); + const setFolderWatchInitialFolder = useSetAtom(folderWatchInitialFolderAtom); + const { isDesktop } = usePlatform(); + const selfHosted = isSelfHosted(); + // Use global atom for dialog open state so it can be controlled from anywhere const [isOpen, setIsOpen] = useAtom(connectorDialogOpenAtom); @@ -440,11 +452,21 @@ export const useConnectorDialog = () => { const handleConnectNonOAuth = useCallback( (connectorType: string) => { if (!searchSpaceId) return; + + // Handle Obsidian specifically on Desktop & Cloud + if (connectorType === EnumConnectorName.OBSIDIAN_CONNECTOR && !selfHosted && isDesktop) { + setIsOpen(false); + setFolderWatchInitialFolder(null); + setFolderWatchOpen(true); + return; + } + setConnectingConnectorType(connectorType); }, - [searchSpaceId] + [searchSpaceId, selfHosted, isDesktop, setIsOpen, setFolderWatchOpen, setFolderWatchInitialFolder] ); + // Handle submitting connect form const handleSubmitConnectForm = useCallback( async ( diff --git a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx index ee0826595..71f2c5f68 100644 --- a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx @@ -14,6 +14,10 @@ import { deleteDocumentMutationAtom } from "@/atoms/documents/document-mutation. import { expandedFolderIdsAtom } from "@/atoms/documents/folder.atoms"; import { agentCreatedDocumentsAtom } from "@/atoms/documents/ui.atoms"; import { openEditorPanelAtom } from "@/atoms/editor/editor-panel.atom"; +import { + folderWatchDialogOpenAtom, + folderWatchInitialFolderAtom, +} from "@/atoms/folder-sync/folder-sync.atoms"; import { rightPanelCollapsedAtom } from "@/atoms/layout/right-panel.atom"; import { searchSpacesAtom } from "@/atoms/search-spaces/search-space-query.atoms"; import { CreateFolderDialog } from "@/components/documents/CreateFolderDialog"; @@ -106,8 +110,8 @@ export function DocumentsSidebar({ const debouncedSearch = useDebouncedValue(search, 250); const [activeTypes, setActiveTypes] = useState([]); const [watchedFolderIds, setWatchedFolderIds] = useState>(new Set()); - const [folderWatchOpen, setFolderWatchOpen] = useState(false); - const [watchInitialFolder, setWatchInitialFolder] = useState(null); + const [folderWatchOpen, setFolderWatchOpen] = useAtom(folderWatchDialogOpenAtom); + const [watchInitialFolder, setWatchInitialFolder] = useAtom(folderWatchInitialFolderAtom); const isElectron = typeof window !== "undefined" && !!window.electronAPI; // AI File Sort state @@ -161,7 +165,8 @@ export function DocumentsSidebar({ const folderName = folderPath.split("/").pop() || folderPath.split("\\").pop() || folderPath; setWatchInitialFolder({ path: folderPath, name: folderName }); setFolderWatchOpen(true); - }, []); + }, [setWatchInitialFolder, setFolderWatchOpen]); + const refreshWatchedIds = useCallback(async () => { if (!electronAPI?.getWatchedFolders) return;