Remove document link and download URL management from frontend components

This commit is contained in:
2025-12-04 00:23:27 +01:00
parent 4b02d1c7d5
commit 9f88823315
4 changed files with 3 additions and 127 deletions
+3 -104
View File
@@ -1,23 +1,15 @@
import { useCallback, useEffect, useRef, useState } from 'react'; import { useCallback, useEffect, useRef } from 'react';
import type { import type {
Dispatch, Dispatch,
MutableRefObject, MutableRefObject,
SetStateAction, SetStateAction,
} from 'react'; } from 'react';
import { fetchDocument } from '../lib/apiClient';
import type { DocumentId } from '../types/identifiers'; import type { DocumentId } from '../types/identifiers';
type FolderId = DocumentId | 'root'; type FolderId = DocumentId | 'root';
import type { Document } from '../types/documents'; import type { Document } from '../types/documents';
type DocumentLink = {
url?: string;
mimeType?: string | null;
filename?: string | null;
expiresAt?: number;
};
type NavigateHandler = (path: string, options?: { replace?: boolean }) => void; type NavigateHandler = (path: string, options?: { replace?: boolean }) => void;
interface UseDocumentPreviewArgs { interface UseDocumentPreviewArgs {
@@ -42,13 +34,10 @@ interface UseDocumentPreviewArgs {
} }
interface UseDocumentPreviewResult { interface UseDocumentPreviewResult {
documentLinks: Map<DocumentId, DocumentLink>;
ensureDownloadUrl: (documentId: DocumentId, options?: { force?: boolean }) => Promise<DocumentLink | null>;
ensurePreviewData: (documentId: DocumentId) => Promise<Document | null>; ensurePreviewData: (documentId: DocumentId) => Promise<Document | null>;
openDocumentPreview: (documentId: DocumentId, options?: { replace?: boolean }) => void; openDocumentPreview: (documentId: DocumentId, options?: { replace?: boolean }) => void;
closeDocumentPreview: (folderId?: FolderId) => void; closeDocumentPreview: (folderId?: FolderId) => void;
resetPreviewState: () => void; resetPreviewState: () => void;
removeDocumentLinks: (ids: DocumentId[]) => void;
} }
const useDocumentPreview = ({ const useDocumentPreview = ({
@@ -62,105 +51,20 @@ const useDocumentPreview = ({
detailPanelControlRef, detailPanelControlRef,
setActivePreviewId, setActivePreviewId,
}: UseDocumentPreviewArgs): UseDocumentPreviewResult => { }: UseDocumentPreviewArgs): UseDocumentPreviewResult => {
const [documentLinks, setDocumentLinks] = useState<Map<DocumentId, DocumentLink>>(() => new Map());
const previewInflightRef = useRef<Map<DocumentId, Promise<DocumentLink | null>>>(new Map());
const previewReturnPathRef = useRef<string | null>(null); const previewReturnPathRef = useRef<string | null>(null);
const resetPreviewState = useCallback(() => { const resetPreviewState = useCallback(() => {
setDocumentLinks(() => new Map());
previewInflightRef.current = new Map();
previewReturnPathRef.current = null; previewReturnPathRef.current = null;
}, []); }, []);
const removeDocumentLinks = useCallback((ids: DocumentId[]) => {
if (!Array.isArray(ids) || ids.length === 0) {
return;
}
setDocumentLinks((prev) => {
if (!prev.size) {
return prev;
}
let changed = false;
const next = new Map(prev);
ids.forEach((id) => {
if (next.delete(id)) {
changed = true;
}
previewInflightRef.current.delete(id);
});
return changed ? next : prev;
});
}, []);
const ensureDownloadUrl = useCallback(
async (documentId: DocumentId, { force = false }: { force?: boolean } = {}): Promise<DocumentLink | null> => {
if (!documentId) return null;
const existing = documentLinks.get(documentId);
const now = Date.now();
const expiresAt = existing?.expiresAt ?? null;
if (!force && existing && (!expiresAt || expiresAt > now)) {
return existing;
}
if (!force && previewInflightRef.current.has(documentId)) {
return previewInflightRef.current.get(documentId) || null;
}
const request: Promise<DocumentLink | null> = (async () => {
try {
const docResponse = await fetchDocument(documentId);
const download = docResponse?.current_version?.download || null;
const downloadUrl = download?.url;
if (!downloadUrl) {
throw new Error('Document missing download url');
}
const entry: DocumentLink = {
url: downloadUrl,
mimeType: docResponse?.mime_type || null,
filename: docResponse?.filename,
expiresAt: download?.expires_at,
};
setDocumentLinks((prev) => {
const next = new Map(prev);
next.set(documentId, entry);
return next;
});
return entry;
} catch (error) {
notifyApiError(error, 'Unable to fetch document preview.');
throw error;
} finally {
previewInflightRef.current.delete(documentId);
}
})();
previewInflightRef.current.set(documentId, request);
return request;
},
[documentLinks, notifyApiError],
);
const ensurePreviewData = useCallback( const ensurePreviewData = useCallback(
async (documentId: DocumentId): Promise<Document | null> => { async (documentId: DocumentId): Promise<Document | null> => {
if (!documentId) return null; if (!documentId) return null;
const findInCache = () => documentsManager.getById(documentId); const doc = await documentsManager.ensure(documentId);
let doc = findInCache();
if (!doc) { if (!doc) {
doc = await documentsManager.ensure(documentId); throw new Error('Document metadata unavailable.');
}
if (!doc) {
const fetched = await fetchDocument(documentId);
const { canonical } = documentsManager.ingest([fetched as unknown]);
doc = (canonical[0] as Document | undefined) || null;
if (!doc) {
throw new Error('Document metadata unavailable.');
}
} }
if (!previewReturnPathRef.current) { if (!previewReturnPathRef.current) {
@@ -169,13 +73,11 @@ const useDocumentPreview = ({
fallbackFolderId === 'root' ? '/documents' : `/documents/folder/${fallbackFolderId}`; fallbackFolderId === 'root' ? '/documents' : `/documents/folder/${fallbackFolderId}`;
} }
await ensureDownloadUrl(documentId, { force: false });
setActivePreviewId(documentId); setActivePreviewId(documentId);
return doc; return doc;
}, },
[ [
documentsManager, documentsManager,
ensureDownloadUrl,
setActivePreviewId, setActivePreviewId,
], ],
); );
@@ -228,13 +130,10 @@ const useDocumentPreview = ({
}, [routeDocumentId, ensurePreviewData, notifyApiError, closeDocumentPreview]); }, [routeDocumentId, ensurePreviewData, notifyApiError, closeDocumentPreview]);
return { return {
documentLinks,
ensureDownloadUrl,
ensurePreviewData, ensurePreviewData,
openDocumentPreview, openDocumentPreview,
closeDocumentPreview, closeDocumentPreview,
resetPreviewState, resetPreviewState,
removeDocumentLinks,
}; };
}; };
@@ -2,11 +2,6 @@ import { useMemo } from 'react';
import type { WorkspaceSelectionValue } from '../../app/WorkspaceSelectionContext'; import type { WorkspaceSelectionValue } from '../../app/WorkspaceSelectionContext';
import type { Identifier } from '../../types/identifiers'; import type { Identifier } from '../../types/identifiers';
interface DocumentLinkLike {
url?: string | null;
mimeType?: string | null;
}
export interface Breadcrumb { export interface Breadcrumb {
id?: Identifier; id?: Identifier;
name?: string; name?: string;
@@ -68,8 +63,6 @@ export interface UseDocumentsPanelPropsArgs {
handleBulkSelectionReanalyze?: (...args: unknown[]) => void; handleBulkSelectionReanalyze?: (...args: unknown[]) => void;
folderOptions?: unknown[]; folderOptions?: unknown[];
moveDocumentsToFolder?: (...args: unknown[]) => void; moveDocumentsToFolder?: (...args: unknown[]) => void;
documentLinks?: Map<Identifier, DocumentLinkLike>;
ensureDownloadUrl?: (documentId: Identifier, options?: { force?: boolean }) => Promise<DocumentLinkLike | null>;
selectionValue: WorkspaceSelectionValue; selectionValue: WorkspaceSelectionValue;
currentTenantId?: Identifier | null; currentTenantId?: Identifier | null;
} }
@@ -124,8 +117,6 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
handleBulkSelectionReanalyze, handleBulkSelectionReanalyze,
folderOptions, folderOptions,
moveDocumentsToFolder, moveDocumentsToFolder,
documentLinks,
ensureDownloadUrl,
selectionValue, selectionValue,
currentTenantId, currentTenantId,
} = props; } = props;
@@ -181,8 +172,6 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
onBulkReanalyze: handleBulkSelectionReanalyze, onBulkReanalyze: handleBulkSelectionReanalyze,
folderOptions, folderOptions,
onMoveDocumentsToFolder: moveDocumentsToFolder, onMoveDocumentsToFolder: moveDocumentsToFolder,
documentLinks,
ensureDownloadUrl,
selectionValue, selectionValue,
currentTenantId, currentTenantId,
}), }),
@@ -233,8 +222,6 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
ensureAssetUrl, ensureAssetUrl,
getDocumentAsset, getDocumentAsset,
folderOptions, folderOptions,
documentLinks,
ensureDownloadUrl,
selectionValue, selectionValue,
currentTenantId, currentTenantId,
], ],
@@ -51,8 +51,6 @@ interface DocumentsPanelProps extends DocumentsPanelInnerProps {
selectionValue: WorkspaceSelectionValue; selectionValue: WorkspaceSelectionValue;
} }
export type DocumentLinkLike = { url?: string | null; mimeType?: string | null };
export interface DocumentsViewProps { export interface DocumentsViewProps {
entries: DocumentsListEntry[]; entries: DocumentsListEntry[];
draggingDocumentIdsSet?: Set<Identifier> | null; draggingDocumentIdsSet?: Set<Identifier> | null;
@@ -85,7 +83,6 @@ export interface DocumentsViewProps {
// Desk specific (optional for now or handled via intersection) // Desk specific (optional for now or handled via intersection)
tenantId?: Identifier | null; tenantId?: Identifier | null;
viewId?: string | null; viewId?: string | null;
ensureDownloadUrl?: (docId: Identifier, options?: { force?: boolean }) => Promise<any>;
activeTagFilters?: Array<Identifier | null>; activeTagFilters?: Array<Identifier | null>;
} }
@@ -432,12 +432,9 @@ const useDocumentsWorkspace = ({
); );
const { const {
documentLinks,
ensureDownloadUrl,
openDocumentPreview, openDocumentPreview,
closeDocumentPreview, closeDocumentPreview,
resetPreviewState, resetPreviewState,
removeDocumentLinks,
} = useDocumentPreview({ } = useDocumentPreview({
routeDocumentId: previewDocumentId, routeDocumentId: previewDocumentId,
documentsManager, documentsManager,
@@ -719,14 +716,12 @@ const useDocumentsWorkspace = ({
}); });
removeDocumentsFromLookup(Array.from(idSet)); removeDocumentsFromLookup(Array.from(idSet));
removeDocumentLinks(Array.from(idSet));
}, },
[ [
setDocuments, setDocuments,
setSearchResultIds, setSearchResultIds,
setFolderContents, setFolderContents,
removeDocumentsFromLookup, removeDocumentsFromLookup,
removeDocumentLinks,
], ],
); );
@@ -1195,8 +1190,6 @@ const useDocumentsWorkspace = ({
folderOptions, folderOptions,
moveDocumentsToFolder, moveDocumentsToFolder,
selectFolder, selectFolder,
documentLinks,
ensureDownloadUrl,
selectionValue: selection, selectionValue: selection,
currentTenantId, currentTenantId,
}); });