This commit is contained in:
2025-11-06 01:46:33 +01:00
parent a16f1501d3
commit 82ae18b4b9
5 changed files with 489 additions and 28 deletions
+147 -6
View File
@@ -6,7 +6,12 @@ import {
RefreshIcon,
MinusVerticalIcon,
InfoIcon,
FoldersIcon,
FoldersOffIcon,
SortAscendingLettersIcon,
SortDescendingLettersIcon,
} from '../ui/icons';
import QuickAddMenu from '../ui/QuickAddMenu';
import BreadcrumbTrail from '../ui/BreadcrumbTrail';
import createWorkspaceSurfaceConfig from './workspaceHeader';
import DetailPanel from '../detail/DetailPanel';
@@ -25,6 +30,19 @@ const EntryType = {
document: 'document',
};
const SORT_OPTIONS = [
{ value: 'title', label: 'Title' },
{ value: 'issued_at', label: 'Issued date' },
{ value: 'created_at', label: 'Added' },
{ value: 'updated_at', label: 'Updated date' },
];
const SORT_LABEL_LOOKUP = SORT_OPTIONS.reduce((accumulator, option) => {
const next = accumulator;
next[option.value] = option.label;
return next;
}, {});
const DocumentsPanel = ({
currentFolderName,
breadcrumbs,
@@ -545,7 +563,6 @@ const DocumentsPanel = ({
const showDefaultEmptyState = !showingSearchResults && !isFilterActive && entries.length === 0;
const showListSearchEmptyState = showingSearchResults && !hasDocumentEntries && !isGridView && !isSearchLoading;
const showGridSearchEmptyState = isGridView && showingSearchResults && !hasDocumentEntries && !isSearchLoading;
const showSearchHint = showingSearchResults && rows.length > 0;
const breadcrumbEntries = useMemo(() => (Array.isArray(breadcrumbs) ? breadcrumbs.filter(Boolean) : []), [breadcrumbs]);
const trailEntries = useMemo(() => {
if (!breadcrumbEntries.length) {
@@ -724,11 +741,6 @@ const DocumentsPanel = ({
/>
)}
</div>
{showSearchHint && (
<div className="search-hint">
Showing {rows.length} document{rows.length === 1 ? '' : 's'} in {currentFolderName} and subfolders.
</div>
)}
</div>
)}
</section>
@@ -743,16 +755,115 @@ const DocumentsPanel = ({
export default DocumentsPanel;
const SortFieldQuickMenu = ({ sortField, onChange }) => {
const currentOption = useMemo(
() => SORT_OPTIONS.find((option) => option.value === sortField) || SORT_OPTIONS[0],
[sortField],
);
const options = useMemo(
() => SORT_OPTIONS.map((option) => ({ id: option.value, label: option.label })),
[],
);
const handleSelect = useCallback(
(value, option) => {
if (typeof onChange !== 'function') {
return;
}
const nextValue = option?.id || option?.original?.id || value;
if (nextValue) {
onChange(nextValue);
}
},
[onChange],
);
const label = currentOption?.label || SORT_LABEL_LOOKUP[currentOption?.value] || 'Title';
return (
<QuickAddMenu
className="documents-sort__quickmenu"
options={options}
onSelectOption={handleSelect}
triggerClassName="view-toggle__button documents-sort__trigger quick-add__trigger"
triggerContent={(
<span className="documents-sort__trigger-content">
<span className="documents-sort__label">{label}</span>
</span>
)}
triggerAriaLabel={`Sort by ${label}`}
triggerTitle={`Sort by ${label}`}
placeholder="Select sort field"
menuMinWidth={200}
align="start"
positionStrategy="absolute"
/>
);
};
export const createDocumentsTableHeaderActions = ({
viewMode,
onViewModeChange,
onRefresh,
onShowDeskHelp = null,
sortField = 'title',
onSortFieldChange = null,
sortDirection = 'asc',
onSortDirectionToggle = null,
isFilterActive = false,
includeDescendants = true,
onToggleIncludeDescendants = null,
}) => {
const isListView = viewMode === 'list';
const isGridView = viewMode === 'grid';
const isDeskView = viewMode === 'desk';
const sortDirectionIsDesc = sortDirection === 'desc';
const sortDirectionTitle = sortDirectionIsDesc
? 'Sorting Z → A. Click to switch to ascending.'
: 'Sorting A → Z. Click to switch to descending.';
const includeDescendantsToggle = isFilterActive && typeof onToggleIncludeDescendants === 'function'
? (
<button
type="button"
className="icon-button documents-toolbar__toggle"
onClick={onToggleIncludeDescendants}
aria-pressed={!includeDescendants}
aria-label={includeDescendants ? 'Include subfolders' : 'Limit to current folder'}
title={includeDescendants
? 'Including subfolders. Click to limit the search to the current folder.'
: 'Limiting to the current folder. Click to include subfolders again.'}
>
{includeDescendants ? <FoldersIcon /> : <FoldersOffIcon />}
</button>
)
: null;
const sortControls = typeof onSortFieldChange === 'function'
? (
<div className="documents-actions__sort-group">
<SortFieldQuickMenu sortField={sortField} onChange={onSortFieldChange} />
{typeof onSortDirectionToggle === 'function' ? (
<button
type="button"
className="icon-button documents-toolbar__toggle documents-sort__direction"
onClick={onSortDirectionToggle}
aria-pressed={sortDirectionIsDesc}
aria-label={sortDirectionIsDesc ? 'Sort descending' : 'Sort ascending'}
title={sortDirectionTitle}
>
{sortDirectionIsDesc ? (
<SortDescendingLettersIcon size={18} />
) : (
<SortAscendingLettersIcon size={18} />
)}
</button>
) : null}
</div>
)
: null;
return (
<>
{isDeskView && typeof onShowDeskHelp === 'function' ? (
@@ -771,6 +882,22 @@ export const createDocumentsTableHeaderActions = ({
</span>
</>
) : null}
{includeDescendantsToggle ? (
<>
{includeDescendantsToggle}
<span className="main-content__actions-divider" aria-hidden="true">
<MinusVerticalIcon />
</span>
</>
) : null}
{sortControls ? (
<>
{sortControls}
<span className="main-content__actions-divider" aria-hidden="true">
<MinusVerticalIcon />
</span>
</>
) : null}
<div className="view-toggle" role="group" aria-label="Change view">
<button
type="button"
@@ -828,9 +955,14 @@ export const createDocumentsSurface = ({
currentFolderName,
breadcrumbs,
searchResults,
isFilterActive,
viewMode,
onViewModeChange,
onRefresh,
sortField,
sortDirection,
onSortFieldChange,
onSortDirectionToggle,
selectedDocumentIds,
selectedFolderIds,
onDeleteSelection,
@@ -846,6 +978,8 @@ export const createDocumentsSurface = ({
onBulkReanalyze,
folderOptions,
onMoveDocumentsToFolder,
searchIncludeDescendants,
onToggleSearchIncludeDescendants,
} = tableProps;
const title = Array.isArray(searchResults) ? 'Search results' : currentFolderName;
@@ -862,6 +996,13 @@ export const createDocumentsSurface = ({
viewMode,
onViewModeChange,
onRefresh,
sortField,
onSortFieldChange,
sortDirection,
onSortDirectionToggle,
isFilterActive,
includeDescendants: searchIncludeDescendants,
onToggleIncludeDescendants: onToggleSearchIncludeDescendants,
});
const floatingActions = selectionCount > 0