From 659007bc4d576337c76458658fb6ac9eb647525c Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Wed, 20 May 2026 11:57:31 +0530 Subject: [PATCH] feat: enhance document export functionality for memory documents and update UI components --- .../components/documents/DocumentNode.tsx | 18 +++++++--- .../components/documents/FolderTreeView.tsx | 2 +- .../layout/ui/sidebar/DocumentsSidebar.tsx | 33 +++++++++++++++++++ 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/surfsense_web/components/documents/DocumentNode.tsx b/surfsense_web/components/documents/DocumentNode.tsx index bef2c6ba2..a5b02cbb3 100644 --- a/surfsense_web/components/documents/DocumentNode.tsx +++ b/surfsense_web/components/documents/DocumentNode.tsx @@ -328,7 +328,12 @@ export const DocumentNode = React.memo(function DocumentNode({ Move to... )} - {onExport && ( + {onExport && isMemoryDocument ? ( + handleExport("md")}> + + Export as MD + + ) : onExport ? ( @@ -338,7 +343,7 @@ export const DocumentNode = React.memo(function DocumentNode({ - )} + ) : null} {onVersionHistory && isVersionableType(doc.document_type) && ( onVersionHistory(doc)}> @@ -381,7 +386,12 @@ export const DocumentNode = React.memo(function DocumentNode({ Move to... )} - {onExport && ( + {onExport && isMemoryDocument ? ( + handleExport("md")}> + + Export as MD + + ) : onExport ? ( @@ -391,7 +401,7 @@ export const DocumentNode = React.memo(function DocumentNode({ - )} + ) : null} {onVersionHistory && isVersionableType(doc.document_type) && ( onVersionHistory(doc)}> diff --git a/surfsense_web/components/documents/FolderTreeView.tsx b/surfsense_web/components/documents/FolderTreeView.tsx index 4bf4a04ab..fb1030028 100644 --- a/surfsense_web/components/documents/FolderTreeView.tsx +++ b/surfsense_web/components/documents/FolderTreeView.tsx @@ -254,7 +254,7 @@ export function FolderTreeView({ onDelete={onDeleteDocument} onMove={onMoveDocument} onReset={onResetDocument} - onExport={isMemoryDocument ? undefined : onExportDocument} + onExport={onExportDocument} onVersionHistory={isMemoryDocument ? undefined : onVersionHistory} canDelete={!isMemoryDocument} canMove={!isMemoryDocument} diff --git a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx index 0c37d003c..2acc0a9f4 100644 --- a/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx +++ b/surfsense_web/components/layout/ui/sidebar/DocumentsSidebar.tsx @@ -113,6 +113,18 @@ const MEMORY_DOCUMENTS: DocumentNodeDoc[] = [ function isMemoryDocument(doc: { document_type: string }) { return doc.document_type === "USER_MEMORY" || doc.document_type === "TEAM_MEMORY"; } + +function downloadTextFile(content: string, fileName: string, type = "text/markdown;charset=utf-8") { + const blob = new Blob([content], { type }); + const url = URL.createObjectURL(blob); + const a = document.createElement("a"); + a.href = url; + a.download = fileName; + document.body.appendChild(a); + a.click(); + document.body.removeChild(a); + URL.revokeObjectURL(url); +} const LOCAL_FILESYSTEM_TRUST_KEY = "surfsense.local-filesystem-trust.v1"; const MAX_LOCAL_FILESYSTEM_ROOTS = 10; @@ -808,6 +820,27 @@ function AuthenticatedDocumentsSidebarBase({ const handleExportDocument = useCallback( async (doc: DocumentNodeDoc, format: string) => { + if (isMemoryDocument(doc)) { + try { + const endpoint = + doc.document_type === "USER_MEMORY" + ? `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/users/me/memory` + : `${process.env.NEXT_PUBLIC_FASTAPI_BACKEND_URL}/api/v1/searchspaces/${searchSpaceId}/memory`; + const response = await authenticatedFetch(endpoint, { method: "GET" }); + if (!response.ok) { + const errorData = await response.json().catch(() => ({ detail: "Export failed" })); + throw new Error(errorData.detail || "Export failed"); + } + const data = (await response.json()) as { memory_md?: string }; + downloadTextFile(data.memory_md ?? "", doc.title.endsWith(".md") ? doc.title : `${doc.title}.md`); + return; + } catch (err) { + console.error("Memory export failed:", err); + toast.error(err instanceof Error ? err.message : "Export failed"); + return; + } + } + const safeTitle = doc.title .replace(/[^a-zA-Z0-9 _-]/g, "_")