This commit is contained in:
2025-11-18 14:17:53 +01:00
parent ea6e42175a
commit 3e21e72953
11 changed files with 118 additions and 130 deletions
+3 -3
View File
@@ -35,7 +35,7 @@ interface DocumentsRouteAppShell {
openTagsModal?: () => void;
openCorrespondentsModal?: () => void;
previewWorkspaceDocument?: unknown;
previewWorkspaceEntry?: unknown;
documentLink?: unknown;
previewDocumentId?: Identifier | null;
closeDocumentPreview?: () => void;
ensurePreviewData?: EnsurePreviewData;
@@ -54,7 +54,7 @@ const DocumentsRouteContent: React.FC = () => {
openTagsModal,
openCorrespondentsModal,
previewWorkspaceDocument,
previewWorkspaceEntry,
documentLink,
previewDocumentId,
closeDocumentPreview,
ensurePreviewData,
@@ -107,7 +107,7 @@ const DocumentsRouteContent: React.FC = () => {
detailPanelProps,
detailPanelOpen,
previewWorkspaceDocument,
previewWorkspaceEntry,
documentLink,
previewDocumentId,
ensureAssetUrl,
ensurePreviewData,
+17 -17
View File
@@ -16,7 +16,7 @@ type DocumentLike = {
[key: string]: unknown;
};
type PreviewEntry = {
type DocumentLink = {
url?: string;
contentType?: string | null;
filename?: string | null;
@@ -54,14 +54,14 @@ interface UseDocumentPreviewArgs {
}
interface UseDocumentPreviewResult {
previewEntries: Map<DocumentId, PreviewEntry>;
documentLinks: Map<DocumentId, DocumentLink>;
previewDocuments: Map<DocumentId, DocumentLike>;
ensureDownloadUrl: (documentId: DocumentId, options?: { force?: boolean }) => Promise<PreviewEntry | null>;
ensureDownloadUrl: (documentId: DocumentId, options?: { force?: boolean }) => Promise<DocumentLink | null>;
ensurePreviewData: (documentId: DocumentId) => Promise<DocumentLike | null>;
openDocumentPreview: (documentId: DocumentId, options?: { replace?: boolean }) => void;
closeDocumentPreview: (folderId?: FolderId) => void;
resetPreviewState: () => void;
removePreviewEntries: (ids: DocumentId[]) => void;
removeDocumentLinks: (ids: DocumentId[]) => void;
}
const useDocumentPreview = ({
@@ -79,22 +79,22 @@ const useDocumentPreview = ({
detailPanelControlRef,
setActivePreviewId,
}: UseDocumentPreviewArgs): UseDocumentPreviewResult => {
const [previewEntries, setPreviewEntries] = useState<Map<DocumentId, PreviewEntry>>(() => new Map());
const [documentLinks, setDocumentLinks] = useState<Map<DocumentId, DocumentLink>>(() => new Map());
const [previewDocuments, setPreviewDocuments] = useState<Map<DocumentId, DocumentLike>>(() => new Map());
const previewInflightRef = useRef<Map<DocumentId, Promise<PreviewEntry | null>>>(new Map());
const previewInflightRef = useRef<Map<DocumentId, Promise<DocumentLink | null>>>(new Map());
const previewReturnPathRef = useRef<string | null>(null);
const resetPreviewState = useCallback(() => {
setPreviewEntries(() => new Map());
setDocumentLinks(() => new Map());
previewInflightRef.current = new Map();
previewReturnPathRef.current = null;
}, []);
const removePreviewEntries = useCallback((ids: DocumentId[]) => {
const removeDocumentLinks = useCallback((ids: DocumentId[]) => {
if (!Array.isArray(ids) || ids.length === 0) {
return;
}
setPreviewEntries((prev) => {
setDocumentLinks((prev) => {
if (!prev.size) {
return prev;
}
@@ -140,10 +140,10 @@ const useDocumentPreview = ({
}, []);
const ensureDownloadUrl = useCallback(
async (documentId: DocumentId, { force = false }: { force?: boolean } = {}): Promise<PreviewEntry | null> => {
async (documentId: DocumentId, { force = false }: { force?: boolean } = {}): Promise<DocumentLink | null> => {
if (!documentId) return null;
const existing = previewEntries.get(documentId) || null;
const existing = documentLinks.get(documentId) || null;
const now = Date.now();
const expiresAt = Number.isFinite(existing?.expiresAt) ? Number(existing?.expiresAt) : null;
if (!force && existing && (!expiresAt || expiresAt > now)) {
@@ -154,7 +154,7 @@ const useDocumentPreview = ({
return previewInflightRef.current.get(documentId) || null;
}
const request: Promise<PreviewEntry | null> = (async () => {
const request: Promise<DocumentLink | null> = (async () => {
try {
const docResponse = await api.get<{ document?: Record<string, any> }>(`/documents/${documentId}`);
const downloadPath = docResponse.data?.document?.current_version?.download_path;
@@ -163,13 +163,13 @@ const useDocumentPreview = ({
}
const href = resolveApiPath(downloadPath);
const entry: PreviewEntry = {
const entry: DocumentLink = {
url: href,
contentType: docResponse.data?.document?.current_version?.version?.content_type || null,
filename: docResponse.data?.document?.filename,
expiresAt: Date.now() + 5 * 60 * 1000,
};
setPreviewEntries((prev) => {
setDocumentLinks((prev) => {
const next = new Map(prev);
next.set(documentId, entry);
return next;
@@ -186,7 +186,7 @@ const useDocumentPreview = ({
previewInflightRef.current.set(documentId, request);
return request;
},
[previewEntries, api, resolveApiPath, notifyApiError],
[documentLinks, api, resolveApiPath, notifyApiError],
);
const ensurePreviewData = useCallback(
@@ -330,14 +330,14 @@ const useDocumentPreview = ({
}, [documents, searchResults]);
return {
previewEntries,
documentLinks,
previewDocuments,
ensureDownloadUrl,
ensurePreviewData,
openDocumentPreview,
closeDocumentPreview,
resetPreviewState,
removePreviewEntries,
removeDocumentLinks,
};
};
+4 -4
View File
@@ -24,7 +24,7 @@ interface UseWorkspaceSurfaceArgs {
detailPanelProps?: (Record<string, any> & { onClose?: () => void }) | null;
detailPanelOpen?: boolean;
previewWorkspaceDocument?: unknown;
previewWorkspaceEntry?: unknown;
documentLink?: unknown;
previewDocumentId?: Identifier | null;
ensureAssetUrl?: EnsureAssetUrl;
ensurePreviewData?: EnsurePreviewData;
@@ -45,7 +45,7 @@ export const useWorkspaceSurface = ({
detailPanelProps,
detailPanelOpen = false,
previewWorkspaceDocument,
previewWorkspaceEntry,
documentLink,
previewDocumentId,
ensureAssetUrl,
ensurePreviewData,
@@ -122,7 +122,7 @@ export const useWorkspaceSurface = ({
} = detailExtras;
return createDocumentViewerSurface({
document: previewWorkspaceDocument,
previewEntry: previewWorkspaceEntry,
documentLink,
ensureAssetUrl,
ensurePreviewData,
getDocumentAsset,
@@ -144,7 +144,7 @@ export const useWorkspaceSurface = ({
}, [
showPreviewWorkspace,
previewWorkspaceDocument,
previewWorkspaceEntry,
documentLink,
ensureAssetUrl,
ensurePreviewData,
getDocumentAsset,
+8 -8
View File
@@ -32,14 +32,14 @@ import '../styles/workspace/workspace-cards.css';
type Identifier = string | number;
type TagLike = { id?: Identifier | null; label?: string; color?: string | null } | null;
type PreviewEntryLike = { url?: string | null; contentType?: string | null };
type DocumentLinkLike = { url?: string | null; contentType?: string | null };
type OverlaySource = { url: string; alt?: string | null; contentType?: string | null };
export interface DeskDocument {
id?: Identifier | null;
title?: string;
tags?: TagLike[] | null;
previewEntry?: OverlaySource | null;
documentLink?: OverlaySource | null;
[key: string]: unknown;
}
@@ -208,7 +208,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
onClearSelection = null,
tenantId = null,
viewId = 'default',
previewEntries,
documentLinks,
ensureDownloadUrl,
}) => {
const items = useMemo<DeskDocument[]>(
@@ -217,7 +217,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
);
const allowLayoutPersistence = Boolean(tenantId && viewId && viewId.startsWith('folder:'));
const previewEntryMap = previewEntries instanceof Map ? previewEntries : null;
const documentLinkMap = documentLinks instanceof Map ? documentLinks : null;
const containerRef = useRef<HTMLDivElement | null>(null);
const itemRefs = useRef<Map<string, HTMLDivElement | null>>(new Map());
@@ -562,7 +562,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
const docContentType = doc?.content_type ?? null;
const versionContentType = (doc?.current_version as { version?: { content_type?: string | null } } | null)?.version?.content_type ?? null;
const applyEntry = (entry?: PreviewEntryLike | null) => {
const applyEntry = (entry?: DocumentLinkLike | null) => {
if (!entry?.url) {
setOverlaySource(null);
return;
@@ -574,7 +574,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
});
};
const cachedEntry = previewEntryMap?.get(docIdentifier) || null;
const cachedEntry = documentLinkMap?.get(docIdentifier) || null;
if (cachedEntry?.url) {
applyEntry(cachedEntry);
return () => {
@@ -605,7 +605,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
return () => {
cancelled = true;
};
}, [overlayDocId, documentLookup, previewEntryMap, ensureDownloadUrl]);
}, [overlayDocId, documentLookup, documentLinkMap, ensureDownloadUrl]);
const closeOverlay = useCallback(() => {
setOverlayDocId(null);
@@ -666,7 +666,7 @@ const DesktopWorkspace: React.FC<DesktopWorkspaceProps> = ({
}
const baseDoc = documentLookup.get(String(overlayDocId)) || null;
if (baseDoc && overlayDisplay?.url) {
return { ...baseDoc, previewEntry: overlayDisplay };
return { ...baseDoc, documentLink: overlayDisplay };
}
return baseDoc;
}, [documentLookup, overlayDisplay, overlayDocId]);
+18 -18
View File
@@ -20,15 +20,15 @@ type NaturalSize = { width: number | null; height: number | null };
type FocusPoint = { xRatio: number; yRatio: number } | null;
type DisplayKind = 'image' | 'pdf';
type PreviewEntry = {
type DocumentLink = {
url: string;
alt?: string;
contentType?: string | null;
};
type DocumentLikeWithPreview = DocumentLike & { previewEntry?: PreviewEntry };
type DocumentLikeWithPreview = DocumentLike & { documentLink?: DocumentLink };
const determineDisplayKind = (entry?: PreviewEntry | null): DisplayKind => {
const determineDisplayKind = (entry?: DocumentLink | null): DisplayKind => {
const type = entry?.contentType?.toLowerCase?.() || '';
if (type.includes('pdf')) {
return 'pdf';
@@ -66,17 +66,17 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
const currentDocument = overlayDocument as DocumentLikeWithPreview | null;
useEffect(() => {
if (currentDocument?.previewEntry?.url) {
if (currentDocument?.documentLink?.url) {
setDocumentSnapshot(currentDocument);
}
}, [currentDocument]);
const activeDocument = open && currentDocument?.previewEntry?.url ? currentDocument : documentSnapshot;
const previewEntry = activeDocument?.previewEntry || null;
const displayKind = useMemo(() => determineDisplayKind(previewEntry), [previewEntry]);
const activeDocument = open && currentDocument?.documentLink?.url ? currentDocument : documentSnapshot;
const documentLink = activeDocument?.documentLink || null;
const displayKind = useMemo(() => determineDisplayKind(documentLink), [documentLink]);
const isPdfDisplay = displayKind === 'pdf';
const documentTitle = activeDocument?.title || undefined;
const effectiveAlt = previewEntry?.alt || documentTitle || 'Document preview';
const effectiveAlt = documentLink?.alt || documentTitle || 'Document preview';
useEffect(() => {
if (visibilityTimerRef.current) {
@@ -88,7 +88,7 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
displayTimerRef.current = null;
}
if (open && previewEntry?.url) {
if (open && documentLink?.url) {
setRenderBackdrop(true);
displayTimerRef.current = requestAnimationFrame(() => {
displayTimerRef.current = requestAnimationFrame(() => {
@@ -114,7 +114,7 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
visibilityTimerRef.current = null;
}
};
}, [open, previewEntry?.url]);
}, [open, documentLink?.url]);
useEffect(() => () => {
if (visibilityTimerRef.current) {
@@ -126,7 +126,7 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
}, []);
useEffect(() => {
}, [isPdfDisplay, open, previewEntry?.url]);
}, [isPdfDisplay, open, documentLink?.url]);
useEffect(() => {
setIsNativeScale(false);
@@ -137,7 +137,7 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
scrollEl.scrollLeft = 0;
scrollEl.scrollTop = 0;
}
}, [open, previewEntry?.url, displayKind]);
}, [open, documentLink?.url, displayKind]);
useEffect(() => {
@@ -180,7 +180,7 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
}, [open]);
useEffect(() => {
if (!previewEntry?.url) {
if (!documentLink?.url) {
return;
}
@@ -190,10 +190,10 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
scrollEl.scrollTop = 0;
}
focusRef.current = null;
}, [previewEntry?.url]);
}, [documentLink?.url]);
useEffect(() => {
if (!renderBackdrop || !previewEntry?.url) {
if (!renderBackdrop || !documentLink?.url) {
return undefined;
}
@@ -202,7 +202,7 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
});
return () => cancelAnimationFrame(frame);
}, [renderBackdrop, previewEntry?.url]);
}, [renderBackdrop, documentLink?.url]);
const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>) => {
event.stopPropagation();
@@ -267,7 +267,7 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
toggleZoomAtPoint(event.clientX ?? 0, event.clientY ?? 0);
};
const shouldRender = renderBackdrop && Boolean(previewEntry?.url);
const shouldRender = renderBackdrop && Boolean(documentLink?.url);
const stageClassName = isPdfDisplay
? 'preview-zoom__stage preview-zoom__stage--pdf'
@@ -308,7 +308,7 @@ const PreviewZoomOverlay: React.FC<PreviewZoomOverlayProps> = ({
return null;
}
const effectiveDisplay = previewEntry;
const effectiveDisplay = documentLink;
return createPortal(
(
+9 -21
View File
@@ -25,7 +25,7 @@ interface FolderNode {
parentId?: Identifier | 'root';
}
type PreviewEntry = {
type DocumentLink = {
url?: string;
contentType?: string | null;
} | null;
@@ -41,7 +41,7 @@ interface UseDetailWorkspaceArgs {
ensureFolderData: (folderId: Identifier | 'root', options?: { force?: boolean; includeDocuments?: boolean }) => Promise<void>;
detailPanelControlRef: MutableRefObject<{ open?: (args?: { documentIds?: Identifier[] }) => void; close?: () => void } | null>;
detailFolderFetchRef: MutableRefObject<Set<Identifier | 'root'>>;
previewEntries: Map<Identifier, PreviewEntry>;
documentLinks: Map<Identifier, DocumentLink>;
previewDocumentId?: Identifier | null;
activePreviewId?: Identifier | null;
openDocumentPreview?: (args: { documentIds: Identifier[] }) => void;
@@ -70,7 +70,7 @@ interface UseDetailWorkspaceResult {
inspectDocument: (docId: Identifier | null) => void;
previewActive: boolean;
previewWorkspaceDocument: DocumentLike | null;
previewWorkspaceEntry: PreviewEntry;
documentLink: DocumentLink;
resolveThumbnailUrlForDoc: (doc: DocumentLike | null) => string | null;
resolveFolderPath: (folderId?: Identifier | 'root') => Array<{ id: Identifier | 'root'; name: string }>;
}
@@ -86,7 +86,7 @@ const useDetailWorkspace = ({
ensureFolderData,
detailPanelControlRef,
detailFolderFetchRef,
previewEntries,
documentLinks,
previewDocumentId,
activePreviewId,
openDocumentPreview,
@@ -245,21 +245,9 @@ const useDetailWorkspace = ({
[folderNodes],
);
const detailPanelPreviewEntry = useMemo(() => {
if (!detailPanelDocument) {
return null;
}
return previewEntries.get(detailPanelDocument.id) || null;
}, [detailPanelDocument, previewEntries]);
const documentLink = useMemo(() => (detailPanelDocument ? documentLinks.get(detailPanelDocument.id) || null : null), [detailPanelDocument, documentLinks]);
const previewWorkspaceEntry = useMemo(() => {
if (!previewDocumentId) {
return null;
}
return previewEntries.get(previewDocumentId) || null;
}, [previewDocumentId, previewEntries]);
const previewWorkspaceDocument = useMemo(() => {
const previewWorkspaceDocument = useMemo(() => {
if (!previewDocumentId) {
return null;
}
@@ -301,7 +289,7 @@ const useDetailWorkspace = ({
tagLookupById,
onTagAdd: handleDocumentTagAdd,
onTagRemove: handleTagRemove,
previewEntry: detailPanelPreviewEntry,
documentLink,
onOpenPreview: openDocumentPreview,
activePreviewId,
onUpdateTitle: handleDocumentTitleUpdate,
@@ -335,7 +323,7 @@ const useDetailWorkspace = ({
resolveApiPath,
resolveFolderPath,
selectFolder,
detailPanelPreviewEntry,
documentLink,
tags,
tagLookupById,
],
@@ -350,7 +338,7 @@ const useDetailWorkspace = ({
inspectDocument,
previewActive,
previewWorkspaceDocument,
previewWorkspaceEntry,
documentLink,
resolveThumbnailUrlForDoc,
resolveFolderPath,
};
@@ -2,7 +2,7 @@ import { useMemo } from 'react';
type Identifier = string | number;
interface PreviewEntryLike {
interface DocumentLinkLike {
url?: string | null;
contentType?: string | null;
}
@@ -70,8 +70,8 @@ export interface UseDocumentsPanelPropsArgs {
handleBulkSelectionReanalyze?: (...args: unknown[]) => void;
folderOptions?: unknown[];
moveDocumentsToFolder?: (...args: unknown[]) => void;
previewEntries?: Map<Identifier, PreviewEntryLike>;
ensureDownloadUrl?: (documentId: Identifier, options?: { force?: boolean }) => Promise<PreviewEntryLike | null>;
documentLinks?: Map<Identifier, DocumentLinkLike>;
ensureDownloadUrl?: (documentId: Identifier, options?: { force?: boolean }) => Promise<DocumentLinkLike | null>;
}
export type DocumentsPanelProps = ReturnType<typeof useDocumentsPanelProps>;
@@ -126,7 +126,7 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
handleBulkSelectionReanalyze,
folderOptions,
moveDocumentsToFolder,
previewEntries,
documentLinks,
ensureDownloadUrl,
} = props;
@@ -182,7 +182,7 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
onBulkReanalyze: handleBulkSelectionReanalyze,
folderOptions,
onMoveDocumentsToFolder: moveDocumentsToFolder,
previewEntries,
documentLinks,
ensureDownloadUrl,
}),
[
@@ -234,7 +234,7 @@ const useDocumentsPanelProps = (props: UseDocumentsPanelPropsArgs) => {
ensureAssetUrl,
getDocumentAsset,
folderOptions,
previewEntries,
documentLinks,
ensureDownloadUrl,
],
);
@@ -27,7 +27,7 @@ interface DocumentsPanelProps {
const defaultGetDocumentAsset = (_doc?: unknown, _type?: string) => null;
export type PreviewEntryLike = { url?: string | null; contentType?: string | null };
export type DocumentLinkLike = { url?: string | null; contentType?: string | null };
const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
headerConfig,
@@ -62,7 +62,7 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
onDocumentTagDrop,
viewMode = 'list',
onViewModeChange: _onViewModeChange,
previewEntries,
documentLinks,
ensureDownloadUrl,
deskWorkspaceProps = null,
}): ReactNode => {
@@ -75,7 +75,7 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
} = useWorkspaceSelectionContext();
const showingSearchResults = searchResults !== null;
const rows = showingSearchResults ? searchResults : documents;
const previewEntryMap = previewEntries instanceof Map ? previewEntries : null;
const documentLinkMap = documentLinks instanceof Map ? documentLinks : null;
const currentFolderId = useMemo(() => {
if (showingSearchResults) {
@@ -159,7 +159,7 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
const zoomDisplay = previewZoomSource;
const overlayDocument = useMemo(() => (
previewDoc && zoomDisplay?.url
? { ...previewDoc, previewEntry: zoomDisplay }
? { ...previewDoc, documentLink: zoomDisplay }
: previewDoc
), [previewDoc, zoomDisplay]);
@@ -175,7 +175,7 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
const versionContentType = previewDoc.current_version?.version?.content_type;
const contentFallback = docContentType || versionContentType || null;
const applyEntry = (entry?: PreviewEntryLike | null) => {
const applyEntry = (entry?: DocumentLinkLike | null) => {
if (!entry?.url) {
setPreviewZoomSource(null);
return;
@@ -187,7 +187,7 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
});
};
const cachedEntry = previewEntryMap?.get(previewDocId) || null;
const cachedEntry = documentLinkMap?.get(previewDocId) || null;
if (cachedEntry?.url) {
applyEntry(cachedEntry);
return () => {
@@ -218,7 +218,7 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
return () => {
cancelled = true;
};
}, [previewDocId, previewDoc, previewEntryMap, ensureDownloadUrl]);
}, [previewDocId, previewDoc, documentLinkMap, ensureDownloadUrl]);
const closePreviewOverlay = useCallback(() => {
setPreviewDocId(null);
@@ -230,12 +230,12 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
if (!doc || !doc.id) {
return;
}
if (!ensureDownloadUrl && !(previewEntryMap?.get(doc.id)?.url)) {
if (!ensureDownloadUrl && !(documentLinkMap?.get(doc.id)?.url)) {
return;
}
setPreviewDocId(doc.id);
},
[ensureDownloadUrl, previewEntryMap],
[ensureDownloadUrl, documentLinkMap],
);
const handleDocumentActivate = useCallback(
@@ -375,14 +375,14 @@ const useDocumentsWorkspace = ({
}, [setSearchResults]);
const {
previewEntries,
documentLinks,
previewDocuments,
ensurePreviewData,
ensureDownloadUrl,
openDocumentPreview,
closeDocumentPreview,
resetPreviewState,
removePreviewEntries,
removeDocumentLinks,
} = useDocumentPreview({
routeDocumentId: previewDocumentId,
documents,
@@ -793,9 +793,9 @@ const useDocumentsWorkspace = ({
return changed ? next : prev;
});
removePreviewEntries(Array.from(idSet));
removeDocumentLinks(Array.from(idSet));
},
[setDocuments, setSearchResults, setFolderContents, removePreviewEntries],
[setDocuments, setSearchResults, setFolderContents, removeDocumentLinks],
);
const {
@@ -1235,7 +1235,7 @@ const useDocumentsWorkspace = ({
inspectDocument,
previewActive,
previewWorkspaceDocument,
previewWorkspaceEntry,
documentLink,
resolveFolderPath,
} = useDetailWorkspace({
documents,
@@ -1248,7 +1248,7 @@ const useDocumentsWorkspace = ({
ensureFolderData,
detailPanelControlRef,
detailFolderFetchRef,
previewEntries,
documentLinks,
previewDocumentId,
activePreviewId,
openDocumentPreview: openDocumentPreviewForDetail,
@@ -1465,7 +1465,7 @@ const useDocumentsWorkspace = ({
onClearSelection: clearDocumentSelection,
tenantId: currentTenantId,
viewId: deskViewId,
previewEntries,
documentLinks,
ensureDownloadUrl,
}),
[
@@ -1483,7 +1483,7 @@ const useDocumentsWorkspace = ({
clearDocumentSelection,
currentTenantId,
deskViewId,
previewEntries,
documentLinks,
ensureDownloadUrl,
],
);
@@ -1537,7 +1537,7 @@ const useDocumentsWorkspace = ({
folderOptions,
moveDocumentsToFolder,
selectFolder,
previewEntries,
documentLinks,
ensureDownloadUrl,
});
@@ -1619,7 +1619,7 @@ const useDocumentsWorkspace = ({
revokePasskey,
previewActive,
previewWorkspaceDocument,
previewWorkspaceEntry,
documentLink,
previewDocumentId,
closeDocumentPreview,
handleThumbnailRegeneration,
@@ -1670,7 +1670,7 @@ const useDocumentsWorkspace = ({
revokePasskey,
previewActive,
previewWorkspaceDocument,
previewWorkspaceEntry,
documentLink,
previewDocumentId,
closeDocumentPreview,
handleThumbnailRegeneration,
+16 -16
View File
@@ -13,7 +13,7 @@ interface DocumentLike {
[key: string]: unknown;
}
interface PreviewEntry {
interface DocumentLink {
url?: string;
contentType?: string;
filename?: string;
@@ -36,7 +36,7 @@ type LayoutMode = 'split' | 'stacked' | (string & {});
interface DocumentViewerLayoutProps {
document?: DocumentLike | null;
previewEntry?: PreviewEntry | null;
documentLink?: DocumentLink | null;
summaryProps?: Record<string, unknown>;
metadataPayload?: unknown;
contentTabConfig?: ContentTabConfig | null;
@@ -81,7 +81,7 @@ const getFileExtension = (filename?: string | null) => {
const DocumentViewerLayout = ({
document,
previewEntry,
documentLink,
summaryProps = {},
metadataPayload,
contentTabConfig,
@@ -96,15 +96,15 @@ const DocumentViewerLayout = ({
const viewportRef = useRef<HTMLDivElement>(null);
const previewContent = useMemo(() => {
if (!document || !previewEntry?.url) {
if (!document || !documentLink?.url) {
return null;
}
const normalizedContentType = (previewEntry.contentType
const normalizedContentType = (documentLink.contentType
|| document.content_type
|| '')
.toLowerCase();
const normalizedFilename = previewEntry.filename
const normalizedFilename = documentLink.filename
|| document.filename
|| document.original_name
|| '';
@@ -123,7 +123,7 @@ const DocumentViewerLayout = ({
if (isImage) {
return (
<img
src={previewEntry.url}
src={documentLink.url}
alt={`Preview of ${document.title}`}
className="document-viewer__object document-viewer__object--image"
draggable={false}
@@ -137,7 +137,7 @@ const DocumentViewerLayout = ({
|| document.original_name;
return (
<PdfViewer
src={previewEntry.url}
src={documentLink.url}
title={documentTitle ? `Preview of ${documentTitle}` : undefined}
viewportRef={viewportRef}
/>
@@ -150,7 +150,7 @@ const DocumentViewerLayout = ({
className="document-viewer__object document-viewer__object--audio"
controls
preload="metadata"
src={previewEntry.url}
src={documentLink.url}
aria-label={`Audio preview of ${mediaLabel}`}
>
</audio>
@@ -163,15 +163,15 @@ const DocumentViewerLayout = ({
className="document-viewer__object document-viewer__object--video"
controls
preload="metadata"
src={previewEntry.url}
src={documentLink.url}
aria-label={`Video preview of ${mediaLabel}`}
>
</video>
);
}
const displayContentType = document.content_type || previewEntry.contentType || 'this file type';
const displayFilename = previewEntry.filename
const displayContentType = document.content_type || documentLink.contentType || 'this file type';
const displayFilename = documentLink.filename
|| document.filename
|| document.original_name
|| 'download';
@@ -184,7 +184,7 @@ const DocumentViewerLayout = ({
<div className="document-viewer__unsupported-filename">{displayFilename}</div>
<a
className="button-link document-viewer__unsupported-download"
href={previewEntry.url}
href={documentLink.url}
download={displayFilename}
target="_blank"
rel="noopener noreferrer"
@@ -194,17 +194,17 @@ const DocumentViewerLayout = ({
</a>
</div>
);
}, [document, previewEntry, viewportRef]);
}, [document, documentLink, viewportRef]);
const renderViewportPane = useCallback(() => (
<div className="document-viewer__viewport" ref={viewportRef}>
{!previewEntry?.url ? (
{!documentLink?.url ? (
<div className="document-viewer__message">{previewLoadingMessage}</div>
) : (
previewContent
)}
</div>
), [previewContent, previewEntry?.url, previewLoadingMessage, viewportRef]);
), [previewContent, documentLink?.url, previewLoadingMessage, viewportRef]);
const viewportPane = renderViewportPane();
+17 -17
View File
@@ -39,7 +39,7 @@ interface DocumentLike {
version_number?: number;
version?: { content_type?: string | null } | null;
} | null;
previewEntry?: {
documentLink?: {
url: string;
alt?: string;
contentType?: string | null;
@@ -56,7 +56,7 @@ interface AssetLike {
interface DocumentViewerPanelProps extends DocumentSummarySectionProps {
document: DocumentLike | null;
previewEntry?: {
documentLink?: {
url?: string;
contentType?: string | null;
filename?: string | null;
@@ -79,7 +79,7 @@ interface DocumentViewerPanelProps extends DocumentSummarySectionProps {
export const createDocumentViewerHeaderActions = ({
document,
actionState,
previewEntry,
documentLink,
onZoom,
canZoom = false,
}) => {
@@ -87,7 +87,7 @@ export const createDocumentViewerHeaderActions = ({
return null;
}
const downloadHref = actionState?.downloadHref || previewEntry?.url;
const downloadHref = actionState?.downloadHref || documentLink?.url;
if (!downloadHref && !(canZoom && onZoom)) {
return null;
}
@@ -123,7 +123,7 @@ export const createDocumentViewerHeaderActions = ({
const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
document,
previewEntry,
documentLink,
hydrateDocument,
tagLookupById,
tagOptions,
@@ -254,11 +254,11 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
const [zoomOverlayOpen, setZoomOverlayOpen] = useState(false);
const handleZoomOpen = useCallback(() => {
if (!previewEntry?.url) {
if (!documentLink?.url) {
return;
}
setZoomOverlayOpen(true);
}, [previewEntry?.url]);
}, [documentLink?.url]);
const handleZoomClose = useCallback(() => {
setZoomOverlayOpen(false);
@@ -266,7 +266,7 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
useEffect(() => {
setZoomOverlayOpen(false);
}, [previewEntry?.url, document?.id]);
}, [documentLink?.url, document?.id]);
useEffect(() => {
if (hydrateDocument && document?.id) {
@@ -355,23 +355,23 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
}, [breadcrumbs, handleBreadcrumbNavigate]);
const zoomDisplay = useMemo(() => {
if (!previewEntry?.url || !document) {
if (!documentLink?.url || !document) {
return null;
}
const docContentType = document.content_type;
const versionContentType = document.current_version?.version?.content_type;
const normalizedContentType = previewEntry.contentType || docContentType || versionContentType || null;
const normalizedContentType = documentLink.contentType || docContentType || versionContentType || null;
return {
url: previewEntry.url,
url: documentLink.url,
alt: document.title,
contentType: normalizedContentType || undefined,
};
}, [previewEntry?.url, previewEntry?.contentType, document]);
}, [documentLink?.url, documentLink?.contentType, document]);
const headerActions = createDocumentViewerHeaderActions({
document,
actionState,
previewEntry,
documentLink,
onZoom: zoomDisplay ? handleZoomOpen : null,
canZoom: Boolean(zoomDisplay),
});
@@ -471,7 +471,7 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
<section className={viewerClassName}>
<DocumentViewerLayout
document={document}
previewEntry={previewEntry}
documentLink={documentLink}
summaryProps={summaryProps}
metadataPayload={metadataPayload}
contentTabConfig={contentTabConfig}
@@ -495,7 +495,7 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
const overlayDocument = useMemo(() => (
document && zoomDisplay?.url
? { ...document, previewEntry: zoomDisplay }
? { ...document, documentLink: zoomDisplay }
: document
), [document, zoomDisplay]);
@@ -549,7 +549,7 @@ export default DocumentViewerPanel;
export const createDocumentViewerSurface = ({
document,
previewEntry,
documentLink,
ensureAssetUrl,
ensurePreviewData,
getDocumentAsset,
@@ -581,7 +581,7 @@ export const createDocumentViewerSurface = ({
content: (
<DocumentViewerPanel
document={document}
previewEntry={previewEntry}
documentLink={documentLink}
hydrateDocument={ensurePreviewData}
tagLookupById={tagLookupById}
tagOptions={tagOptions}