mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-17 18:35:19 +02:00
feat: add support for Local Folder connector in UI components and configuration
This commit is contained in:
parent
28f556224a
commit
e2f946b7c0
9 changed files with 72 additions and 52 deletions
|
|
@ -17,6 +17,7 @@ import { DocumentUploadDialogProvider } from "@/components/assistant-ui/document
|
||||||
import { LayoutDataProvider } from "@/components/layout";
|
import { LayoutDataProvider } from "@/components/layout";
|
||||||
import { OnboardingTour } from "@/components/onboarding-tour";
|
import { OnboardingTour } from "@/components/onboarding-tour";
|
||||||
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
|
||||||
|
import { useFolderSync } from "@/hooks/use-folder-sync";
|
||||||
import { useGlobalLoadingEffect } from "@/hooks/use-global-loading";
|
import { useGlobalLoadingEffect } from "@/hooks/use-global-loading";
|
||||||
|
|
||||||
export function DashboardClientLayout({
|
export function DashboardClientLayout({
|
||||||
|
|
@ -159,6 +160,9 @@ export function DashboardClientLayout({
|
||||||
// Use global loading screen - spinner animation won't reset
|
// Use global loading screen - spinner animation won't reset
|
||||||
useGlobalLoadingEffect(shouldShowLoading);
|
useGlobalLoadingEffect(shouldShowLoading);
|
||||||
|
|
||||||
|
// Wire desktop app file watcher -> single-file re-index API
|
||||||
|
useFolderSync();
|
||||||
|
|
||||||
if (shouldShowLoading) {
|
if (shouldShowLoading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ const FORM_ID_MAP: Record<string, string> = {
|
||||||
CIRCLEBACK_CONNECTOR: "circleback-connect-form",
|
CIRCLEBACK_CONNECTOR: "circleback-connect-form",
|
||||||
MCP_CONNECTOR: "mcp-connect-form",
|
MCP_CONNECTOR: "mcp-connect-form",
|
||||||
OBSIDIAN_CONNECTOR: "obsidian-connect-form",
|
OBSIDIAN_CONNECTOR: "obsidian-connect-form",
|
||||||
|
LOCAL_FOLDER_CONNECTOR: "local-folder-connect-form",
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ConnectorConnectViewProps {
|
interface ConnectorConnectViewProps {
|
||||||
|
|
|
||||||
|
|
@ -272,13 +272,14 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
||||||
{/* AI Summary toggle */}
|
{/* AI Summary toggle */}
|
||||||
<SummaryConfig enabled={enableSummary} onEnabledChange={onEnableSummaryChange} />
|
<SummaryConfig enabled={enableSummary} onEnabledChange={onEnableSummaryChange} />
|
||||||
|
|
||||||
{/* Date range selector - not shown for file-based connectors (Drive, Dropbox, OneDrive), Webcrawler, or GitHub (indexes full repo snapshots) */}
|
{/* Date range selector - not shown for file-based connectors (Drive, Dropbox, OneDrive), Webcrawler, GitHub, or Local Folder */}
|
||||||
{connector.connector_type !== "GOOGLE_DRIVE_CONNECTOR" &&
|
{connector.connector_type !== "GOOGLE_DRIVE_CONNECTOR" &&
|
||||||
connector.connector_type !== "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" &&
|
connector.connector_type !== "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" &&
|
||||||
connector.connector_type !== "DROPBOX_CONNECTOR" &&
|
connector.connector_type !== "DROPBOX_CONNECTOR" &&
|
||||||
connector.connector_type !== "ONEDRIVE_CONNECTOR" &&
|
connector.connector_type !== "ONEDRIVE_CONNECTOR" &&
|
||||||
connector.connector_type !== "WEBCRAWLER_CONNECTOR" &&
|
connector.connector_type !== "WEBCRAWLER_CONNECTOR" &&
|
||||||
connector.connector_type !== "GITHUB_CONNECTOR" && (
|
connector.connector_type !== "GITHUB_CONNECTOR" &&
|
||||||
|
connector.connector_type !== "LOCAL_FOLDER_CONNECTOR" && (
|
||||||
<DateRangeSelector
|
<DateRangeSelector
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
|
|
@ -293,39 +294,39 @@ export const ConnectorEditView: FC<ConnectorEditViewProps> = ({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Periodic sync - shown for all indexable connectors */}
|
{/* Periodic sync - shown for all indexable connectors except Local Folder */}
|
||||||
{(() => {
|
{connector.connector_type !== "LOCAL_FOLDER_CONNECTOR" &&
|
||||||
// Check if Google Drive (regular or Composio) has folders/files selected
|
(() => {
|
||||||
const isGoogleDrive = connector.connector_type === "GOOGLE_DRIVE_CONNECTOR";
|
const isGoogleDrive = connector.connector_type === "GOOGLE_DRIVE_CONNECTOR";
|
||||||
const isComposioGoogleDrive =
|
const isComposioGoogleDrive =
|
||||||
connector.connector_type === "COMPOSIO_GOOGLE_DRIVE_CONNECTOR";
|
connector.connector_type === "COMPOSIO_GOOGLE_DRIVE_CONNECTOR";
|
||||||
const requiresFolderSelection = isGoogleDrive || isComposioGoogleDrive;
|
const requiresFolderSelection = isGoogleDrive || isComposioGoogleDrive;
|
||||||
const selectedFolders =
|
const selectedFolders =
|
||||||
(connector.config?.selected_folders as
|
(connector.config?.selected_folders as
|
||||||
| Array<{ id: string; name: string }>
|
| Array<{ id: string; name: string }>
|
||||||
| undefined) || [];
|
| undefined) || [];
|
||||||
const selectedFiles =
|
const selectedFiles =
|
||||||
(connector.config?.selected_files as
|
(connector.config?.selected_files as
|
||||||
| Array<{ id: string; name: string }>
|
| Array<{ id: string; name: string }>
|
||||||
| undefined) || [];
|
| undefined) || [];
|
||||||
const hasItemsSelected = selectedFolders.length > 0 || selectedFiles.length > 0;
|
const hasItemsSelected = selectedFolders.length > 0 || selectedFiles.length > 0;
|
||||||
const isDisabled = requiresFolderSelection && !hasItemsSelected;
|
const isDisabled = requiresFolderSelection && !hasItemsSelected;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PeriodicSyncConfig
|
<PeriodicSyncConfig
|
||||||
enabled={periodicEnabled}
|
enabled={periodicEnabled}
|
||||||
frequencyMinutes={frequencyMinutes}
|
frequencyMinutes={frequencyMinutes}
|
||||||
onEnabledChange={onPeriodicEnabledChange}
|
onEnabledChange={onPeriodicEnabledChange}
|
||||||
onFrequencyChange={onFrequencyChange}
|
onFrequencyChange={onFrequencyChange}
|
||||||
disabled={isDisabled}
|
disabled={isDisabled}
|
||||||
disabledMessage={
|
disabledMessage={
|
||||||
isDisabled
|
isDisabled
|
||||||
? "Select at least one folder or file above to enable periodic sync"
|
? "Select at least one folder or file above to enable periodic sync"
|
||||||
: undefined
|
: undefined
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -158,13 +158,14 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
|
||||||
{/* AI Summary toggle */}
|
{/* AI Summary toggle */}
|
||||||
<SummaryConfig enabled={enableSummary} onEnabledChange={onEnableSummaryChange} />
|
<SummaryConfig enabled={enableSummary} onEnabledChange={onEnableSummaryChange} />
|
||||||
|
|
||||||
{/* Date range selector - not shown for file-based connectors (Drive, Dropbox, OneDrive), Webcrawler, or GitHub (indexes full repo snapshots) */}
|
{/* Date range selector - not shown for file-based connectors (Drive, Dropbox, OneDrive), Webcrawler, GitHub, or Local Folder */}
|
||||||
{config.connectorType !== "GOOGLE_DRIVE_CONNECTOR" &&
|
{config.connectorType !== "GOOGLE_DRIVE_CONNECTOR" &&
|
||||||
config.connectorType !== "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" &&
|
config.connectorType !== "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" &&
|
||||||
config.connectorType !== "DROPBOX_CONNECTOR" &&
|
config.connectorType !== "DROPBOX_CONNECTOR" &&
|
||||||
config.connectorType !== "ONEDRIVE_CONNECTOR" &&
|
config.connectorType !== "ONEDRIVE_CONNECTOR" &&
|
||||||
config.connectorType !== "WEBCRAWLER_CONNECTOR" &&
|
config.connectorType !== "WEBCRAWLER_CONNECTOR" &&
|
||||||
config.connectorType !== "GITHUB_CONNECTOR" && (
|
config.connectorType !== "GITHUB_CONNECTOR" &&
|
||||||
|
config.connectorType !== "LOCAL_FOLDER_CONNECTOR" && (
|
||||||
<DateRangeSelector
|
<DateRangeSelector
|
||||||
startDate={startDate}
|
startDate={startDate}
|
||||||
endDate={endDate}
|
endDate={endDate}
|
||||||
|
|
@ -179,9 +180,12 @@ export const IndexingConfigurationView: FC<IndexingConfigurationViewProps> = ({
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Periodic sync - not shown for Google Drive (regular and Composio) */}
|
{/* Periodic sync - not shown for file-based connectors (Drive, Dropbox, OneDrive) or Local Folder in initial setup; configured in edit view instead */}
|
||||||
{config.connectorType !== "GOOGLE_DRIVE_CONNECTOR" &&
|
{config.connectorType !== "GOOGLE_DRIVE_CONNECTOR" &&
|
||||||
config.connectorType !== "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" && (
|
config.connectorType !== "COMPOSIO_GOOGLE_DRIVE_CONNECTOR" &&
|
||||||
|
config.connectorType !== "DROPBOX_CONNECTOR" &&
|
||||||
|
config.connectorType !== "ONEDRIVE_CONNECTOR" &&
|
||||||
|
config.connectorType !== "LOCAL_FOLDER_CONNECTOR" && (
|
||||||
<PeriodicSyncConfig
|
<PeriodicSyncConfig
|
||||||
enabled={periodicEnabled}
|
enabled={periodicEnabled}
|
||||||
frequencyMinutes={frequencyMinutes}
|
frequencyMinutes={frequencyMinutes}
|
||||||
|
|
|
||||||
|
|
@ -184,6 +184,14 @@ export const OTHER_CONNECTORS = [
|
||||||
connectorType: EnumConnectorName.OBSIDIAN_CONNECTOR,
|
connectorType: EnumConnectorName.OBSIDIAN_CONNECTOR,
|
||||||
selfHostedOnly: true,
|
selfHostedOnly: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: "local-folder-connector",
|
||||||
|
title: "Local Folder",
|
||||||
|
description: "Watch and sync local folders (desktop only)",
|
||||||
|
connectorType: EnumConnectorName.LOCAL_FOLDER_CONNECTOR,
|
||||||
|
selfHostedOnly: true,
|
||||||
|
desktopOnly: true,
|
||||||
|
},
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
// Composio Connectors - Individual entries for each supported toolkit
|
// Composio Connectors - Individual entries for each supported toolkit
|
||||||
|
|
|
||||||
|
|
@ -76,29 +76,26 @@ export const AllConnectorsTab: FC<AllConnectorsTabProps> = ({
|
||||||
}) => {
|
}) => {
|
||||||
// Check if self-hosted mode (for showing self-hosted only connectors)
|
// Check if self-hosted mode (for showing self-hosted only connectors)
|
||||||
const selfHosted = isSelfHosted();
|
const selfHosted = isSelfHosted();
|
||||||
|
const isDesktop = typeof window !== "undefined" && !!window.electronAPI;
|
||||||
|
|
||||||
|
const matchesSearch = (title: string, description: string) =>
|
||||||
|
title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||||
|
description.toLowerCase().includes(searchQuery.toLowerCase());
|
||||||
|
|
||||||
|
const passesDeploymentFilter = (c: { selfHostedOnly?: boolean; desktopOnly?: boolean }) =>
|
||||||
|
(!c.selfHostedOnly || selfHosted) && (!c.desktopOnly || isDesktop);
|
||||||
|
|
||||||
// Filter connectors based on search and deployment mode
|
// Filter connectors based on search and deployment mode
|
||||||
const filteredOAuth = OAUTH_CONNECTORS.filter(
|
const filteredOAuth = OAUTH_CONNECTORS.filter(
|
||||||
(c) =>
|
(c) => matchesSearch(c.title, c.description) && passesDeploymentFilter(c)
|
||||||
// Filter by search query
|
|
||||||
(c.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
c.description.toLowerCase().includes(searchQuery.toLowerCase())) &&
|
|
||||||
// Filter self-hosted only connectors in cloud mode
|
|
||||||
(!("selfHostedOnly" in c) || !c.selfHostedOnly || selfHosted)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const filteredCrawlers = CRAWLERS.filter(
|
const filteredCrawlers = CRAWLERS.filter(
|
||||||
(c) =>
|
(c) => matchesSearch(c.title, c.description) && passesDeploymentFilter(c)
|
||||||
(c.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
c.description.toLowerCase().includes(searchQuery.toLowerCase())) &&
|
|
||||||
(!("selfHostedOnly" in c) || !c.selfHostedOnly || selfHosted)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const filteredOther = OTHER_CONNECTORS.filter(
|
const filteredOther = OTHER_CONNECTORS.filter(
|
||||||
(c) =>
|
(c) => matchesSearch(c.title, c.description) && passesDeploymentFilter(c)
|
||||||
(c.title.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
|
||||||
c.description.toLowerCase().includes(searchQuery.toLowerCase())) &&
|
|
||||||
(!("selfHostedOnly" in c) || !c.selfHostedOnly || selfHosted)
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Filter Composio connectors
|
// Filter Composio connectors
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@ export enum EnumConnectorName {
|
||||||
YOUTUBE_CONNECTOR = "YOUTUBE_CONNECTOR",
|
YOUTUBE_CONNECTOR = "YOUTUBE_CONNECTOR",
|
||||||
CIRCLEBACK_CONNECTOR = "CIRCLEBACK_CONNECTOR",
|
CIRCLEBACK_CONNECTOR = "CIRCLEBACK_CONNECTOR",
|
||||||
OBSIDIAN_CONNECTOR = "OBSIDIAN_CONNECTOR",
|
OBSIDIAN_CONNECTOR = "OBSIDIAN_CONNECTOR",
|
||||||
|
LOCAL_FOLDER_CONNECTOR = "LOCAL_FOLDER_CONNECTOR",
|
||||||
DROPBOX_CONNECTOR = "DROPBOX_CONNECTOR",
|
DROPBOX_CONNECTOR = "DROPBOX_CONNECTOR",
|
||||||
MCP_CONNECTOR = "MCP_CONNECTOR",
|
MCP_CONNECTOR = "MCP_CONNECTOR",
|
||||||
COMPOSIO_GOOGLE_DRIVE_CONNECTOR = "COMPOSIO_GOOGLE_DRIVE_CONNECTOR",
|
COMPOSIO_GOOGLE_DRIVE_CONNECTOR = "COMPOSIO_GOOGLE_DRIVE_CONNECTOR",
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import {
|
||||||
BookOpen,
|
BookOpen,
|
||||||
File,
|
File,
|
||||||
FileText,
|
FileText,
|
||||||
|
FolderSync,
|
||||||
Globe,
|
Globe,
|
||||||
Microscope,
|
Microscope,
|
||||||
Search,
|
Search,
|
||||||
|
|
@ -75,6 +76,8 @@ export const getConnectorIcon = (connectorType: EnumConnectorName | string, clas
|
||||||
return <Image src="/connectors/circleback.svg" alt="Circleback" {...imgProps} />;
|
return <Image src="/connectors/circleback.svg" alt="Circleback" {...imgProps} />;
|
||||||
case EnumConnectorName.MCP_CONNECTOR:
|
case EnumConnectorName.MCP_CONNECTOR:
|
||||||
return <Image src="/connectors/modelcontextprotocol.svg" alt="MCP" {...imgProps} />;
|
return <Image src="/connectors/modelcontextprotocol.svg" alt="MCP" {...imgProps} />;
|
||||||
|
case EnumConnectorName.LOCAL_FOLDER_CONNECTOR:
|
||||||
|
return <FolderSync {...iconProps} />;
|
||||||
case EnumConnectorName.OBSIDIAN_CONNECTOR:
|
case EnumConnectorName.OBSIDIAN_CONNECTOR:
|
||||||
return <Image src="/connectors/obsidian.svg" alt="Obsidian" {...imgProps} />;
|
return <Image src="/connectors/obsidian.svg" alt="Obsidian" {...imgProps} />;
|
||||||
case EnumConnectorName.COMPOSIO_GOOGLE_DRIVE_CONNECTOR:
|
case EnumConnectorName.COMPOSIO_GOOGLE_DRIVE_CONNECTOR:
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export const searchSourceConnectorTypeEnum = z.enum([
|
||||||
"DROPBOX_CONNECTOR",
|
"DROPBOX_CONNECTOR",
|
||||||
"MCP_CONNECTOR",
|
"MCP_CONNECTOR",
|
||||||
"OBSIDIAN_CONNECTOR",
|
"OBSIDIAN_CONNECTOR",
|
||||||
|
"LOCAL_FOLDER_CONNECTOR",
|
||||||
"COMPOSIO_GOOGLE_DRIVE_CONNECTOR",
|
"COMPOSIO_GOOGLE_DRIVE_CONNECTOR",
|
||||||
"COMPOSIO_GMAIL_CONNECTOR",
|
"COMPOSIO_GMAIL_CONNECTOR",
|
||||||
"COMPOSIO_GOOGLE_CALENDAR_CONNECTOR",
|
"COMPOSIO_GOOGLE_CALENDAR_CONNECTOR",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue