sorting
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user