mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-24 04:48:03 +00:00
sortable directory tree (#8069)
Co-authored-by: zhouwenxuan <aries@Mac.local>
This commit is contained in:
@@ -29,7 +29,8 @@ const propTypes = {
|
||||
getMenuContainerSize: PropTypes.func,
|
||||
updateDirent: PropTypes.func,
|
||||
updateTreeNode: PropTypes.func,
|
||||
updateRepoInfo: PropTypes.func
|
||||
updateRepoInfo: PropTypes.func,
|
||||
sortTreeNode: PropTypes.func,
|
||||
};
|
||||
|
||||
class DirColumnNav extends React.Component {
|
||||
@@ -67,6 +68,7 @@ class DirColumnNav extends React.Component {
|
||||
onItemsMove={this.props.onItemsMove}
|
||||
updateDirent={this.props.updateDirent}
|
||||
updateTreeNode={this.props.updateTreeNode}
|
||||
sortTreeNode={this.props.sortTreeNode}
|
||||
/>
|
||||
<DirViews repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
||||
<DirTags repoID={repoID} currentPath={currentPath} userPerm={userPerm} currentRepoInfo={currentRepoInfo} />
|
||||
|
@@ -79,7 +79,8 @@ const propTypes = {
|
||||
updateCurrentPath: PropTypes.func,
|
||||
toggleShowDirentToolbar: PropTypes.func,
|
||||
updateTreeNode: PropTypes.func,
|
||||
updateRepoInfo: PropTypes.func
|
||||
updateRepoInfo: PropTypes.func,
|
||||
sortTreeNode: PropTypes.func,
|
||||
};
|
||||
|
||||
class DirColumnView extends React.Component {
|
||||
@@ -177,6 +178,7 @@ class DirColumnView extends React.Component {
|
||||
direntList={this.props.direntList}
|
||||
updateDirent={this.props.updateDirent}
|
||||
updateTreeNode={this.props.updateTreeNode}
|
||||
sortTreeNode={this.props.sortTreeNode}
|
||||
/>
|
||||
<ResizeBar
|
||||
resizeBarRef={this.resizeBarRef}
|
||||
|
@@ -1,11 +1,12 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import cookie from 'react-cookies';
|
||||
import TreeView from '../tree-view/tree-view';
|
||||
import ModalPortal from '../modal-portal';
|
||||
import ImageDialog from '../dialog/image-dialog';
|
||||
import toaster from '../toast';
|
||||
import ItemDropdownMenu from '../dropdown-menu/item-dropdown-menu';
|
||||
import { fileServerRoot, gettext, siteRoot, thumbnailSizeForOriginal, thumbnailDefaultSize } from '../../utils/constants';
|
||||
import { fileServerRoot, gettext, siteRoot, thumbnailSizeForOriginal, thumbnailDefaultSize, SF_DIRECTORY_TREE_SORT_BY_KEY, SF_DIRECTORY_TREE_SORT_ORDER_KEY } from '../../utils/constants';
|
||||
import { isMobile, Utils } from '../../utils/utils';
|
||||
import TextTranslation from '../../utils/text-translation';
|
||||
import TreeSection from '../tree-section';
|
||||
@@ -31,6 +32,12 @@ const propTypes = {
|
||||
onItemMove: PropTypes.func.isRequired,
|
||||
onItemsMove: PropTypes.func.isRequired,
|
||||
updateDirent: PropTypes.func,
|
||||
sortTreeNode: PropTypes.func,
|
||||
};
|
||||
|
||||
const SORT_KEY_MAP = {
|
||||
'name-asc': TextTranslation.ASCENDING_BY_NAME.key,
|
||||
'name-desc': TextTranslation.DESCENDING_BY_NAME.key,
|
||||
};
|
||||
|
||||
class DirFiles extends React.Component {
|
||||
@@ -46,12 +53,20 @@ class DirFiles extends React.Component {
|
||||
imageIndex: 0,
|
||||
operationList: [],
|
||||
isDisplayFiles: localStorage.getItem('sf_display_files') === 'true' || false,
|
||||
sortKey: TextTranslation.ASCENDING_BY_NAME.key,
|
||||
};
|
||||
this.isNodeMenuShow = true;
|
||||
this.imageItemsSnapshot = [];
|
||||
this.imageIndexSnapshot = 0;
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const sortBy = cookie.load(SF_DIRECTORY_TREE_SORT_BY_KEY) || 'name';
|
||||
const sortOrder = cookie.load(SF_DIRECTORY_TREE_SORT_ORDER_KEY) || 'asc';
|
||||
const sortKey = SORT_KEY_MAP[`${sortBy}-${sortOrder}`];
|
||||
this.setState({ sortKey });
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.direntList.length < this.props.direntList.length && this.state.isNodeImagePopupOpen) {
|
||||
if (this.state.imageNodeItems.length === 0) {
|
||||
@@ -73,6 +88,7 @@ class DirFiles extends React.Component {
|
||||
|
||||
getMenuList = () => {
|
||||
const { userPerm } = this.props;
|
||||
const { sortKey } = this.state;
|
||||
const list = [];
|
||||
if (userPerm == 'rw') {
|
||||
list.push(
|
||||
@@ -80,7 +96,10 @@ class DirFiles extends React.Component {
|
||||
TextTranslation.NEW_FILE
|
||||
);
|
||||
}
|
||||
list.push(TextTranslation.DISPLAY_FILES);
|
||||
list.push({ ...TextTranslation.DISPLAY_FILES, tick: this.state.isDisplayFiles });
|
||||
list.push('Divider');
|
||||
list.push({ ...TextTranslation.ASCENDING_BY_NAME, tick: sortKey === TextTranslation.ASCENDING_BY_NAME.key });
|
||||
list.push({ ...TextTranslation.DESCENDING_BY_NAME, tick: sortKey === TextTranslation.DESCENDING_BY_NAME.key });
|
||||
return list;
|
||||
};
|
||||
|
||||
@@ -142,6 +161,16 @@ class DirFiles extends React.Component {
|
||||
case 'Display files':
|
||||
this.onDisplayFilesToggle();
|
||||
break;
|
||||
case 'Ascending by name': {
|
||||
this.props.sortTreeNode('name', 'asc');
|
||||
this.setState({ sortKey: TextTranslation.ASCENDING_BY_NAME.key });
|
||||
break;
|
||||
}
|
||||
case 'Descending by name': {
|
||||
this.props.sortTreeNode('name', 'desc');
|
||||
this.setState({ sortKey: TextTranslation.DESCENDING_BY_NAME.key });
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -306,7 +335,6 @@ class DirFiles extends React.Component {
|
||||
item={{ name: 'files' }}
|
||||
toggleClass="sf3-font sf3-font-more"
|
||||
menuStyle={isMobile ? { zIndex: 1050 } : {}}
|
||||
isDisplayFiles={this.state.isDisplayFiles}
|
||||
getMenuList={this.getMenuList}
|
||||
onMenuItemClick={this.onMoreOperationClick}
|
||||
/>
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classnames from 'classnames';
|
||||
import { Dropdown, DropdownMenu, DropdownToggle, DropdownItem } from 'reactstrap';
|
||||
import listener from '../context-menu/globalEventListener';
|
||||
import { gettext } from '../../utils/constants';
|
||||
@@ -20,7 +19,6 @@ const propTypes = {
|
||||
freezeItem: PropTypes.func,
|
||||
unfreezeItem: PropTypes.func,
|
||||
menuStyle: PropTypes.object,
|
||||
isDisplayFiles: PropTypes.bool,
|
||||
};
|
||||
|
||||
class ItemDropdownMenu extends React.Component {
|
||||
@@ -279,16 +277,13 @@ class ItemDropdownMenu extends React.Component {
|
||||
return (
|
||||
<DropdownItem
|
||||
key={index}
|
||||
className={classnames({
|
||||
'pl-5': this.props.isDisplayFiles != undefined,
|
||||
'position-relative': this.props.isDisplayFiles
|
||||
})}
|
||||
className="position-relative pl-5"
|
||||
data-toggle={menuItem.key}
|
||||
onClick={this.onMenuItemClick}
|
||||
onKeyDown={this.onMenuItemKeyDown}
|
||||
onMouseMove={this.onDropDownMouseMove}
|
||||
>
|
||||
{menuItem.key === 'Display files' && this.props.isDisplayFiles && (
|
||||
{menuItem.tick && (
|
||||
<i className="dropdown-item-tick sf2-icon-tick"></i>
|
||||
)}
|
||||
{menuItem.icon_dom || null}
|
||||
|
@@ -9,7 +9,7 @@ import { Modal } from 'reactstrap';
|
||||
import { navigate } from '@gatsbyjs/reach-router';
|
||||
import { DndProvider } from 'react-dnd';
|
||||
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||
import { gettext, siteRoot, username } from '../../utils/constants';
|
||||
import { gettext, SF_DIRECTORY_TREE_SORT_BY_KEY, SF_DIRECTORY_TREE_SORT_ORDER_KEY, siteRoot, username } from '../../utils/constants';
|
||||
import { seafileAPI } from '../../utils/seafile-api';
|
||||
import { Utils } from '../../utils/utils';
|
||||
import { Dirent, FileTag, RepoTag, RepoInfo } from '../../models';
|
||||
@@ -2095,7 +2095,9 @@ class LibContentView extends React.Component {
|
||||
let direntList = list.map(item => {
|
||||
return new Dirent(item);
|
||||
});
|
||||
direntList = Utils.sortDirents(direntList, this.state.sortBy, this.state.sortOrder);
|
||||
const sortBy = cookie.load(SF_DIRECTORY_TREE_SORT_BY_KEY) || 'name';
|
||||
const sortOrder = cookie.load(SF_DIRECTORY_TREE_SORT_ORDER_KEY) || 'asc';
|
||||
direntList = Utils.sortDirents(direntList, sortBy, sortOrder);
|
||||
|
||||
let nodeList = direntList.map(object => {
|
||||
return new TreeNode({ object });
|
||||
@@ -2186,11 +2188,18 @@ class LibContentView extends React.Component {
|
||||
cookie.save('seafile-repo-dir-sort-order', sortOrder);
|
||||
|
||||
const sortedDirentList = Utils.sortDirents(this.state.direntList, sortBy, sortOrder);
|
||||
const sortedTreeData = treeHelper.sortTreeNodes(this.state.treeData, sortBy, sortOrder);
|
||||
this.setState({
|
||||
sortBy: sortBy,
|
||||
sortOrder: sortOrder,
|
||||
direntList: sortedDirentList,
|
||||
});
|
||||
};
|
||||
|
||||
sortTreeNode = (sortBy, sortOrder) => {
|
||||
cookie.save(SF_DIRECTORY_TREE_SORT_BY_KEY, sortBy);
|
||||
cookie.save(SF_DIRECTORY_TREE_SORT_ORDER_KEY, sortOrder);
|
||||
const sortedTreeData = treeHelper.sortTreeNodes(this.state.treeData, sortBy, sortOrder);
|
||||
this.setState({
|
||||
treeData: sortedTreeData,
|
||||
});
|
||||
};
|
||||
@@ -2551,6 +2560,7 @@ class LibContentView extends React.Component {
|
||||
updateCurrentPath={this.updatePath}
|
||||
toggleShowDirentToolbar={this.toggleShowDirentToolbar}
|
||||
updateTreeNode={this.updateTreeNode}
|
||||
sortTreeNode={this.sortTreeNode}
|
||||
/>
|
||||
:
|
||||
<div className="message err-tip">{gettext('Folder does not exist.')}</div>
|
||||
|
@@ -233,3 +233,6 @@ export const MimetypesKind = {
|
||||
export const LARGE_DIALOG_STYLE = { maxWidth: '980px' };
|
||||
|
||||
export const SF_COLOR_MODE = 'sf_color_mode';
|
||||
|
||||
export const SF_DIRECTORY_TREE_SORT_BY_KEY = 'sf_directory_tree_sort_by';
|
||||
export const SF_DIRECTORY_TREE_SORT_ORDER_KEY = 'sf_directory_tree_sort_order';
|
||||
|
@@ -278,6 +278,16 @@ const TextTranslation = {
|
||||
key: 'New child tag',
|
||||
value: gettext('New child tag'),
|
||||
},
|
||||
|
||||
// directory op
|
||||
ASCENDING_BY_NAME: {
|
||||
key: 'Ascending by name',
|
||||
value: gettext('Ascending by name'),
|
||||
},
|
||||
DESCENDING_BY_NAME: {
|
||||
key: 'Descending by name',
|
||||
value: gettext('Descending by name'),
|
||||
},
|
||||
};
|
||||
|
||||
export default TextTranslation;
|
||||
|
Reference in New Issue
Block a user