From c706b5f417c31562ee41b722668b44cc06a41e0b Mon Sep 17 00:00:00 2001 From: Anish Sarkar <104695310+AnishSarkar22@users.noreply.github.com> Date: Wed, 4 Feb 2026 22:34:03 +0530 Subject: [PATCH] feat: enhance metadata viewing in DocumentsTableShell with on-demand fetching and loading state --- .../components/DocumentsTableShell.tsx | 47 ++++++++++++++++--- .../components/json-metadata-viewer.tsx | 12 ++++- 2 files changed, 51 insertions(+), 8 deletions(-) diff --git a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx index dd32a3b78..1be226a56 100644 --- a/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx +++ b/surfsense_web/app/dashboard/[search_space_id]/documents/(manage)/components/DocumentsTableShell.tsx @@ -158,7 +158,10 @@ export function DocumentsTableShell({ const { openDialog } = useDocumentUploadDialog(); // State for metadata viewer (opened via Ctrl/Cmd+Click) + // Real-time documents don't sync metadata - we fetch on-demand when viewing const [metadataDoc, setMetadataDoc] = useState(null); + const [metadataContent, setMetadataContent] = useState(null); + const [metadataLoading, setMetadataLoading] = useState(false); // State for lazy document content viewer // Real-time documents don't sync content - we fetch on-demand when viewing @@ -166,6 +169,36 @@ export function DocumentsTableShell({ const [viewingContent, setViewingContent] = useState(""); const [viewingLoading, setViewingLoading] = useState(false); + // Fetch document metadata on-demand when metadata viewer is opened + const handleViewMetadata = useCallback(async (doc: Document) => { + setMetadataDoc(doc); + + // If metadata is already available (from API/search), use it directly + if (doc.document_metadata) { + setMetadataContent(doc.document_metadata); + return; + } + + // Otherwise, fetch from API (lazy loading for real-time synced documents) + setMetadataLoading(true); + try { + const fullDoc = await documentsApiService.getDocument({ id: doc.id }); + setMetadataContent(fullDoc.document_metadata); + } catch (err) { + console.error("[DocumentsTableShell] Failed to fetch document metadata:", err); + setMetadataContent(null); + } finally { + setMetadataLoading(false); + } + }, []); + + // Close metadata viewer + const handleCloseMetadata = useCallback(() => { + setMetadataDoc(null); + setMetadataContent(null); + setMetadataLoading(false); + }, []); + // Fetch document content on-demand when viewer is opened const handleViewDocument = useCallback(async (doc: Document) => { setViewingDoc(doc); @@ -474,7 +507,7 @@ export function DocumentsTableShell({ if (e.ctrlKey || e.metaKey) { e.preventDefault(); e.stopPropagation(); - setMetadataDoc(doc); + handleViewMetadata(doc); } else { // Normal click opens document viewer (lazy loads content) handleViewDocument(doc); @@ -484,7 +517,7 @@ export function DocumentsTableShell({ // Ctrl/Cmd + Enter opens metadata if ((e.ctrlKey || e.metaKey) && e.key === "Enter") { e.preventDefault(); - setMetadataDoc(doc); + handleViewMetadata(doc); } else if (e.key === "Enter") { // Enter opens document viewer handleViewDocument(doc); @@ -553,7 +586,7 @@ export function DocumentsTableShell({ if (e.ctrlKey || e.metaKey) { e.preventDefault(); e.stopPropagation(); - setMetadataDoc(doc); + handleViewMetadata(doc); } else { // Normal click opens document viewer (lazy loads content) handleViewDocument(doc); @@ -563,7 +596,7 @@ export function DocumentsTableShell({ // Ctrl/Cmd + Enter opens metadata if ((e.ctrlKey || e.metaKey) && e.key === "Enter") { e.preventDefault(); - setMetadataDoc(doc); + handleViewMetadata(doc); } else if (e.key === "Enter") { // Enter opens document viewer handleViewDocument(doc); @@ -602,12 +635,14 @@ export function DocumentsTableShell({ )} {/* Metadata Viewer - opened via Ctrl/Cmd+Click on document title */} + {/* Lazy loads metadata from API for real-time synced documents */} { - if (!open) setMetadataDoc(null); + if (!open) handleCloseMetadata(); }} /> diff --git a/surfsense_web/components/json-metadata-viewer.tsx b/surfsense_web/components/json-metadata-viewer.tsx index 982d16786..faab000ad 100644 --- a/surfsense_web/components/json-metadata-viewer.tsx +++ b/surfsense_web/components/json-metadata-viewer.tsx @@ -1,4 +1,4 @@ -import { FileJson } from "lucide-react"; +import { FileJson, Loader2 } from "lucide-react"; import React from "react"; import { defaultStyles, JsonView } from "react-json-view-lite"; import { Button } from "@/components/ui/button"; @@ -17,6 +17,7 @@ interface JsonMetadataViewerProps { trigger?: React.ReactNode; open?: boolean; onOpenChange?: (open: boolean) => void; + loading?: boolean; } export function JsonMetadataViewer({ @@ -25,6 +26,7 @@ export function JsonMetadataViewer({ trigger, open, onOpenChange, + loading, }: JsonMetadataViewerProps) { // Ensure metadata is a valid object const jsonData = React.useMemo(() => { @@ -54,7 +56,13 @@ export function JsonMetadataViewer({
- + {loading ? ( +
+ +
+ ) : ( + + )}