cleanup
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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(
|
||||
(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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}
|
||||
|
||||
Reference in New Issue
Block a user