mirror of
https://github.com/haiwen/seahub.git
synced 2025-05-09 08:28:42 +00:00
Merge pull request #7650 from haiwen/feature/sort_tag_files
Feature/sort tag files
This commit is contained in:
commit
1841d799a2
frontend/src
components/cur-dir-path
metadata
tag
@ -12,7 +12,8 @@ import MetadataViewToolBar from '../../metadata/components/view-toolbar';
|
||||
import TagsTableSearcher from '../../tag/views/all-tags/tags-table/tags-searcher';
|
||||
import { PRIVATE_FILE_TYPE } from '../../constants';
|
||||
import { ALL_TAGS_ID } from '../../tag/constants';
|
||||
import SortSetter from '../../tag/views/all-tags/tags-table/sort-setter';
|
||||
import AllTagsSortSetter from '../../tag/views/all-tags/tags-table/sort-setter';
|
||||
import TagFilesSortSetter from '../../tag/views/tag-files/sort-setter';
|
||||
|
||||
const propTypes = {
|
||||
repoID: PropTypes.string.isRequired,
|
||||
@ -120,8 +121,8 @@ class DirTool extends React.Component {
|
||||
if (isTagView) {
|
||||
return (
|
||||
<div className="dir-tool">
|
||||
<TagsTableSearcher />
|
||||
{isAllTagsView && <SortSetter />}
|
||||
{isAllTagsView && <TagsTableSearcher />}
|
||||
{isAllTagsView ? <AllTagsSortSetter /> : <TagFilesSortSetter />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -137,50 +138,50 @@ class DirTool extends React.Component {
|
||||
</div>
|
||||
}
|
||||
{menuItems.length > 0 &&
|
||||
<Dropdown isOpen={isDropdownMenuOpen} toggle={this.toggleDropdownMenu}>
|
||||
<DropdownToggle
|
||||
tag="i"
|
||||
id="cur-folder-more-op-toggle"
|
||||
className='cur-view-path-btn sf3-font-more sf3-font'
|
||||
data-toggle="dropdown"
|
||||
title={gettext('More operations')}
|
||||
aria-label={gettext('More operations')}
|
||||
aria-expanded={isDropdownMenuOpen}
|
||||
>
|
||||
</DropdownToggle>
|
||||
<DropdownMenu>
|
||||
{menuItems.map((menuItem, index) => {
|
||||
if (menuItem === 'Divider') {
|
||||
return <DropdownItem key={index} divider />;
|
||||
} else {
|
||||
return (
|
||||
<DropdownItem
|
||||
key={index}
|
||||
onClick={this.onMenuItemClick.bind(this, menuItem)}
|
||||
onKeyDown={this.onMenuItemKeyDown.bind(this, menuItem)}
|
||||
>{menuItem.value}
|
||||
</DropdownItem>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
<Dropdown isOpen={isDropdownMenuOpen} toggle={this.toggleDropdownMenu}>
|
||||
<DropdownToggle
|
||||
tag="i"
|
||||
id="cur-folder-more-op-toggle"
|
||||
className='cur-view-path-btn sf3-font-more sf3-font'
|
||||
data-toggle="dropdown"
|
||||
title={gettext('More operations')}
|
||||
aria-label={gettext('More operations')}
|
||||
aria-expanded={isDropdownMenuOpen}
|
||||
>
|
||||
</DropdownToggle>
|
||||
<DropdownMenu>
|
||||
{menuItems.map((menuItem, index) => {
|
||||
if (menuItem === 'Divider') {
|
||||
return <DropdownItem key={index} divider />;
|
||||
} else {
|
||||
return (
|
||||
<DropdownItem
|
||||
key={index}
|
||||
onClick={this.onMenuItemClick.bind(this, menuItem)}
|
||||
onKeyDown={this.onMenuItemKeyDown.bind(this, menuItem)}
|
||||
>{menuItem.value}
|
||||
</DropdownItem>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</DropdownMenu>
|
||||
</Dropdown>
|
||||
}
|
||||
</div>
|
||||
{this.state.isRepoTagDialogOpen &&
|
||||
<CustomizePopover
|
||||
popoverClassName="list-tag-popover"
|
||||
target="cur-folder-more-op-toggle"
|
||||
hidePopover={this.hidePopover}
|
||||
hidePopoverWithEsc={this.hidePopover}
|
||||
boundariesElement={document.body}
|
||||
placement={'bottom-end'}
|
||||
>
|
||||
<ListTagPopover
|
||||
repoID={repoID}
|
||||
onListTagCancel={this.toggleCancel}
|
||||
/>
|
||||
</CustomizePopover>
|
||||
<CustomizePopover
|
||||
popoverClassName="list-tag-popover"
|
||||
target="cur-folder-more-op-toggle"
|
||||
hidePopover={this.hidePopover}
|
||||
hidePopoverWithEsc={this.hidePopover}
|
||||
boundariesElement={document.body}
|
||||
placement={'bottom-end'}
|
||||
>
|
||||
<ListTagPopover
|
||||
repoID={repoID}
|
||||
onListTagCancel={this.toggleCancel}
|
||||
/>
|
||||
</CustomizePopover>
|
||||
}
|
||||
</React.Fragment>
|
||||
);
|
||||
|
@ -20,7 +20,9 @@ const FileTagsFormatter = ({ tagsData, value: oldValue, className, children: emp
|
||||
const tag = getRowById(tagsData, item);
|
||||
const tagColor = getTagColor(tag);
|
||||
const tagName = getTagName(tag);
|
||||
if (!showName) return <span className="sf-metadata-ui-tag-color" style={{ backgroundColor: tagColor }}></span>;
|
||||
if (!showName) return (
|
||||
<span key={item} className="sf-metadata-ui-tag-color" style={{ backgroundColor: tagColor }}></span>
|
||||
);
|
||||
return (
|
||||
<div key={item} className="sf-metadata-ui-tag" title={tagName}>
|
||||
<span className="sf-metadata-ui-tag-color mr-1" style={{ backgroundColor: tagColor }}></span>
|
||||
|
@ -98,6 +98,7 @@ export const EVENT_BUS_TYPE = {
|
||||
DELETE_TAG_FILES: 'delete_tag_files',
|
||||
SELECT_TAG_FILES: 'select_tag_files',
|
||||
UNSELECT_TAG_FILES: 'unselect_tag_files',
|
||||
MODIFY_TAG_FILES_SORT: 'modify_tag_files_sort',
|
||||
|
||||
// tags
|
||||
SELECT_TAGS: 'select_tags',
|
||||
|
@ -10,3 +10,16 @@ export const ALL_TAGS_SORT_KEY = {
|
||||
CHILD_TAGS_COUNT: 'child_tags_count',
|
||||
TAG_FILE_COUNT: 'tag_file_count'
|
||||
};
|
||||
|
||||
export const TAG_FILES_SORT = 'tag_files_sort';
|
||||
|
||||
export const TAG_FILES_DEFAULT_SORT = {
|
||||
sort_by: 'name',
|
||||
order: 'asc'
|
||||
};
|
||||
|
||||
export const TAG_FILES_SORT_KEY = {
|
||||
NAME: 'name',
|
||||
SIZE: 'size',
|
||||
TIME: 'time'
|
||||
};
|
||||
|
@ -9,12 +9,13 @@ import { getAllChildTagsIdsFromNode } from '../utils/tree';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { TAG_FILE_KEY } from '../constants/file';
|
||||
import { EVENT_BUS_TYPE } from '../../metadata/constants';
|
||||
import { getFileById } from '../utils/file';
|
||||
import { getFileById, sortTagFiles } from '../utils/file';
|
||||
import { getRowById } from '../../components/sf-table/utils/table';
|
||||
import { getTagFilesLinks } from '../utils/cell';
|
||||
import { PRIVATE_COLUMN_KEY } from '../constants';
|
||||
import URLDecorator from '../../utils/url-decorator';
|
||||
import { fileServerRoot, useGoFileserver } from '../../utils/constants';
|
||||
import { TAG_FILES_DEFAULT_SORT, TAG_FILES_SORT } from '../constants/sort';
|
||||
|
||||
// This hook provides content related to seahub interaction, such as whether to enable extended attributes, views data, etc.
|
||||
const TagViewContext = React.createContext(null);
|
||||
@ -156,6 +157,14 @@ export const TagViewProvider = ({
|
||||
});
|
||||
}, [repoID, convertFileCallback]);
|
||||
|
||||
const sortFiles = useCallback((sort) => {
|
||||
const sorted = sortTagFiles(tagFiles, sort);
|
||||
setTagFiles({
|
||||
...tagFiles,
|
||||
rows: sorted,
|
||||
});
|
||||
}, [tagFiles]);
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(true);
|
||||
const childTagsIds = getChildTagsIds(tagID, nodeKey);
|
||||
@ -165,7 +174,10 @@ export const TagViewProvider = ({
|
||||
}
|
||||
tagsAPI.getTagsFiles(repoID, tagsIds).then(res => {
|
||||
const rows = res.data?.results || [];
|
||||
setTagFiles({ columns: res.data?.metadata || [], rows });
|
||||
const savedSort = window.sfTagsDataContext?.localStorage?.getItem(TAG_FILES_SORT);
|
||||
const sort = savedSort ? JSON.parse(savedSort) : TAG_FILES_DEFAULT_SORT;
|
||||
const sorted = sortTagFiles(rows, sort);
|
||||
setTagFiles({ columns: res.data?.metadata || [], rows: sorted });
|
||||
setLoading(false);
|
||||
}).catch(error => {
|
||||
const errorMessage = Utils.getErrorMsg(error);
|
||||
@ -175,6 +187,21 @@ export const TagViewProvider = ({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [repoID, tagID, nodeKey]);
|
||||
|
||||
useEffect(() => {
|
||||
const unsubscribeModifyTagFilesSort = window.sfTagsDataContext?.eventBus?.subscribe(EVENT_BUS_TYPE.MODIFY_TAG_FILES_SORT, (sort) => {
|
||||
const files = tagFiles?.rows || [];
|
||||
const sorted = sortTagFiles(files, sort);
|
||||
setTagFiles({
|
||||
...tagFiles,
|
||||
rows: sorted,
|
||||
});
|
||||
});
|
||||
|
||||
return () => {
|
||||
unsubscribeModifyTagFilesSort && unsubscribeModifyTagFilesSort();
|
||||
};
|
||||
}, [tagFiles]);
|
||||
|
||||
return (
|
||||
<TagViewContext.Provider value={{
|
||||
isLoading,
|
||||
@ -194,6 +221,7 @@ export const TagViewProvider = ({
|
||||
downloadTagFiles,
|
||||
renameTagFile,
|
||||
convertFile,
|
||||
sortFiles,
|
||||
}}>
|
||||
{children}
|
||||
</TagViewContext.Provider>
|
||||
|
@ -1,7 +1,10 @@
|
||||
import { compareString } from '../../metadata/utils/sort';
|
||||
import { enableSeadoc, fileAuditEnabled, isPro } from '../../utils/constants';
|
||||
import TextTranslation from '../../utils/text-translation';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { TAG_FILE_KEY } from '../constants/file';
|
||||
import { TAG_FILES_SORT_KEY } from '../constants/sort';
|
||||
import { getSortBy, getSortOrder } from './sort';
|
||||
|
||||
export const getFileById = (tagFiles, fileId) => {
|
||||
return fileId ? tagFiles.rows.find(file => file._id === fileId) : '';
|
||||
@ -15,6 +18,14 @@ export const getFileParentDir = (file) => {
|
||||
return file ? file[TAG_FILE_KEY.PARENT_DIR] : '';
|
||||
};
|
||||
|
||||
export const getFileMTime = (file) => {
|
||||
return file ? file[TAG_FILE_KEY.FILE_MTIME] : '';
|
||||
};
|
||||
|
||||
export const getFileSize = (file) => {
|
||||
return file ? file[TAG_FILE_KEY.SIZE] : '';
|
||||
};
|
||||
|
||||
export const getTagFileOperationList = (fileName, repo, canModify) => {
|
||||
const {
|
||||
SHARE, DOWNLOAD, DELETE, RENAME, MOVE, COPY, HISTORY, ACCESS_LOG, OPEN_VIA_CLIENT, CONVERT_AND_EXPORT, CONVERT_TO_MARKDOWN, CONVERT_TO_DOCX, EXPORT_DOCX, CONVERT_TO_SDOC, EXPORT_SDOC
|
||||
@ -60,3 +71,38 @@ export const getTagFileOperationList = (fileName, repo, canModify) => {
|
||||
}
|
||||
return menuList;
|
||||
};
|
||||
|
||||
export const sortTagFiles = (files, sort) => {
|
||||
const sortBy = getSortBy(sort);
|
||||
const order = getSortOrder(sort);
|
||||
|
||||
const compare = (a, b) => {
|
||||
let valueA = '';
|
||||
let valueB = '';
|
||||
switch (sortBy) {
|
||||
case TAG_FILES_SORT_KEY.NAME:
|
||||
valueA = getFileName(a);
|
||||
valueB = getFileName(b);
|
||||
break;
|
||||
case TAG_FILES_SORT_KEY.SIZE:
|
||||
valueA = getFileSize(a);
|
||||
valueB = getFileSize(b);
|
||||
break;
|
||||
case TAG_FILES_SORT_KEY.TIME:
|
||||
valueA = getFileMTime(a);
|
||||
valueB = getFileMTime(b);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const result =
|
||||
sortBy === TAG_FILES_SORT_KEY.SIZE
|
||||
? valueA - valueB
|
||||
: compareString(valueA, valueB);
|
||||
|
||||
return order === 'asc' ? result : -result;
|
||||
};
|
||||
|
||||
return files.sort(compare);
|
||||
};
|
||||
|
31
frontend/src/tag/views/tag-files/sort-setter.js
Normal file
31
frontend/src/tag/views/tag-files/sort-setter.js
Normal file
@ -0,0 +1,31 @@
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import SortMenu from '../../../components/sort-menu';
|
||||
import { EVENT_BUS_TYPE } from '../../../metadata/constants';
|
||||
import { TAG_FILES_SORT, TAG_FILES_DEFAULT_SORT } from '../../constants/sort';
|
||||
import { getSortBy, getSortOrder } from '../../utils/sort';
|
||||
|
||||
const SortSetter = () => {
|
||||
const [sort, setSort] = useState(TAG_FILES_DEFAULT_SORT);
|
||||
|
||||
const eventBus = useMemo(() => window.sfTagsDataContext?.eventBus, []);
|
||||
const localStorage = useMemo(() => window.sfTagsDataContext?.localStorage, []);
|
||||
|
||||
const onSelectSortOption = useCallback((item) => {
|
||||
const [sortBy, order] = item.value.split('-');
|
||||
const newSort = { sort_by: sortBy, order };
|
||||
setSort(newSort);
|
||||
eventBus && eventBus.dispatch(EVENT_BUS_TYPE.MODIFY_TAG_FILES_SORT, newSort);
|
||||
}, [eventBus]);
|
||||
|
||||
useEffect(() => {
|
||||
const storedSort = localStorage && localStorage.getItem(TAG_FILES_SORT);
|
||||
const sort = storedSort ? JSON.parse(storedSort) : TAG_FILES_DEFAULT_SORT;
|
||||
setSort(sort);
|
||||
}, [localStorage]);
|
||||
|
||||
return (
|
||||
<SortMenu sortBy={getSortBy(sort)} sortOrder={getSortOrder(sort)} onSelectSortOption={onSelectSortOption} />
|
||||
);
|
||||
};
|
||||
|
||||
export default SortSetter;
|
Loading…
Reference in New Issue
Block a user