mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-07-06 22:12:12 +02:00
refactor: completely remove Local Folder connector references and update folder sync logic
This commit is contained in:
parent
493d720b89
commit
149ccb97dd
8 changed files with 60 additions and 35 deletions
|
|
@ -25,7 +25,6 @@ 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,7 +3,6 @@ import {
|
||||||
BookOpen,
|
BookOpen,
|
||||||
File,
|
File,
|
||||||
FileText,
|
FileText,
|
||||||
FolderSync,
|
|
||||||
Globe,
|
Globe,
|
||||||
Microscope,
|
Microscope,
|
||||||
Search,
|
Search,
|
||||||
|
|
@ -76,8 +75,6 @@ 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,7 +30,6 @@ 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",
|
||||||
|
|
|
||||||
|
|
@ -1,41 +1,73 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { connectorsApiService } from "@/lib/apis/connectors-api.service";
|
import { documentsApiService } from "@/lib/apis/documents-api.service";
|
||||||
|
|
||||||
|
interface FileChangedEvent {
|
||||||
|
rootFolderId: number | null;
|
||||||
|
searchSpaceId: number;
|
||||||
|
folderPath: string;
|
||||||
|
folderName: string;
|
||||||
|
relativePath: string;
|
||||||
|
fullPath: string;
|
||||||
|
action: string;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
const DEBOUNCE_MS = 2000;
|
const DEBOUNCE_MS = 2000;
|
||||||
|
|
||||||
export function useFolderSync() {
|
export function useFolderSync() {
|
||||||
const pendingRef = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());
|
const queueRef = useRef<FileChangedEvent[]>([]);
|
||||||
|
const processingRef = useRef(false);
|
||||||
|
const debounceTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());
|
||||||
|
|
||||||
|
async function processQueue() {
|
||||||
|
if (processingRef.current) return;
|
||||||
|
processingRef.current = true;
|
||||||
|
while (queueRef.current.length > 0) {
|
||||||
|
const event = queueRef.current.shift()!;
|
||||||
|
try {
|
||||||
|
await documentsApiService.folderIndexFile(event.searchSpaceId, {
|
||||||
|
folder_path: event.folderPath,
|
||||||
|
folder_name: event.folderName,
|
||||||
|
search_space_id: event.searchSpaceId,
|
||||||
|
target_file_path: event.fullPath,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
console.error("[FolderSync] Failed to trigger re-index:", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
processingRef.current = false;
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const api = typeof window !== "undefined" ? window.electronAPI : null;
|
const api = typeof window !== "undefined" ? window.electronAPI : null;
|
||||||
if (!api?.onFileChanged) return;
|
if (!api?.onFileChanged) return;
|
||||||
|
|
||||||
const cleanup = api.onFileChanged((event) => {
|
// Signal to main process that the renderer is ready to receive events
|
||||||
const key = `${event.connectorId}:${event.fullPath}`;
|
api.signalRendererReady?.();
|
||||||
|
|
||||||
const existing = pendingRef.current.get(key);
|
const cleanup = api.onFileChanged((event: FileChangedEvent) => {
|
||||||
|
const key = `${event.folderPath}:${event.fullPath}`;
|
||||||
|
|
||||||
|
const existing = debounceTimers.current.get(key);
|
||||||
if (existing) clearTimeout(existing);
|
if (existing) clearTimeout(existing);
|
||||||
|
|
||||||
const timeout = setTimeout(async () => {
|
const timeout = setTimeout(() => {
|
||||||
pendingRef.current.delete(key);
|
debounceTimers.current.delete(key);
|
||||||
try {
|
queueRef.current.push(event);
|
||||||
await connectorsApiService.indexFile(event.connectorId, event.fullPath);
|
processQueue();
|
||||||
} catch (err) {
|
|
||||||
console.error("[FolderSync] Failed to trigger re-index:", err);
|
|
||||||
}
|
|
||||||
}, DEBOUNCE_MS);
|
}, DEBOUNCE_MS);
|
||||||
|
|
||||||
pendingRef.current.set(key, timeout);
|
debounceTimers.current.set(key, timeout);
|
||||||
});
|
});
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
cleanup();
|
cleanup();
|
||||||
for (const timeout of pendingRef.current.values()) {
|
for (const timeout of debounceTimers.current.values()) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
}
|
}
|
||||||
pendingRef.current.clear();
|
debounceTimers.current.clear();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -405,17 +405,6 @@ class ConnectorsApiService {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
|
||||||
// Local Folder Connector Methods
|
|
||||||
// =============================================================================
|
|
||||||
|
|
||||||
indexFile = async (connectorId: number, filePath: string) => {
|
|
||||||
return baseApiService.post(
|
|
||||||
`/api/v1/search-source-connectors/${connectorId}/index-file`,
|
|
||||||
undefined,
|
|
||||||
{ body: { file_path: filePath } }
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export type { SlackChannel, DiscordChannel };
|
export type { SlackChannel, DiscordChannel };
|
||||||
|
|
|
||||||
|
|
@ -395,6 +395,14 @@ class DocumentsApiService {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
folderIndex = async (searchSpaceId: number, body: { folder_path: string; folder_name: string; search_space_id: number; exclude_patterns?: string[]; file_extensions?: string[]; root_folder_id?: number; enable_summary?: boolean }) => {
|
||||||
|
return baseApiService.post(`/api/v1/documents/folder-index`, undefined, { body });
|
||||||
|
};
|
||||||
|
|
||||||
|
folderIndexFile = async (searchSpaceId: number, body: { folder_path: string; folder_name: string; search_space_id: number; target_file_path: string; enable_summary?: boolean }) => {
|
||||||
|
return baseApiService.post(`/api/v1/documents/folder-index-file`, undefined, { body });
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete a document
|
* Delete a document
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,6 @@ export const getConnectorTypeDisplay = (type: string): string => {
|
||||||
YOUTUBE_CONNECTOR: "YouTube",
|
YOUTUBE_CONNECTOR: "YouTube",
|
||||||
CIRCLEBACK_CONNECTOR: "Circleback",
|
CIRCLEBACK_CONNECTOR: "Circleback",
|
||||||
OBSIDIAN_CONNECTOR: "Obsidian",
|
OBSIDIAN_CONNECTOR: "Obsidian",
|
||||||
LOCAL_FOLDER_CONNECTOR: "Local Folder",
|
|
||||||
DROPBOX_CONNECTOR: "Dropbox",
|
DROPBOX_CONNECTOR: "Dropbox",
|
||||||
MCP_CONNECTOR: "MCP Server",
|
MCP_CONNECTOR: "MCP Server",
|
||||||
};
|
};
|
||||||
|
|
|
||||||
8
surfsense_web/types/window.d.ts
vendored
8
surfsense_web/types/window.d.ts
vendored
|
|
@ -5,15 +5,16 @@ interface WatchedFolderConfig {
|
||||||
name: string;
|
name: string;
|
||||||
excludePatterns: string[];
|
excludePatterns: string[];
|
||||||
fileExtensions: string[] | null;
|
fileExtensions: string[] | null;
|
||||||
connectorId: number;
|
rootFolderId: number | null;
|
||||||
searchSpaceId: number;
|
searchSpaceId: number;
|
||||||
active: boolean;
|
active: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FolderSyncFileChangedEvent {
|
interface FolderSyncFileChangedEvent {
|
||||||
connectorId: number;
|
rootFolderId: number | null;
|
||||||
searchSpaceId: number;
|
searchSpaceId: number;
|
||||||
folderPath: string;
|
folderPath: string;
|
||||||
|
folderName: string;
|
||||||
relativePath: string;
|
relativePath: string;
|
||||||
fullPath: string;
|
fullPath: string;
|
||||||
action: "add" | "change" | "unlink";
|
action: "add" | "change" | "unlink";
|
||||||
|
|
@ -21,7 +22,7 @@ interface FolderSyncFileChangedEvent {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FolderSyncWatcherReadyEvent {
|
interface FolderSyncWatcherReadyEvent {
|
||||||
connectorId: number;
|
rootFolderId: number | null;
|
||||||
folderPath: string;
|
folderPath: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -49,6 +50,7 @@ interface ElectronAPI {
|
||||||
onWatcherReady: (callback: (data: FolderSyncWatcherReadyEvent) => void) => () => void;
|
onWatcherReady: (callback: (data: FolderSyncWatcherReadyEvent) => void) => () => void;
|
||||||
pauseWatcher: () => Promise<void>;
|
pauseWatcher: () => Promise<void>;
|
||||||
resumeWatcher: () => Promise<void>;
|
resumeWatcher: () => Promise<void>;
|
||||||
|
signalRendererReady: () => Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue