cleanup
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { useCallback, useEffect, useMemo } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
import { SidebarExpandIcon } from '../ui/icons';
|
||||
import { createDocumentsSurface } from '../documents/DocumentsPanel';
|
||||
import { createDocumentViewerSurface } from '../preview/DocumentViewerPanel';
|
||||
import DocumentsPanel from '../documents/panel/DocumentsPanel';
|
||||
import DocumentViewerPanel from '../preview/DocumentViewerPanel';
|
||||
import { usePanelManager } from './PanelManagerContext';
|
||||
|
||||
type Identifier = string | number;
|
||||
@@ -13,9 +13,7 @@ type GetDocumentAsset = (document: unknown, assetType: string) => unknown;
|
||||
type ResolveApiPath = (path: string) => string;
|
||||
type NotifyApiError = (error: unknown, fallbackMessage?: string) => void;
|
||||
|
||||
type DocumentsSurface = ReturnType<typeof createDocumentsSurface> | null;
|
||||
type PreviewSurface = ReturnType<typeof createDocumentViewerSurface> | null;
|
||||
type WorkspaceSurface = DocumentsSurface | PreviewSurface | null;
|
||||
type WorkspaceSurface = { content: ReactNode; detail?: ReactNode | null } | null;
|
||||
|
||||
interface UseWorkspaceSurfaceArgs {
|
||||
sidebarHidden?: boolean;
|
||||
@@ -84,29 +82,52 @@ export const useWorkspaceSurface = ({
|
||||
);
|
||||
}, [sidebarHidden, onExpandSidebar]);
|
||||
|
||||
const documentsSurface = useMemo<DocumentsSurface>(() => {
|
||||
const documentsSurface = useMemo<WorkspaceSurface>(() => {
|
||||
if (!documentsTableProps) {
|
||||
return null;
|
||||
}
|
||||
return createDocumentsSurface({
|
||||
tableProps: documentsTableProps,
|
||||
renderSidebarToggle,
|
||||
detailProps: detailPanelProps,
|
||||
detailOpen: detailPanelOpen,
|
||||
});
|
||||
|
||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||
|
||||
const detail = detailPanelOpen && detailPanelProps
|
||||
? (() => {
|
||||
const { onClose, onOpenPreview, tags: tagOptions, ...restDetailProps } = detailPanelProps;
|
||||
return (
|
||||
<DocumentViewerPanel
|
||||
variant="sidebar"
|
||||
onCollapsePanel={onClose}
|
||||
onMaximizePanel={onOpenPreview}
|
||||
tagOptions={tagOptions}
|
||||
{...restDetailProps}
|
||||
/>
|
||||
);
|
||||
})()
|
||||
: null;
|
||||
|
||||
return {
|
||||
content: (
|
||||
<DocumentsPanel
|
||||
{...documentsTableProps}
|
||||
headerLeading={sidebarToggle}
|
||||
/>
|
||||
),
|
||||
detail,
|
||||
};
|
||||
}, [
|
||||
documentsTableProps,
|
||||
renderSidebarToggle,
|
||||
detailPanelProps,
|
||||
detailPanelOpen,
|
||||
detailPanelProps,
|
||||
]);
|
||||
|
||||
const showPreviewWorkspace = Boolean(previewDocumentId);
|
||||
|
||||
const previewSurface = useMemo<PreviewSurface>(() => {
|
||||
if (!showPreviewWorkspace) {
|
||||
const previewSurface = useMemo<WorkspaceSurface>(() => {
|
||||
if (!showPreviewWorkspace || !previewWorkspaceDocument) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||
const detailExtras = detailPanelProps || {};
|
||||
const {
|
||||
tagLookupById,
|
||||
@@ -120,38 +141,45 @@ export const useWorkspaceSurface = ({
|
||||
onUpdateIssued,
|
||||
resolveFolderPath,
|
||||
} = detailExtras;
|
||||
return createDocumentViewerSurface({
|
||||
document: previewWorkspaceDocument,
|
||||
documentLink,
|
||||
ensureAssetUrl,
|
||||
ensurePreviewData,
|
||||
getDocumentAsset,
|
||||
resolveApiPath,
|
||||
notifyApiError,
|
||||
onClose: closeDocumentPreview,
|
||||
renderSidebarToggle,
|
||||
tagLookupById,
|
||||
tagOptions,
|
||||
onTagAdd,
|
||||
onTagRemove,
|
||||
correspondents,
|
||||
onCorrespondentAdd,
|
||||
onCorrespondentRemove,
|
||||
onUpdateTitle,
|
||||
onUpdateIssued,
|
||||
resolveFolderPath,
|
||||
});
|
||||
|
||||
return {
|
||||
content: (
|
||||
<DocumentViewerPanel
|
||||
document={previewWorkspaceDocument}
|
||||
documentLink={documentLink}
|
||||
hydrateDocument={ensurePreviewData}
|
||||
tagLookupById={tagLookupById}
|
||||
tagOptions={tagOptions}
|
||||
onTagAdd={onTagAdd}
|
||||
onTagRemove={onTagRemove}
|
||||
correspondents={correspondents}
|
||||
onCorrespondentAdd={onCorrespondentAdd}
|
||||
onCorrespondentRemove={onCorrespondentRemove}
|
||||
onUpdateTitle={onUpdateTitle}
|
||||
onUpdateIssued={onUpdateIssued}
|
||||
ensureAssetUrl={ensureAssetUrl}
|
||||
getDocumentAsset={getDocumentAsset}
|
||||
ensurePreviewData={ensurePreviewData}
|
||||
resolveApiPath={resolveApiPath}
|
||||
notifyApiError={notifyApiError}
|
||||
sidebarToggle={sidebarToggle}
|
||||
onClosePanel={closeDocumentPreview}
|
||||
resolveFolderPath={resolveFolderPath}
|
||||
/>
|
||||
),
|
||||
detail: null,
|
||||
};
|
||||
}, [
|
||||
showPreviewWorkspace,
|
||||
previewWorkspaceDocument,
|
||||
documentLink,
|
||||
ensureAssetUrl,
|
||||
ensurePreviewData,
|
||||
ensureAssetUrl,
|
||||
getDocumentAsset,
|
||||
resolveApiPath,
|
||||
notifyApiError,
|
||||
closeDocumentPreview,
|
||||
renderSidebarToggle,
|
||||
closeDocumentPreview,
|
||||
detailPanelProps,
|
||||
]);
|
||||
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export { default } from './panel/DocumentsPanel';
|
||||
export { default as createDocumentsSurface } from './panel/createDocumentsSurface';
|
||||
export { createDocumentsTableHeaderActions } from './panel/DocumentsToolbar';
|
||||
|
||||
@@ -11,6 +11,8 @@ import DocumentsPanelHeader, {
|
||||
DocumentsPanelHeaderConfig,
|
||||
DocumentsHeaderBreadcrumb,
|
||||
} from './DocumentsPanelHeader';
|
||||
import { SelectionFloatingPanel } from '../SelectionFloatingActions';
|
||||
import { createDocumentsTableHeaderActions } from './DocumentsToolbar';
|
||||
|
||||
const DEFAULT_GRID_ICON_SIZE = 144;
|
||||
|
||||
@@ -20,7 +22,7 @@ const EntryType = {
|
||||
};
|
||||
|
||||
interface DocumentsPanelProps {
|
||||
headerConfig?: DocumentsPanelHeaderConfig;
|
||||
headerLeading?: ReactNode;
|
||||
onBreadcrumbNavigate?: (crumb: DocumentsHeaderBreadcrumb) => void;
|
||||
[key: string]: any;
|
||||
}
|
||||
@@ -30,9 +32,9 @@ const defaultGetDocumentAsset = (_doc?: unknown, _type?: string) => null;
|
||||
export type DocumentLinkLike = { url?: string | null; contentType?: string | null };
|
||||
|
||||
const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
|
||||
headerConfig,
|
||||
headerLeading = null,
|
||||
onBreadcrumbNavigate,
|
||||
currentFolderName: _currentFolderName,
|
||||
currentFolderName,
|
||||
breadcrumbs,
|
||||
subfolders,
|
||||
documents,
|
||||
@@ -61,10 +63,28 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
|
||||
isSearchLoading = false,
|
||||
onDocumentTagDrop,
|
||||
viewMode = 'list',
|
||||
onViewModeChange: _onViewModeChange,
|
||||
onViewModeChange,
|
||||
documentLinks,
|
||||
ensureDownloadUrl,
|
||||
deskWorkspaceProps = null,
|
||||
onRefresh = () => {},
|
||||
sortField,
|
||||
sortDirection,
|
||||
onSortFieldChange,
|
||||
onSortDirectionToggle,
|
||||
searchIncludeDescendants,
|
||||
onToggleSearchIncludeDescendants,
|
||||
onDeleteSelection,
|
||||
documentLookup,
|
||||
tags,
|
||||
correspondents,
|
||||
onBulkTagAdd,
|
||||
onBulkTagRemove,
|
||||
onBulkCorrespondentAdd,
|
||||
onBulkCorrespondentRemove,
|
||||
onBulkReanalyze,
|
||||
folderOptions,
|
||||
onMoveDocumentsToFolder,
|
||||
}): ReactNode => {
|
||||
const {
|
||||
selectedEntries,
|
||||
@@ -76,6 +96,85 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
|
||||
const showingSearchResults = searchResults !== null;
|
||||
const rows = showingSearchResults ? searchResults : documents;
|
||||
const documentLinkMap = documentLinks instanceof Map ? documentLinks : null;
|
||||
const searchResultCount = Array.isArray(searchResults) ? searchResults.length : 0;
|
||||
const headerTitle = showingSearchResults
|
||||
? 'Search results'
|
||||
: currentFolderName || 'Documents';
|
||||
const headerSubtitle = showingSearchResults
|
||||
? `${searchResultCount} matching document${searchResultCount === 1 ? '' : 's'}`
|
||||
: null;
|
||||
const headerActions = useMemo(
|
||||
() => createDocumentsTableHeaderActions({
|
||||
viewMode,
|
||||
onViewModeChange,
|
||||
onRefresh,
|
||||
sortField,
|
||||
onSortFieldChange,
|
||||
sortDirection,
|
||||
onSortDirectionToggle,
|
||||
isFilterActive,
|
||||
includeDescendants: searchIncludeDescendants,
|
||||
onToggleIncludeDescendants: onToggleSearchIncludeDescendants,
|
||||
}),
|
||||
[
|
||||
viewMode,
|
||||
onViewModeChange,
|
||||
onRefresh,
|
||||
sortField,
|
||||
onSortFieldChange,
|
||||
sortDirection,
|
||||
onSortDirectionToggle,
|
||||
isFilterActive,
|
||||
searchIncludeDescendants,
|
||||
onToggleSearchIncludeDescendants,
|
||||
],
|
||||
);
|
||||
const floatingActions = useMemo(() => (
|
||||
<SelectionFloatingPanel
|
||||
documentLookup={documentLookup}
|
||||
tags={tags}
|
||||
tagLookupById={tagLookupById}
|
||||
correspondents={correspondents}
|
||||
onBulkTagAdd={onBulkTagAdd}
|
||||
onBulkTagRemove={onBulkTagRemove}
|
||||
onBulkCorrespondentAdd={onBulkCorrespondentAdd}
|
||||
onBulkCorrespondentRemove={onBulkCorrespondentRemove}
|
||||
onBulkReanalyze={onBulkReanalyze}
|
||||
onDeleteSelection={onDeleteSelection}
|
||||
folderOptions={folderOptions}
|
||||
onMoveDocumentsToFolder={onMoveDocumentsToFolder}
|
||||
onClearSelection={clearSelection}
|
||||
/>
|
||||
), [
|
||||
documentLookup,
|
||||
tags,
|
||||
tagLookupById,
|
||||
correspondents,
|
||||
onBulkTagAdd,
|
||||
onBulkTagRemove,
|
||||
onBulkCorrespondentAdd,
|
||||
onBulkCorrespondentRemove,
|
||||
onBulkReanalyze,
|
||||
onDeleteSelection,
|
||||
folderOptions,
|
||||
onMoveDocumentsToFolder,
|
||||
clearSelection,
|
||||
]);
|
||||
const headerConfig: DocumentsPanelHeaderConfig = useMemo(() => ({
|
||||
title: headerTitle,
|
||||
subtitle: headerSubtitle,
|
||||
leading: headerLeading,
|
||||
actions: headerActions,
|
||||
breadcrumbs,
|
||||
floatingActions,
|
||||
}), [
|
||||
headerTitle,
|
||||
headerSubtitle,
|
||||
headerLeading,
|
||||
headerActions,
|
||||
breadcrumbs,
|
||||
floatingActions,
|
||||
]);
|
||||
|
||||
const currentFolderId = useMemo(() => {
|
||||
if (showingSearchResults) {
|
||||
@@ -702,12 +801,10 @@ const DocumentsPanel: React.FC<DocumentsPanelProps> = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
{headerConfig ? (
|
||||
<DocumentsPanelHeader
|
||||
header={headerConfig}
|
||||
onBreadcrumbClick={onBreadcrumbNavigate}
|
||||
/>
|
||||
) : null}
|
||||
<DocumentsPanelHeader
|
||||
header={headerConfig}
|
||||
onBreadcrumbClick={onBreadcrumbNavigate}
|
||||
/>
|
||||
<section
|
||||
ref={scrollRef}
|
||||
className={`documents-panel documents-panel--view-${panelVariant}`}
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import DocumentViewerPanel from '../../preview/DocumentViewerPanel';
|
||||
import createWorkspaceSurfaceConfig from '../workspaceHeader';
|
||||
import DocumentsPanel from './DocumentsPanel';
|
||||
import type { DocumentsPanelHeaderConfig } from './DocumentsPanelHeader';
|
||||
import { SelectionFloatingPanel } from '../SelectionFloatingActions';
|
||||
import { createDocumentsTableHeaderActions } from './DocumentsToolbar';
|
||||
|
||||
interface CreateDocumentsSurfaceArgs {
|
||||
tableProps: Record<string, any>;
|
||||
renderSidebarToggle?: () => ReactNode;
|
||||
detailProps?: Record<string, any> | null;
|
||||
detailOpen?: boolean;
|
||||
}
|
||||
|
||||
const createDocumentsSurface = ({
|
||||
tableProps,
|
||||
renderSidebarToggle,
|
||||
detailProps,
|
||||
detailOpen = false,
|
||||
}: CreateDocumentsSurfaceArgs) => {
|
||||
const {
|
||||
currentFolderName,
|
||||
breadcrumbs,
|
||||
searchResults,
|
||||
isFilterActive,
|
||||
viewMode,
|
||||
onViewModeChange,
|
||||
onRefresh,
|
||||
sortField,
|
||||
sortDirection,
|
||||
onSortFieldChange,
|
||||
onSortDirectionToggle,
|
||||
onDeleteSelection,
|
||||
tags,
|
||||
correspondents,
|
||||
documentLookup,
|
||||
tagLookupById,
|
||||
onBulkTagAdd,
|
||||
onBulkTagRemove,
|
||||
onBulkCorrespondentAdd,
|
||||
onBulkCorrespondentRemove,
|
||||
onBulkReanalyze,
|
||||
folderOptions,
|
||||
onMoveDocumentsToFolder,
|
||||
searchIncludeDescendants,
|
||||
onToggleSearchIncludeDescendants,
|
||||
onInspectDocument,
|
||||
} = tableProps;
|
||||
|
||||
const isDeskView = viewMode === 'desk';
|
||||
|
||||
const title = Array.isArray(searchResults) ? 'Search results' : currentFolderName;
|
||||
const subtitle = Array.isArray(searchResults)
|
||||
? `${searchResults.length} matching document${searchResults.length === 1 ? '' : 's'}`
|
||||
: null;
|
||||
|
||||
const actions = createDocumentsTableHeaderActions({
|
||||
viewMode,
|
||||
onViewModeChange,
|
||||
onRefresh,
|
||||
sortField,
|
||||
onSortFieldChange,
|
||||
sortDirection,
|
||||
onSortDirectionToggle,
|
||||
isFilterActive,
|
||||
includeDescendants: searchIncludeDescendants,
|
||||
onToggleIncludeDescendants: onToggleSearchIncludeDescendants,
|
||||
});
|
||||
|
||||
const floatingActions = (
|
||||
<SelectionFloatingPanel
|
||||
documentLookup={documentLookup}
|
||||
tags={tags}
|
||||
tagLookupById={tagLookupById}
|
||||
correspondents={correspondents}
|
||||
onBulkTagAdd={onBulkTagAdd}
|
||||
onBulkTagRemove={onBulkTagRemove}
|
||||
onBulkCorrespondentAdd={onBulkCorrespondentAdd}
|
||||
onBulkCorrespondentRemove={onBulkCorrespondentRemove}
|
||||
onBulkReanalyze={onBulkReanalyze}
|
||||
onDeleteSelection={onDeleteSelection}
|
||||
folderOptions={folderOptions}
|
||||
onMoveDocumentsToFolder={onMoveDocumentsToFolder}
|
||||
/>
|
||||
);
|
||||
|
||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||
const detail = detailOpen && detailProps
|
||||
? (() => {
|
||||
const { onClose, onOpenPreview, tags: tagOptions, ...restDetailProps } = detailProps;
|
||||
return (
|
||||
<DocumentViewerPanel
|
||||
variant="sidebar"
|
||||
onCollapsePanel={onClose}
|
||||
onMaximizePanel={onOpenPreview}
|
||||
tagOptions={tagOptions}
|
||||
{...restDetailProps}
|
||||
/>
|
||||
);
|
||||
})()
|
||||
: null;
|
||||
|
||||
const headerConfig: DocumentsPanelHeaderConfig = {
|
||||
title,
|
||||
subtitle,
|
||||
leading: sidebarToggle,
|
||||
actions,
|
||||
breadcrumbs,
|
||||
floatingActions,
|
||||
};
|
||||
|
||||
return createWorkspaceSurfaceConfig({
|
||||
key: isDeskView ? 'workspace' : 'documents',
|
||||
variant: isDeskView ? 'workspace' : 'documents',
|
||||
title,
|
||||
subtitle,
|
||||
sidebarToggle,
|
||||
actions,
|
||||
breadcrumbs,
|
||||
selectionLabel: null,
|
||||
floatingActions,
|
||||
content: (
|
||||
<DocumentsPanel
|
||||
{...tableProps}
|
||||
headerConfig={headerConfig}
|
||||
onInspectDocument={onInspectDocument}
|
||||
/>
|
||||
),
|
||||
detail,
|
||||
});
|
||||
};
|
||||
|
||||
export default createDocumentsSurface;
|
||||
@@ -1,67 +0,0 @@
|
||||
import { ReactNode } from 'react';
|
||||
|
||||
interface WorkspaceSurfaceHeaderConfig {
|
||||
title: ReactNode;
|
||||
subtitle?: ReactNode;
|
||||
leading?: ReactNode;
|
||||
actions?: ReactNode;
|
||||
breadcrumbs?: ReactNode;
|
||||
selectionLabel?: ReactNode;
|
||||
floatingActions?: ReactNode;
|
||||
}
|
||||
|
||||
interface WorkspaceSurfaceConfig {
|
||||
key: string;
|
||||
variant: string;
|
||||
header: WorkspaceSurfaceHeaderConfig;
|
||||
content?: ReactNode;
|
||||
detail?: ReactNode;
|
||||
}
|
||||
|
||||
interface CreateWorkspaceSurfaceConfigArgs {
|
||||
title: ReactNode;
|
||||
subtitle?: ReactNode;
|
||||
sidebarToggle?: ReactNode;
|
||||
actions?: ReactNode;
|
||||
breadcrumbs?: ReactNode;
|
||||
selectionLabel?: ReactNode;
|
||||
floatingActions?: ReactNode;
|
||||
content?: ReactNode;
|
||||
detail?: ReactNode;
|
||||
variant?: string;
|
||||
key?: string;
|
||||
}
|
||||
|
||||
export const createWorkspaceSurfaceConfig = ({
|
||||
title,
|
||||
subtitle = null,
|
||||
sidebarToggle = null,
|
||||
actions = null,
|
||||
breadcrumbs = null,
|
||||
selectionLabel = null,
|
||||
floatingActions = null,
|
||||
content = null,
|
||||
detail = null,
|
||||
variant = 'documents',
|
||||
key = 'documents',
|
||||
}: CreateWorkspaceSurfaceConfigArgs): WorkspaceSurfaceConfig => {
|
||||
const leading = sidebarToggle ? <>{sidebarToggle}</> : null;
|
||||
|
||||
return {
|
||||
key,
|
||||
variant,
|
||||
header: {
|
||||
title,
|
||||
subtitle,
|
||||
leading,
|
||||
actions,
|
||||
breadcrumbs,
|
||||
selectionLabel,
|
||||
floatingActions,
|
||||
},
|
||||
content,
|
||||
detail,
|
||||
};
|
||||
};
|
||||
|
||||
export default createWorkspaceSurfaceConfig;
|
||||
@@ -546,62 +546,3 @@ const DocumentViewerPanel: React.FC<DocumentViewerPanelProps> = ({
|
||||
};
|
||||
|
||||
export default DocumentViewerPanel;
|
||||
|
||||
export const createDocumentViewerSurface = ({
|
||||
document,
|
||||
documentLink,
|
||||
ensureAssetUrl,
|
||||
ensurePreviewData,
|
||||
getDocumentAsset,
|
||||
resolveApiPath,
|
||||
notifyApiError,
|
||||
onClose,
|
||||
renderSidebarToggle,
|
||||
tagLookupById,
|
||||
tagOptions,
|
||||
onTagAdd,
|
||||
onTagRemove,
|
||||
correspondents,
|
||||
onCorrespondentAdd,
|
||||
onCorrespondentRemove,
|
||||
onUpdateTitle,
|
||||
onUpdateIssued,
|
||||
resolveFolderPath,
|
||||
}) => {
|
||||
if (!document) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const sidebarToggle = renderSidebarToggle ? renderSidebarToggle() : null;
|
||||
|
||||
return {
|
||||
key: 'preview',
|
||||
variant: 'preview',
|
||||
header: null,
|
||||
content: (
|
||||
<DocumentViewerPanel
|
||||
document={document}
|
||||
documentLink={documentLink}
|
||||
hydrateDocument={ensurePreviewData}
|
||||
tagLookupById={tagLookupById}
|
||||
tagOptions={tagOptions}
|
||||
onTagAdd={onTagAdd}
|
||||
onTagRemove={onTagRemove}
|
||||
correspondents={correspondents}
|
||||
onCorrespondentAdd={onCorrespondentAdd}
|
||||
onCorrespondentRemove={onCorrespondentRemove}
|
||||
onUpdateTitle={onUpdateTitle}
|
||||
onUpdateIssued={onUpdateIssued}
|
||||
ensureAssetUrl={ensureAssetUrl}
|
||||
getDocumentAsset={getDocumentAsset}
|
||||
ensurePreviewData={ensurePreviewData}
|
||||
resolveApiPath={resolveApiPath}
|
||||
notifyApiError={notifyApiError}
|
||||
sidebarToggle={sidebarToggle}
|
||||
onClosePanel={onClose}
|
||||
resolveFolderPath={resolveFolderPath}
|
||||
/>
|
||||
),
|
||||
supportsDetail: false,
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user