feat: refactor document opening/preview logic to support preview/sidepanel actions.

This commit is contained in:
2025-12-04 01:02:54 +01:00
parent 447b012e48
commit 8bb9f9950a
6 changed files with 37 additions and 24 deletions
+16 -3
View File
@@ -4,8 +4,8 @@ import { useNavigate } from 'react-router-dom';
import {
DocumentsFilterProvider,
} from '../documents/context/DocumentsFilterContext';
import { PreviewProvider } from '../preview/PreviewContext';
import { DocumentOpenProvider } from '../context/DocumentOpenContext';
import { PreviewProvider, usePreviewContext } from '../preview/PreviewContext';
import { DocumentOpenProvider } from '../contexts/DocumentOpenContext';
import { useWorkspaceSurface } from './useWorkspaceSurface';
import { DocumentsHeaderBreadcrumb } from '../documents/panel/DocumentsPanelHeader';
import { SidebarProvider, useSidebarContext } from '../sidebar/SidebarContext';
@@ -24,8 +24,11 @@ const DocumentsRouteContent: React.FC = () => {
const {
sidebarSuppressed,
expandSidebar,
openDetailPanel,
} = usePanelManager();
const { openPreview } = usePreviewContext();
const sidebarHidden = sidebarCollapsed || sidebarSuppressed;
const handleHeaderBreadcrumbClick = useCallback((crumb: DocumentsHeaderBreadcrumb) => {
@@ -40,6 +43,12 @@ const DocumentsRouteContent: React.FC = () => {
navigate(`/documents/${documentId}`);
}, [navigate]);
const handleOpenSidepanel = useCallback((docId: string) => {
if (openDetailPanel) {
openDetailPanel({ documentIds: [docId] });
}
}, [openDetailPanel]);
const documentsTablePropsWithNav = useMemo(() => (
surfaceConfig.documentsTableProps
? { ...surfaceConfig.documentsTableProps, onBreadcrumbNavigate: handleHeaderBreadcrumbClick }
@@ -84,7 +93,11 @@ const DocumentsRouteContent: React.FC = () => {
<PreviewProvider
onNavigate={handleDocumentNavigate}
>
<DocumentOpenProvider onOpenViewer={handleDocumentNavigate}>
<DocumentOpenProvider
onOpenViewer={handleDocumentNavigate}
onOpenPreview={openPreview}
onOpenSidepanel={handleOpenSidepanel}
>
{content}
</DocumentOpenProvider>
</PreviewProvider>
@@ -1,6 +1,4 @@
import React, { createContext, useContext, useCallback } from 'react';
import { usePreviewContext } from '../preview/PreviewContext';
import { useAppShell } from '../appShellContext';
import type { Document } from '../types/documents';
import type { Identifier } from '../types/identifiers';
@@ -20,25 +18,31 @@ export const useDocumentOpen = () => {
return context;
};
export const DocumentOpenProvider: React.FC<{ children: React.ReactNode; onOpenViewer?: (docId: Identifier) => void }> = ({ children, onOpenViewer }) => {
const { openPreview } = usePreviewContext();
const appShell = useAppShell();
// We cast appShell.openDetailPanel because AppShellContext is loosely typed
const openDetailPanel = appShell.openDetailPanel as ((args: { documentIds: Identifier[] }) => void) | undefined;
interface DocumentOpenProviderProps {
children: React.ReactNode;
onOpenViewer?: (docId: Identifier) => void;
onOpenPreview?: (doc: Document) => void;
onOpenSidepanel?: (docId: Identifier) => void;
}
export const DocumentOpenProvider: React.FC<DocumentOpenProviderProps> = ({
children,
onOpenViewer,
onOpenPreview,
onOpenSidepanel,
}) => {
const openDocument = useCallback((doc: Document, target: DocumentOpenTarget = 'preview') => {
if (!doc) return;
switch (target) {
case 'preview':
openPreview(doc);
if (onOpenPreview) {
onOpenPreview(doc);
}
break;
case 'sidepanel':
if (openDetailPanel) {
openDetailPanel({ documentIds: [doc.id] });
} else {
console.warn('openDetailPanel is not available in AppShellContext');
if (onOpenSidepanel) {
onOpenSidepanel(doc.id);
}
break;
case 'viewer':
@@ -47,7 +51,7 @@ export const DocumentOpenProvider: React.FC<{ children: React.ReactNode; onOpenV
}
break;
}
}, [openPreview, openDetailPanel, onOpenViewer]);
}, [onOpenPreview, onOpenSidepanel, onOpenViewer]);
return (
<DocumentOpenContext.Provider value={{ openDocument }}>
+1 -1
View File
@@ -19,7 +19,7 @@ import { PointerTrackingProvider, usePointerTracking } from './PointerTrackingCo
import type { Identifier } from '../types/identifiers';
import type { DocumentsListEntry, Document } from '../types/documents';
import { useAppState } from '../app/appState';
import { useDocumentOpen } from '../context/DocumentOpenContext';
import { useDocumentOpen } from '../contexts/DocumentOpenContext';
type TagLike = { id?: Identifier | null; label?: string; color?: string | null } | null;
type OverlaySource = { url: string; alt?: string | null; mimeType?: string | null; };
@@ -7,13 +7,9 @@ type FetchDocument = (id: DocumentId) => Promise<unknown>;
class DocumentsManager<T extends ManagedDocument = ManagedDocument> {
private byId: Map<DocumentId, T>;
private fetcher?: FetchDocument;
private inflight: Map<DocumentId, Promise<T | null>>;
private listeners: Set<() => void>;
private emitScheduled: boolean;
constructor(
@@ -1,7 +1,7 @@
import React, { type DragEvent } from 'react';
import { parseTagTransferPayload } from '../tagTransfer';
import { createDocumentEntryKey } from '../../app/entryKey';
import { useDocumentOpen } from '../../context/DocumentOpenContext';
import { useDocumentOpen } from '../../contexts/DocumentOpenContext';
import type { Document } from '../../types/documents';
import type { DocumentsViewProps } from '../panel/DocumentsPanel';
import type { DocumentViewLogic } from './useDocumentViewLogic';
@@ -1,7 +1,7 @@
import React, { useCallback, useMemo } from 'react';
import type { DocumentsListEntry } from '../../types/documents';
import { useWorkspaceSelectionContext } from '../../app/WorkspaceSelectionContext';
import { useDocumentOpen } from '../../context/DocumentOpenContext';
import { useDocumentOpen } from '../../contexts/DocumentOpenContext';
interface UseDocumentsNavigationProps {
entries: DocumentsListEntry[];