refactor: Consolidate workspace utilities into new workspaceUtils.ts with typed entry keys, replacing appLayoutUtils.ts, and update related components.

This commit is contained in:
2025-11-24 22:38:01 +01:00
parent deec2fe69d
commit 096c377897
19 changed files with 202 additions and 283 deletions
+54 -58
View File
@@ -62,7 +62,6 @@ interface DocumentViewerPanelProps extends DocumentSummarySectionProps {
ensureAssetUrl?: (docId: string | number, asset: AssetLike, options?: { force?: boolean }) => Promise<unknown>;
getDocumentAsset?: (doc: DocumentLike | null, type: string) => AssetLike | null;
ensurePreviewData?: (docId: string | number, options?: { signal?: AbortSignal }) => Promise<DocumentLike | null>;
resolveApiPath?: (path: string) => string;
notifyApiError?: (error: unknown, fallbackMessage?: string) => void;
sidebarToggle?: ReactNode;
onClosePanel?: () => void;
@@ -131,7 +130,6 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
ensureAssetUrl,
getDocumentAsset,
ensurePreviewData,
resolveApiPath,
notifyApiError,
sidebarToggle = null,
onClosePanel,
@@ -264,7 +262,7 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
return null;
}
const downloadUrl = document.current_version?.download?.url;
const href = resolveApiPath ? resolveApiPath(downloadUrl) : downloadUrl;
const href = downloadUrl;
if (!href) {
return null;
}
@@ -275,7 +273,7 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
mimeType,
filename,
};
}, [document, resolveApiPath]);
}, [document]);
const handleZoomOpen = useCallback(() => {
if (!resolvedDocumentLink?.url) {
@@ -311,18 +309,16 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
() =>
document
? createDocumentActionState({
document,
resolveApiPath,
ensurePreviewData,
ensureAssetUrl,
getDocumentAsset,
notifyApiError,
ocrErrorMessage: 'Unable to open OCR text.',
})
document,
ensurePreviewData,
ensureAssetUrl,
getDocumentAsset,
notifyApiError,
ocrErrorMessage: 'Unable to open OCR text.',
})
: null,
[
document,
resolveApiPath,
ensurePreviewData,
ensureAssetUrl,
getDocumentAsset,
@@ -337,8 +333,8 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
const folderSegments = resolveFolderPath(document.folder_id);
const normalizedSegments = Array.isArray(folderSegments)
? folderSegments
.filter((segment) => segment && segment.id && segment.name)
.map((segment) => ({ id: segment.id, name: segment.name }))
.filter((segment) => segment && segment.id && segment.name)
.map((segment) => ({ id: segment.id, name: segment.name }))
: [];
return [
@@ -380,62 +376,62 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
const collapseButton = isSidebarVariant && onCollapsePanel
? (
<button
type="button"
className="icon-button"
onClick={() => onCollapsePanel?.()}
aria-label="Close detail panel"
title="Close detail panel"
>
<IconX />
</button>
)
<button
type="button"
className="icon-button"
onClick={() => onCollapsePanel?.()}
aria-label="Close detail panel"
title="Close detail panel"
>
<IconX />
</button>
)
: null;
const maximizeButton = isSidebarVariant && onMaximizePanel
? (
<button
type="button"
className="icon-button"
onClick={(event) => {
event.stopPropagation();
const targetId = document?.id;
if (targetId == null) {
return;
}
onMaximizePanel?.({ documentIds: [targetId] });
}}
aria-label="Maximize"
title="Maximize"
>
<WindowMaximizeIcon className="icon--flip-y" />
</button>
)
<button
type="button"
className="icon-button"
onClick={(event) => {
event.stopPropagation();
const targetId = document?.id;
if (targetId == null) {
return;
}
onMaximizePanel?.({ documentIds: [targetId] });
}}
aria-label="Maximize"
title="Maximize"
>
<WindowMaximizeIcon className="icon--flip-y" />
</button>
)
: null;
const closeButton = !isSidebarVariant && onClosePanel
? (
<button
type="button"
className="icon-button"
onClick={() => onClosePanel?.()}
aria-label="Close preview"
title="Close preview"
>
<CloseIcon />
</button>
)
<button
type="button"
className="icon-button"
onClick={() => onClosePanel?.()}
aria-label="Close preview"
title="Close preview"
>
<CloseIcon />
</button>
)
: null;
const headerLeadingButtons = isSidebarVariant
? [
collapseButton ? <React.Fragment key="collapse-button">{collapseButton}</React.Fragment> : null,
maximizeButton ? <React.Fragment key="maximize-button">{maximizeButton}</React.Fragment> : null,
].filter(Boolean)
collapseButton ? <React.Fragment key="collapse-button">{collapseButton}</React.Fragment> : null,
maximizeButton ? <React.Fragment key="maximize-button">{maximizeButton}</React.Fragment> : null,
].filter(Boolean)
: [
sidebarToggle ? <React.Fragment key="sidebar-toggle">{sidebarToggle}</React.Fragment> : null,
closeButton ? <React.Fragment key="close-button">{closeButton}</React.Fragment> : null,
].filter(Boolean);
sidebarToggle ? <React.Fragment key="sidebar-toggle">{sidebarToggle}</React.Fragment> : null,
closeButton ? <React.Fragment key="close-button">{closeButton}</React.Fragment> : null,
].filter(Boolean);
const headerLeadingContent = headerLeadingButtons.length ? headerLeadingButtons : null;
const resizeHandle = isSidebarVariant ? (