From 03bc311403aed85c30e8271dacb23f72a774947a Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Sat, 1 Nov 2025 19:39:51 +0100 Subject: [PATCH] detailpanel --- frontend/src/app/AppLayout.jsx | 63 +++++++++---------- frontend/src/detail/DetailPanel.jsx | 47 +++++++++++++- .../src/documents/DocumentSummarySection.jsx | 11 +++- frontend/src/preview/PreviewWorkspace.jsx | 17 +++++ frontend/src/ui/BreadcrumbTrail.jsx | 56 ++++++++++++----- 5 files changed, 142 insertions(+), 52 deletions(-) diff --git a/frontend/src/app/AppLayout.jsx b/frontend/src/app/AppLayout.jsx index 9992867..062ce6d 100644 --- a/frontend/src/app/AppLayout.jsx +++ b/frontend/src/app/AppLayout.jsx @@ -484,6 +484,8 @@ const AppLayout = () => { [selectedRowKeys], ); + const selectionCount = selectedDocumentIds.length; + const selectedFolderIds = useMemo( () => selectedRowKeys @@ -493,30 +495,9 @@ const AppLayout = () => { [selectedRowKeys], ); - const [detailPanelOpen, setDetailPanelOpen] = useState(() => selectedDocumentIds.length > 0); + const [detailPanelOpen, setDetailPanelOpen] = useState(false); const [detailPanelDocIds, setDetailPanelDocIds] = useState([]); const [detailPanelDocs, setDetailPanelDocs] = useState([]); - const detailPanelAutoOpenRef = useRef(true); - const detailPanelSelectionTokenRef = useRef(selectedDocumentIds.join('|')); - - useEffect(() => { - const token = selectedDocumentIds.join('|'); - if (token !== detailPanelSelectionTokenRef.current) { - detailPanelSelectionTokenRef.current = token; - detailPanelAutoOpenRef.current = true; - } - - if (selectedDocumentIds.length === 0) { - if (detailPanelOpen) { - setDetailPanelOpen(false); - } - return; - } - - if (!detailPanelOpen && detailPanelAutoOpenRef.current && !previewDocumentId) { - setDetailPanelOpen(true); - } - }, [selectedDocumentIds, detailPanelOpen, previewDocumentId]); const resetWorkspaceState = useCallback(() => { const rootNode = createRootNode(); @@ -1164,16 +1145,30 @@ const AppLayout = () => { applySelection(nextKeys, { anchor: anchorKey, interactedKeys }); }, - [applySelection, navigableRowKeys, selectedRowKeys, setFocusedRowKey, visibleRowKeySet], + [ + applySelection, + navigableRowKeys, + selectedRowKeys, + setFocusedRowKey, + visibleRowKeySet, + ], ); + const openDetailPanel = useCallback(() => { + setDetailPanelOpen(true); + }, []); + const handleDocumentRowClick = useCallback( (documentId, event) => { const rowKey = resolveDocumentRowKey(documentId); if (!rowKey) return; + const hadSelection = selectionCount > 0; handleRowSelection(rowKey, event); + if (!hadSelection) { + openDetailPanel(); + } }, - [handleRowSelection], + [handleRowSelection, openDetailPanel, selectionCount], ); const clearDocumentSelection = useCallback(() => { @@ -3397,7 +3392,6 @@ const AppLayout = () => { const openDocumentPreview = useCallback( (documentId, { replace = false } = {}) => { if (!documentId) return; - detailPanelAutoOpenRef.current = false; setDetailPanelOpen(false); previewReturnPathRef.current = `${location.pathname}${location.search}`; navigate(`/documents/${documentId}`, { replace }); @@ -3502,6 +3496,9 @@ const AppLayout = () => { if (row.type === 'folder') { selectFolder(row.id); } else if (row.type === 'document') { + if (selectionCount === 0) { + openDetailPanel(); + } openDocumentPreview(row.id); } return; @@ -3534,10 +3531,14 @@ const AppLayout = () => { setFocusedRowKey(targetRow.key); + const hadSelection = selectionCount > 0; handleRowSelection(targetRow.key, { shiftKey, preventDefault: () => {}, }); + if (targetRow.type === 'document' && !hadSelection) { + openDetailPanel(); + } }, [ navigableRows, @@ -3545,8 +3546,10 @@ const AppLayout = () => { focusedRowKey, selectedRowKeys, handleRowSelection, + openDetailPanel, selectFolder, openDocumentPreview, + selectionCount, ], ); @@ -5151,12 +5154,8 @@ const AppLayout = () => { ); const handleDetailPanelClose = useCallback(() => { - detailPanelAutoOpenRef.current = false; setDetailPanelOpen(false); - clearDocumentSelection(); - setDetailPanelDocIds([]); - setDetailPanelDocs([]); - }, [clearDocumentSelection]); + }, []); const detailPanelProps = useMemo( () => ({ @@ -5315,7 +5314,7 @@ const AppLayout = () => { openCorrespondentsModal, openSettings, detailPanelOpen, - setDetailPanelOpen, + openDetailPanel, }), [ token, @@ -5375,7 +5374,7 @@ const AppLayout = () => { openCorrespondentsModal, openSettings, detailPanelOpen, - setDetailPanelOpen, + openDetailPanel, ], ); diff --git a/frontend/src/detail/DetailPanel.jsx b/frontend/src/detail/DetailPanel.jsx index 8da5dbe..40f9592 100644 --- a/frontend/src/detail/DetailPanel.jsx +++ b/frontend/src/detail/DetailPanel.jsx @@ -21,6 +21,7 @@ import DocumentSummarySection, { sortCorrespondents, buildCorrespondentOptions, } from '../documents/DocumentSummarySection'; +import BreadcrumbTrail from '../ui/BreadcrumbTrail'; const MAX_PREVIEW_STACK_ITEMS = 15; @@ -192,6 +193,39 @@ const DetailPanel = ({ return `${selectedCount} document${selectedCount === 1 ? '' : 's'}`; }, [selectedCount, detailSummary]); + const headerBreadcrumbs = useMemo(() => { + if (selectedCount !== 1 || !singleDoc || typeof resolveFolderPath !== 'function') { + return null; + } + + const handleNavigate = (folderId) => { + if (!folderId || typeof onFolderNavigate !== 'function') { + return; + } + onFolderNavigate(folderId); + }; + + const folderSegments = resolveFolderPath(singleDoc.folder_id); + const normalizedSegments = Array.isArray(folderSegments) + ? folderSegments + .filter((segment) => segment && segment.id && segment.name) + .map((segment) => ({ + id: segment.id, + label: segment.name, + onClick: segment.id ? () => handleNavigate(segment.id) : null, + })) + : []; + + const documentLabel = detailSummary.title || 'Document'; + return [ + ...normalizedSegments, + { + id: singleDoc.id || 'current-document', + label: documentLabel, + }, + ]; + }, [selectedCount, singleDoc, resolveFolderPath, detailSummary, onFolderNavigate]); + const [zoomedPreview, setZoomedPreview] = useState(null); const bulkDocumentIds = useMemo( @@ -933,7 +967,18 @@ const DetailPanel = ({