documentsmanager

This commit is contained in:
2025-11-19 23:36:04 +01:00
parent e1b47ed153
commit b76f1df27f
17 changed files with 564 additions and 300 deletions
@@ -1,4 +1,12 @@
import { MutableRefObject, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import {
MutableRefObject,
useCallback,
useEffect,
useMemo,
useRef,
useState,
useSyncExternalStore,
} from 'react';
import {
matchPath,
useLocation,
@@ -220,10 +228,20 @@ const useDocumentsWorkspace = ({
if (!payload) {
return null;
}
const hydratedDetail = assetManager.hydrateDetail(payload);
return hydratedDetail?.document || payload.document || payload;
return payload.document || payload;
},
[assetManager],
[],
);
const fetchDocumentById = useCallback(
async (documentId: DocumentId) => {
if (!documentId) {
return null;
}
const { data } = await api.get(`/documents/${documentId}`);
return extractDocumentFromResponse(data);
},
[extractDocumentFromResponse],
);
const tagManagerRef = useRef(null);
@@ -290,21 +308,27 @@ const useDocumentsWorkspace = ({
folderContentsRef.current = folderContents;
}, [folderContents]);
const setSearchResultsRef = useRef<(value: unknown) => void>(() => {});
const setSearchResultsProxy = useCallback((value) => {
setSearchResultsRef.current(value);
}, []);
const {
documents,
setDocuments,
removeDocumentsFromLookup,
mapDocumentCaches,
updateDocumentCaches,
documentsManager,
} = useDocuments({
setSearchResults: setSearchResultsProxy,
setFolderContents,
fetchDocumentById,
hydrateDocument: (payload) => assetManager.hydrateDocument(payload),
hydrateDocuments: (payload) => assetManager.hydrateDocuments(payload),
extractDocument: extractDocumentFromResponse,
});
const documentLookup = useSyncExternalStore(
(onStoreChange) => documentsManager.subscribe(onStoreChange),
() => documentsManager.getSnapshot(),
() => documentsManager.getSnapshot(),
);
const {
folderNodes,
setFolderNodes,
@@ -338,8 +362,8 @@ const useDocumentsWorkspace = ({
const {
searchQuery,
setSearchQuery,
searchResults,
setSearchResults,
searchResultIds,
setSearchResultIds,
searchLoading,
activeTagFilters,
setActiveTagFilters,
@@ -349,7 +373,6 @@ const useDocumentsWorkspace = ({
documentsFilterValue,
} = useDocumentsSearch({
api,
assetManager,
token,
selectedFolder,
navigate,
@@ -361,17 +384,66 @@ const useDocumentsWorkspace = ({
notifyApiError,
setLoading,
setSearchIncludeDescendants,
documentsManager,
});
const documentsFilter = documentsFilterValue;
const [visibleDocumentIds, setVisibleDocumentIds] = useState<DocumentId[]>([]);
const showingSearchResults = searchResultIds !== null;
useEffect(() => {
setSearchResultsRef.current = setSearchResults;
}, [setSearchResults]);
const arraysEqual = (a: DocumentId[], b: DocumentId[]) =>
a.length === b.length && a.every((value, index) => value === b[index]);
if (showingSearchResults && Array.isArray(searchResultIds)) {
const ids = searchResultIds.filter((id): id is DocumentId => id != null);
setVisibleDocumentIds((prev) => (arraysEqual(prev, ids) ? prev : ids));
return;
}
const folderIds = documents
.map((doc) => (doc?.id ?? null) as DocumentId | null)
.filter((id): id is DocumentId => id != null);
setVisibleDocumentIds((prev) => (arraysEqual(prev, folderIds) ? prev : folderIds));
}, [showingSearchResults, searchResultIds, documents]);
const viewDocuments = useMemo(
() =>
visibleDocumentIds
.map((id) => documentLookup.get(id) || null)
.filter((doc): doc is DocumentLike => Boolean(doc)),
[visibleDocumentIds, documentLookup],
);
const visibleDocumentKeys = useMemo(
() => visibleDocumentIds.map((id) => resolveDocumentRowKey(id)).filter(Boolean),
[visibleDocumentIds],
);
const visibleFolderKeys = useMemo(
() =>
showingSearchResults
? []
: currentSubfolders
.map((folder) => resolveFolderRowKey(folder.id))
.filter(Boolean),
[showingSearchResults, currentSubfolders],
);
const visibleRowKeys = useMemo(
() => [...visibleFolderKeys, ...visibleDocumentKeys],
[visibleFolderKeys, visibleDocumentKeys],
);
const visibleRowKeySet = useMemo(
() => new Set(visibleRowKeys),
[visibleRowKeys],
);
const {
documentLinks,
previewDocuments,
ensurePreviewData,
ensureDownloadUrl,
openDocumentPreview,
@@ -380,8 +452,7 @@ const useDocumentsWorkspace = ({
removeDocumentLinks,
} = useDocumentPreview({
routeDocumentId: previewDocumentId,
documents,
searchResults,
documentsManager,
selectedFolder,
assetManager,
api,
@@ -414,65 +485,6 @@ const useDocumentsWorkspace = ({
const detailFolderFetchRef = useRef(new Set());
const showingSearchResults = searchResults !== null;
const visibleDocuments = useMemo(
() => (showingSearchResults ? searchResults : documents),
[showingSearchResults, searchResults, documents],
);
const visibleDocumentIds = useMemo(
() => visibleDocuments.map((doc) => doc.id),
[visibleDocuments],
);
const visibleDocumentKeys = useMemo(
() => visibleDocumentIds.map((id) => resolveDocumentRowKey(id)).filter(Boolean),
[visibleDocumentIds],
);
const visibleFolderKeys = useMemo(
() =>
showingSearchResults
? []
: currentSubfolders
.map((folder) => resolveFolderRowKey(folder.id))
.filter(Boolean),
[showingSearchResults, currentSubfolders],
);
const visibleRowKeys = useMemo(
() => [...visibleFolderKeys, ...visibleDocumentKeys],
[visibleFolderKeys, visibleDocumentKeys],
);
const visibleRowKeySet = useMemo(
() => new Set(visibleRowKeys),
[visibleRowKeys],
);
const documentLookup = useMemo(() => {
const map = new Map();
const push = (items) => {
(items || []).forEach((doc) => {
if (doc?.id) {
map.set(doc.id, doc);
}
});
};
push(documents);
if (Array.isArray(searchResults)) {
push(searchResults);
}
previewDocuments.forEach((doc, id) => {
if (doc && id && !map.has(id)) {
map.set(id, doc);
}
});
return map;
}, [documents, searchResults, previewDocuments]);
useEffect(() => {
if (!showingSearchResults) {
return;
@@ -696,7 +708,7 @@ const useDocumentsWorkspace = ({
selectionAnchorRef.current = null;
setDraggedDocumentIds([]);
setDraggedFolderId(null);
setSearchResults(null);
setSearchResultIds(null);
setTags([]);
setCorrespondents([]);
setSearchQuery('');
@@ -729,7 +741,7 @@ const useDocumentsWorkspace = ({
setDocuments,
setDraggedDocumentIds,
setDraggedFolderId,
setSearchResults,
setSearchResultIds,
setTags,
setCorrespondents,
setSearchQuery,
@@ -757,11 +769,11 @@ const useDocumentsWorkspace = ({
const idSet = new Set<DocumentId>(documentIds);
setDocuments((prev) => prev.filter((doc) => !idSet.has(doc.id)));
setSearchResults((prev) => {
setSearchResultIds((prev) => {
if (!Array.isArray(prev)) {
return prev;
}
const filtered = prev.filter((doc) => !idSet.has(doc.id));
const filtered = prev.filter((id) => !idSet.has(id as DocumentId));
return filtered.length === prev.length ? prev : filtered;
});
@@ -788,9 +800,16 @@ const useDocumentsWorkspace = ({
return changed ? next : prev;
});
removeDocumentsFromLookup(Array.from(idSet));
removeDocumentLinks(Array.from(idSet));
},
[setDocuments, setSearchResults, setFolderContents, removeDocumentLinks],
[
setDocuments,
setSearchResultIds,
setFolderContents,
removeDocumentsFromLookup,
removeDocumentLinks,
],
);
const {
@@ -812,7 +831,7 @@ const useDocumentsWorkspace = ({
setSelectedFolder,
setDocuments,
setFolderContents,
setSearchResults,
setSearchResultIds,
setSelectedEntries,
setSelectionOrder,
selectionOrderRef,
@@ -864,7 +883,7 @@ const useDocumentsWorkspace = ({
setLoading,
setFolderContents,
setCurrentFolder,
setSearchResults,
setSearchResultIds,
isFilterActive,
navigate,
handleFileDrop,
@@ -883,7 +902,7 @@ const useDocumentsWorkspace = ({
} = useDocumentsSelection({
showingSearchResults,
currentSubfolders,
visibleDocuments,
visibleDocuments: viewDocuments,
resolveFolderRowKey,
resolveDocumentRowKey,
configureSelectionEnvironment,
@@ -1021,19 +1040,13 @@ const useDocumentsWorkspace = ({
prev.map((doc) => (doc.id === documentId ? mergeAssetIntoDocument(doc, entry) : doc)),
);
setSearchResults((prev) =>
Array.isArray(prev)
? prev.map((doc) => (doc.id === documentId ? mergeAssetIntoDocument(doc, entry) : doc))
: prev,
);
return entry;
} catch (error) {
notifyApiError(error, 'Unable to refresh document asset.');
throw error;
}
},
[assetManager, setDocuments, setSearchResults, notifyApiError],
[assetManager, setDocuments, notifyApiError],
);
@@ -1233,9 +1246,7 @@ const useDocumentsWorkspace = ({
documentLink,
resolveFolderPath,
} = useDetailWorkspace({
documents,
searchResults,
previewDocuments,
documents: viewDocuments,
selectionOrder,
selectedDocumentIds,
documentLookup,
@@ -1446,8 +1457,7 @@ const useDocumentsWorkspace = ({
const deskWorkspaceProps = useMemo(
() => ({
documents,
searchResults,
documents: viewDocuments,
onInspectDocument: inspectDocumentForDesk,
onEntryPointer: handleEntryPointerCore,
onDocumentStackSelect: handleDeskDocumentStackSelect,
@@ -1464,8 +1474,7 @@ const useDocumentsWorkspace = ({
ensureDownloadUrl,
}),
[
documents,
searchResults,
viewDocuments,
inspectDocumentForDesk,
handleEntryPointerCore,
handleDeskDocumentStackSelect,
@@ -1488,8 +1497,8 @@ const useDocumentsWorkspace = ({
breadcrumbs,
refreshCurrentFolder,
currentSubfolders,
documents,
searchResults,
documents: viewDocuments,
searchResultIds,
folderClickHandlers,
handleFolderDragStart,
handleFolderDragEnd,