mirror of
https://github.com/haiwen/seahub.git
synced 2025-08-09 19:07:40 +00:00
Merge pull request #7650 from haiwen/feature/sort_tag_files
Feature/sort tag files
This commit is contained in:
commit
1841d799a2
@ -12,7 +12,8 @@ import MetadataViewToolBar from '../../metadata/components/view-toolbar';
|
|||||||
import TagsTableSearcher from '../../tag/views/all-tags/tags-table/tags-searcher';
|
import TagsTableSearcher from '../../tag/views/all-tags/tags-table/tags-searcher';
|
||||||
import { PRIVATE_FILE_TYPE } from '../../constants';
|
import { PRIVATE_FILE_TYPE } from '../../constants';
|
||||||
import { ALL_TAGS_ID } from '../../tag/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 = {
|
const propTypes = {
|
||||||
repoID: PropTypes.string.isRequired,
|
repoID: PropTypes.string.isRequired,
|
||||||
@ -120,8 +121,8 @@ class DirTool extends React.Component {
|
|||||||
if (isTagView) {
|
if (isTagView) {
|
||||||
return (
|
return (
|
||||||
<div className="dir-tool">
|
<div className="dir-tool">
|
||||||
<TagsTableSearcher />
|
{isAllTagsView && <TagsTableSearcher />}
|
||||||
{isAllTagsView && <SortSetter />}
|
{isAllTagsView ? <AllTagsSortSetter /> : <TagFilesSortSetter />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,9 @@ const FileTagsFormatter = ({ tagsData, value: oldValue, className, children: emp
|
|||||||
const tag = getRowById(tagsData, item);
|
const tag = getRowById(tagsData, item);
|
||||||
const tagColor = getTagColor(tag);
|
const tagColor = getTagColor(tag);
|
||||||
const tagName = getTagName(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 (
|
return (
|
||||||
<div key={item} className="sf-metadata-ui-tag" title={tagName}>
|
<div key={item} className="sf-metadata-ui-tag" title={tagName}>
|
||||||
<span className="sf-metadata-ui-tag-color mr-1" style={{ backgroundColor: tagColor }}></span>
|
<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',
|
DELETE_TAG_FILES: 'delete_tag_files',
|
||||||
SELECT_TAG_FILES: 'select_tag_files',
|
SELECT_TAG_FILES: 'select_tag_files',
|
||||||
UNSELECT_TAG_FILES: 'unselect_tag_files',
|
UNSELECT_TAG_FILES: 'unselect_tag_files',
|
||||||
|
MODIFY_TAG_FILES_SORT: 'modify_tag_files_sort',
|
||||||
|
|
||||||
// tags
|
// tags
|
||||||
SELECT_TAGS: 'select_tags',
|
SELECT_TAGS: 'select_tags',
|
||||||
|
@ -10,3 +10,16 @@ export const ALL_TAGS_SORT_KEY = {
|
|||||||
CHILD_TAGS_COUNT: 'child_tags_count',
|
CHILD_TAGS_COUNT: 'child_tags_count',
|
||||||
TAG_FILE_COUNT: 'tag_file_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 { seafileAPI } from '../../utils/seafile-api';
|
||||||
import { TAG_FILE_KEY } from '../constants/file';
|
import { TAG_FILE_KEY } from '../constants/file';
|
||||||
import { EVENT_BUS_TYPE } from '../../metadata/constants';
|
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 { getRowById } from '../../components/sf-table/utils/table';
|
||||||
import { getTagFilesLinks } from '../utils/cell';
|
import { getTagFilesLinks } from '../utils/cell';
|
||||||
import { PRIVATE_COLUMN_KEY } from '../constants';
|
import { PRIVATE_COLUMN_KEY } from '../constants';
|
||||||
import URLDecorator from '../../utils/url-decorator';
|
import URLDecorator from '../../utils/url-decorator';
|
||||||
import { fileServerRoot, useGoFileserver } from '../../utils/constants';
|
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.
|
// This hook provides content related to seahub interaction, such as whether to enable extended attributes, views data, etc.
|
||||||
const TagViewContext = React.createContext(null);
|
const TagViewContext = React.createContext(null);
|
||||||
@ -156,6 +157,14 @@ export const TagViewProvider = ({
|
|||||||
});
|
});
|
||||||
}, [repoID, convertFileCallback]);
|
}, [repoID, convertFileCallback]);
|
||||||
|
|
||||||
|
const sortFiles = useCallback((sort) => {
|
||||||
|
const sorted = sortTagFiles(tagFiles, sort);
|
||||||
|
setTagFiles({
|
||||||
|
...tagFiles,
|
||||||
|
rows: sorted,
|
||||||
|
});
|
||||||
|
}, [tagFiles]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
const childTagsIds = getChildTagsIds(tagID, nodeKey);
|
const childTagsIds = getChildTagsIds(tagID, nodeKey);
|
||||||
@ -165,7 +174,10 @@ export const TagViewProvider = ({
|
|||||||
}
|
}
|
||||||
tagsAPI.getTagsFiles(repoID, tagsIds).then(res => {
|
tagsAPI.getTagsFiles(repoID, tagsIds).then(res => {
|
||||||
const rows = res.data?.results || [];
|
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);
|
setLoading(false);
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
const errorMessage = Utils.getErrorMsg(error);
|
const errorMessage = Utils.getErrorMsg(error);
|
||||||
@ -175,6 +187,21 @@ export const TagViewProvider = ({
|
|||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
}, [repoID, tagID, nodeKey]);
|
}, [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 (
|
return (
|
||||||
<TagViewContext.Provider value={{
|
<TagViewContext.Provider value={{
|
||||||
isLoading,
|
isLoading,
|
||||||
@ -194,6 +221,7 @@ export const TagViewProvider = ({
|
|||||||
downloadTagFiles,
|
downloadTagFiles,
|
||||||
renameTagFile,
|
renameTagFile,
|
||||||
convertFile,
|
convertFile,
|
||||||
|
sortFiles,
|
||||||
}}>
|
}}>
|
||||||
{children}
|
{children}
|
||||||
</TagViewContext.Provider>
|
</TagViewContext.Provider>
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
|
import { compareString } from '../../metadata/utils/sort';
|
||||||
import { enableSeadoc, fileAuditEnabled, isPro } from '../../utils/constants';
|
import { enableSeadoc, fileAuditEnabled, isPro } from '../../utils/constants';
|
||||||
import TextTranslation from '../../utils/text-translation';
|
import TextTranslation from '../../utils/text-translation';
|
||||||
import { Utils } from '../../utils/utils';
|
import { Utils } from '../../utils/utils';
|
||||||
import { TAG_FILE_KEY } from '../constants/file';
|
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) => {
|
export const getFileById = (tagFiles, fileId) => {
|
||||||
return fileId ? tagFiles.rows.find(file => file._id === 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] : '';
|
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) => {
|
export const getTagFileOperationList = (fileName, repo, canModify) => {
|
||||||
const {
|
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
|
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;
|
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