From 9d6d81871219906432e8b35260a8f5c3de6edbc6 Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Wed, 1 Apr 2026 18:52:04 +0530 Subject: [PATCH 01/70] fix: add select-none class to TabBar --- surfsense_web/components/layout/ui/tabs/TabBar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/surfsense_web/components/layout/ui/tabs/TabBar.tsx b/surfsense_web/components/layout/ui/tabs/TabBar.tsx index 18e1ba141..8d0d986d3 100644 --- a/surfsense_web/components/layout/ui/tabs/TabBar.tsx +++ b/surfsense_web/components/layout/ui/tabs/TabBar.tsx @@ -72,7 +72,7 @@ export function TabBar({ onTabSwitch, onNewChat, rightActions, className }: TabB if (tabs.length <= 1) return null; return ( -
No matching documents
+No matching documents
+Try a different search term
Failed to load document
-{error || "An unknown error occurred"}
+ {error?.toLowerCase().includes("still being processed") ? ( ++ {error?.toLowerCase().includes("still being processed") + ? "Document is processing" + : "Document unavailable"} +
+{error || "An unknown error occurred"}
Failed to load document
-+
+ {isProcessing ? "Document is processing" : "Document unavailable"} +
+{error || "An unknown error occurred"}
- Failed to load document +
+ Document unavailable
{documentByChunkFetchingError.message || From 5c11a15fb6534c55e3e50e49caac4e4ee3703cec Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Wed, 1 Apr 2026 20:51:55 +0530 Subject: [PATCH 03/70] refactor: update UI components by removing unused imports and adjusting loading states --- .../components/CommunityPromptsContent.tsx | 2 +- .../components/PromptsContent.tsx | 6 ++-- .../components/editor-panel/editor-panel.tsx | 29 +++++++++---------- .../layout/ui/right-panel/RightPanel.tsx | 2 +- .../settings/image-model-manager.tsx | 3 +- .../settings/model-config-manager.tsx | 2 -- 6 files changed, 20 insertions(+), 24 deletions(-) diff --git a/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/CommunityPromptsContent.tsx b/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/CommunityPromptsContent.tsx index 4bcdcba7e..239832b2d 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/CommunityPromptsContent.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/CommunityPromptsContent.tsx @@ -60,7 +60,7 @@ export function CommunityPromptsContent() { {list.length === 0 && (
No community prompts yet
Share your own prompts from the My Prompts tab diff --git a/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/PromptsContent.tsx b/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/PromptsContent.tsx index 522d71e59..39362d244 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/PromptsContent.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/user-settings/components/PromptsContent.tsx @@ -1,7 +1,8 @@ "use client"; import { useAtomValue } from "jotai"; -import { AlertTriangle, Globe, Lock, PenLine, Plus, Sparkles, Trash2 } from "lucide-react"; +import { AlertTriangle, Globe, Lock, PenLine, Sparkles, Trash2 } from "lucide-react"; +import { ShortcutKbd } from "@/components/ui/shortcut-kbd"; import { useCallback, useState } from "react"; import { toast } from "sonner"; import { @@ -145,7 +146,7 @@ export function PromptsContent() {
Create prompt templates triggered with{" "}
- / in the
+
{canCreate - ? "Add your first LLM model to power document summarization, chat, and other agent capabilities" - : "No LLM models have been added to this space yet. Contact a space owner to add one"} + ? "Add your first model to power document summarization, chat, and other agent capabilities" + : "No models have been added to this space yet. Contact a space owner to add one"}
+ Comma-separated patterns of directories/files to exclude. +
++ Leave empty to index all supported files. +
+No version history available yet.
+Versions are created when file content changes.
+Version {v.version_number}
+ {v.created_at && ( ++ {new Date(v.created_at).toLocaleString()} +
+ )} + {v.title && ( ++ {v.title} +
+ )} +
+ {versionContent || "(empty)"}
+
+ )}
+ - Comma-separated patterns of directories/files to exclude. -
-- Leave empty to index all supported files. -
-Unsaved changes
- )} -Unsaved changes
+ )} +- {t("file_limit_reached")} -
-- {t("file_limit_reached_desc", { max: MAX_FILES })} -
-+ {t("file_limit_reached")} +
++ {t("file_limit_reached_desc", { max: MAX_FILES })} +
{t("drop_files")}
+{t("drop_files")}
+{t("drag_drop")}
+{t("or_browse")}
{t("drag_drop")}
-{t("or_browse")}
-- {t("remaining_capacity", { files: remainingFiles, sizeMB: remainingSizeMB })} -
- )} -+ {t("remaining_capacity", { files: remainingFiles, sizeMB: remainingSizeMB })} +
+ )} +- Upload and sync your documents to your search space -
-+ Upload and sync your documents to your search space +
- {t("file_limit_reached")} -
-- {t("file_limit_reached_desc", { max: MAX_FILES })} -
+ const sizeClass = compact ? "h-7" : "h-8"; + const widthClass = fullWidth ? "w-full" : ""; + + if (isElectron) { + return ( +{t("drop_files")}
-{t("drag_drop")}
-{t("or_browse")}
-- {t("remaining_capacity", { files: remainingFiles, sizeMB: remainingSizeMB })} -
- )} -+ {isElectron ? "Select files or folder" : "Tap to select files"} +
++ {t("file_size_limit")}{" "} + {t("upload_limits", { maxFiles: MAX_FILES, maxSizeMB: MAX_TOTAL_SIZE_MB })} +
+{t("file_limit_reached")}
++ {t("file_limit_reached_desc", { max: MAX_FILES })} +
+{t("drop_files")}
+{t("drag_drop")}
++ {t("file_size_limit")}{" "} + {t("upload_limits", { maxFiles: MAX_FILES, maxSizeMB: MAX_TOTAL_SIZE_MB })} +
+{selectedFolder.name}
+{selectedFolder.path}
+ {t("selected_files", { count: files.length })} · {formatFileSize(totalFileSize)} +
+Enable AI Summary
++ Improves search quality but adds latency +
+
+
{isElectron ? "Select files or folder" : "Tap to select files"}
-- {t("file_size_limit")}{" "} - {t("upload_limits", { maxFiles: MAX_FILES, maxSizeMB: MAX_TOTAL_SIZE_MB })} +
+ {t("file_size_limit")}
+
{t("drag_drop")}
-- {t("file_size_limit")}{" "} - {t("upload_limits", { maxFiles: MAX_FILES, maxSizeMB: MAX_TOTAL_SIZE_MB })} +
+ {t("file_size_limit")}
+
Enable AI Summary
-- Improves search quality but adds latency -
+Watch folder
++ Auto-sync when files change +
+Enable AI Summary
++ Improves search quality but adds latency +
+No version history available yet.
Versions are created when file content changes.
Version {v.version_number}
- {v.created_at && ( -- {new Date(v.created_at).toLocaleString()} -
- )} - {v.title && ( -- {v.title} -
- )} -
- {versionContent || "(empty)"}
-
- )}
+ return (
+ <>
+ {/* Left panel — version list */}
+ + {v.created_at ? formatRelativeTime(v.created_at) : `Version ${v.version_number}`} +
+ {v.title && ( ++ {v.title} +
+ )} +
+ {versionContent || "(empty)"}
+
+ )}
+ Select a version to preview
+No version history available yet.
-Versions are created when file content changes.
+No version history available yet
+Versions are created when file content changes
- {isElectron ? "Select files or folder" : "Tap to select files"} + {isElectron ? "Select files or folder" : "Tap to select files or folder"}
{t("file_size_limit")} @@ -484,40 +490,9 @@ export function DocumentUploadTab({ {t("upload_limits", { maxFiles: MAX_FILES, maxSizeMB: MAX_TOTAL_SIZE_MB })}
- {t("already_have_account")}{" "} - +
+ {t("already_have_account")}{" "} + {t("sign_in")}
diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsFilters.tsx b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsFilters.tsx index 150c119de..b85af13b7 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsFilters.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsFilters.tsx @@ -214,17 +214,17 @@ export function DocumentsFilters({ )} - {/* Upload Button */} -
- Create prompt templates triggered with{" "}
-
- {v.created_at ? formatRelativeTime(v.created_at) : `Version ${v.version_number}`} + {v.created_at + ? formatRelativeTime(v.created_at) + : `Version ${v.version_number}`}
- {v.title && ( -- {v.title} -
- )} + {v.title &&{v.title}
}Unsaved changes
- )} +Unsaved changes
+ )} +{error || "An unknown error occurred"}
++ {error || "An unknown error occurred"} +
- {error || "An unknown error occurred"} -
+{error || "An unknown error occurred"}
- Document unavailable -
+Document unavailable
{documentByChunkFetchingError.message ||
"An unexpected error occurred. Please try again."}
diff --git a/surfsense_web/components/settings/llm-role-manager.tsx b/surfsense_web/components/settings/llm-role-manager.tsx
index d1651b7f0..718503318 100644
--- a/surfsense_web/components/settings/llm-role-manager.tsx
+++ b/surfsense_web/components/settings/llm-role-manager.tsx
@@ -134,24 +134,27 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
preferences?.image_generation_config_id,
]);
- const handleRoleAssignment = useCallback(async (prefKey: string, configId: string) => {
- const value = configId === "unassigned" ? "" : parseInt(configId);
+ const handleRoleAssignment = useCallback(
+ async (prefKey: string, configId: string) => {
+ const value = configId === "unassigned" ? "" : parseInt(configId);
- setAssignments((prev) => ({ ...prev, [prefKey]: value }));
- setSavingRole(prefKey);
- savingRef.current = true;
+ setAssignments((prev) => ({ ...prev, [prefKey]: value }));
+ setSavingRole(prefKey);
+ savingRef.current = true;
- try {
- await updatePreferences({
- search_space_id: searchSpaceId,
- data: { [prefKey]: value || undefined },
- });
- toast.success("Role assignment updated");
- } finally {
- setSavingRole(null);
- savingRef.current = false;
- }
- }, [updatePreferences, searchSpaceId]);
+ try {
+ await updatePreferences({
+ search_space_id: searchSpaceId,
+ data: { [prefKey]: value || undefined },
+ });
+ toast.success("Role assignment updated");
+ } finally {
+ setSavingRole(null);
+ savingRef.current = false;
+ }
+ },
+ [updatePreferences, searchSpaceId]
+ );
// Combine global and custom LLM configs
const allLLMConfigs = [
@@ -199,10 +202,7 @@ export function LLMRoleManager({ searchSpaceId }: LLMRoleManagerProps) {
Refresh
{isAssignmentComplete && !isLoading && !hasError && (
-
{t("file_size_limit")}
Watch folder
-- Auto-sync when files change -
+Auto-sync when files change
- {t("selected_files", { count: files.length })} · {formatFileSize(totalFileSize)} + {t("selected_files", { count: files.length })} ·{" "} + {formatFileSize(totalFileSize)}
{selectedFolder.name}
From 8a8e5fcd76c5dcebb6fbc2142212408553ee7d6d Mon Sep 17 00:00:00 2001 From: SohamBhattacharjee2003 <125297948+SohamBhattacharjee2003@users.noreply.github.com> Date: Fri, 3 Apr 2026 14:29:41 +0530 Subject: [PATCH 58/70] fix(hooks): add AbortController to properly cancel fetch requests on unmount --- package-lock.json | 6 ++++++ .../components/circleback-config.tsx | 16 ++++++++++++---- .../components/editor-panel/editor-panel.tsx | 18 ++++++++---------- .../layout/ui/tabs/DocumentTabContent.tsx | 18 ++++++++---------- 4 files changed, 34 insertions(+), 24 deletions(-) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..9703ac09f --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "SurfSense", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/circleback-config.tsx b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/circleback-config.tsx index 99e26c542..268ab0f98 100644 --- a/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/circleback-config.tsx +++ b/surfsense_web/components/assistant-ui/connector-popup/connector-configs/components/circleback-config.tsx @@ -34,9 +34,12 @@ export const CirclebackConfig: FCResult
- {typeof result === "string" ? result : JSON.stringify(result, null, 2)}
+ {typeof result === "string" ? result : serializedResult}
{citation.title} @@ -339,18 +341,18 @@ function StackedCitations({ id, citations, className, onNavigate }: StackedCitat style={{ zIndex: maxIcons - index }} > {citation.favicon ? ( - // biome-ignore lint/performance/noImgElement: external favicon from arbitrary domain — next/image requires remotePatterns config - - ) : ( - - )} + + ) : ( + + )}
{isElectron ? "Select files or folder" : "Tap to select files or folder"}
-
- {t("file_size_limit")}
-
+ {t("file_size_limit")}
{t("file_limit_reached")}
-- {t("file_limit_reached_desc", { max: MAX_FILES })} -
-{t("drag_drop")}
-
- {t("file_size_limit")}
-
+ {t("file_size_limit")}
- {t("selected_files", { count: files.length })} ·{" "}
- {formatFileSize(totalFileSize)}
+ {t("selected_files", { count: files.length })}
{isElectron ? "Select files or folder" : "Tap to select files or folder"}
-- {t("file_size_limit")} -
+{t("file_size_limit")}
{t("drag_drop")}
-- {t("file_size_limit")} -
+{t("file_size_limit")}
- {t("selected_files", { count: files.length })}
Hello world
" + ) + + count, _skipped, _root_folder_id, err = await index_local_folder( + session=db_session, + search_space_id=db_search_space.id, + user_id=str(db_user.id), + folder_path=str(tmp_path), + folder_name="test-folder", + ) + + assert err is None + assert count == 1 + + doc = ( + await db_session.execute( + select(Document).where( + Document.document_type == DocumentType.LOCAL_FOLDER_FILE, + Document.search_space_id == db_search_space.id, + ) + ) + ).scalar_one() + + assert "Title" in doc.source_markdown + assert "Hello world
" - ) + (tmp_path / "page.html").write_text("Hello world
") count, _skipped, _root_folder_id, err = await index_local_folder( session=db_session, From 5068a6b4f392301a728f59f8c26fdf4679c6fc0c Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Fri, 3 Apr 2026 17:52:59 +0530 Subject: [PATCH 68/70] style: update button variant and improve drag-and-drop UI in DocumentUploadTab --- .../components/sources/DocumentUploadTab.tsx | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/surfsense_web/components/sources/DocumentUploadTab.tsx b/surfsense_web/components/sources/DocumentUploadTab.tsx index 2d70a4e1a..0bf842b6d 100644 --- a/surfsense_web/components/sources/DocumentUploadTab.tsx +++ b/surfsense_web/components/sources/DocumentUploadTab.tsx @@ -401,15 +401,19 @@ export function DocumentUploadTab({{t("drop_files")}
-{t("drag_drop")}
-{t("file_size_limit")}
-{t("drop_files")}
+{t("drag_drop")}
+{t("file_size_limit")}
+