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