This commit is contained in:
2025-11-19 00:44:47 +01:00
parent 3e21e72953
commit 1764f24243
6 changed files with 173 additions and 309 deletions
-1
View File
@@ -1,3 +1,2 @@
export { default } from './panel/DocumentsPanel';
export { default as createDocumentsSurface } from './panel/createDocumentsSurface';
export { createDocumentsTableHeaderActions } from './panel/DocumentsToolbar';
+107 -10
View File
@@ -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;