feat: enhance metadata viewing in DocumentsTableShell with on-demand fetching and loading state

This commit is contained in:
Anish Sarkar 2026-02-04 22:34:03 +05:30
parent c19aa5fa99
commit c706b5f417
2 changed files with 51 additions and 8 deletions

View file

@ -158,7 +158,10 @@ export function DocumentsTableShell({
const { openDialog } = useDocumentUploadDialog(); const { openDialog } = useDocumentUploadDialog();
// State for metadata viewer (opened via Ctrl/Cmd+Click) // 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<Document | null>(null); const [metadataDoc, setMetadataDoc] = useState<Document | null>(null);
const [metadataContent, setMetadataContent] = useState<any>(null);
const [metadataLoading, setMetadataLoading] = useState(false);
// State for lazy document content viewer // State for lazy document content viewer
// Real-time documents don't sync content - we fetch on-demand when viewing // Real-time documents don't sync content - we fetch on-demand when viewing
@ -166,6 +169,36 @@ export function DocumentsTableShell({
const [viewingContent, setViewingContent] = useState<string>(""); const [viewingContent, setViewingContent] = useState<string>("");
const [viewingLoading, setViewingLoading] = useState(false); 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 // Fetch document content on-demand when viewer is opened
const handleViewDocument = useCallback(async (doc: Document) => { const handleViewDocument = useCallback(async (doc: Document) => {
setViewingDoc(doc); setViewingDoc(doc);
@ -474,7 +507,7 @@ export function DocumentsTableShell({
if (e.ctrlKey || e.metaKey) { if (e.ctrlKey || e.metaKey) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
setMetadataDoc(doc); handleViewMetadata(doc);
} else { } else {
// Normal click opens document viewer (lazy loads content) // Normal click opens document viewer (lazy loads content)
handleViewDocument(doc); handleViewDocument(doc);
@ -484,7 +517,7 @@ export function DocumentsTableShell({
// Ctrl/Cmd + Enter opens metadata // Ctrl/Cmd + Enter opens metadata
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") { if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
e.preventDefault(); e.preventDefault();
setMetadataDoc(doc); handleViewMetadata(doc);
} else if (e.key === "Enter") { } else if (e.key === "Enter") {
// Enter opens document viewer // Enter opens document viewer
handleViewDocument(doc); handleViewDocument(doc);
@ -553,7 +586,7 @@ export function DocumentsTableShell({
if (e.ctrlKey || e.metaKey) { if (e.ctrlKey || e.metaKey) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
setMetadataDoc(doc); handleViewMetadata(doc);
} else { } else {
// Normal click opens document viewer (lazy loads content) // Normal click opens document viewer (lazy loads content)
handleViewDocument(doc); handleViewDocument(doc);
@ -563,7 +596,7 @@ export function DocumentsTableShell({
// Ctrl/Cmd + Enter opens metadata // Ctrl/Cmd + Enter opens metadata
if ((e.ctrlKey || e.metaKey) && e.key === "Enter") { if ((e.ctrlKey || e.metaKey) && e.key === "Enter") {
e.preventDefault(); e.preventDefault();
setMetadataDoc(doc); handleViewMetadata(doc);
} else if (e.key === "Enter") { } else if (e.key === "Enter") {
// Enter opens document viewer // Enter opens document viewer
handleViewDocument(doc); handleViewDocument(doc);
@ -602,12 +635,14 @@ export function DocumentsTableShell({
)} )}
{/* Metadata Viewer - opened via Ctrl/Cmd+Click on document title */} {/* Metadata Viewer - opened via Ctrl/Cmd+Click on document title */}
{/* Lazy loads metadata from API for real-time synced documents */}
<JsonMetadataViewer <JsonMetadataViewer
title={metadataDoc?.title ?? ""} title={metadataDoc?.title ?? ""}
metadata={metadataDoc?.document_metadata} metadata={metadataContent}
loading={metadataLoading}
open={!!metadataDoc} open={!!metadataDoc}
onOpenChange={(open) => { onOpenChange={(open) => {
if (!open) setMetadataDoc(null); if (!open) handleCloseMetadata();
}} }}
/> />

View file

@ -1,4 +1,4 @@
import { FileJson } from "lucide-react"; import { FileJson, Loader2 } from "lucide-react";
import React from "react"; import React from "react";
import { defaultStyles, JsonView } from "react-json-view-lite"; import { defaultStyles, JsonView } from "react-json-view-lite";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
@ -17,6 +17,7 @@ interface JsonMetadataViewerProps {
trigger?: React.ReactNode; trigger?: React.ReactNode;
open?: boolean; open?: boolean;
onOpenChange?: (open: boolean) => void; onOpenChange?: (open: boolean) => void;
loading?: boolean;
} }
export function JsonMetadataViewer({ export function JsonMetadataViewer({
@ -25,6 +26,7 @@ export function JsonMetadataViewer({
trigger, trigger,
open, open,
onOpenChange, onOpenChange,
loading,
}: JsonMetadataViewerProps) { }: JsonMetadataViewerProps) {
// Ensure metadata is a valid object // Ensure metadata is a valid object
const jsonData = React.useMemo(() => { const jsonData = React.useMemo(() => {
@ -54,7 +56,13 @@ export function JsonMetadataViewer({
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
<div className="mt-2 sm:mt-4 p-2 sm:p-4 bg-muted/30 rounded-md text-xs sm:text-sm"> <div className="mt-2 sm:mt-4 p-2 sm:p-4 bg-muted/30 rounded-md text-xs sm:text-sm">
<JsonView data={jsonData} style={defaultStyles} /> {loading ? (
<div className="flex items-center justify-center py-12">
<Loader2 className="h-8 w-8 animate-spin text-muted-foreground" />
</div>
) : (
<JsonView data={jsonData} style={defaultStyles} />
)}
</div> </div>
</DialogContent> </DialogContent>
</Dialog> </Dialog>