mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-09 19:01:42 +00:00
Feature/improve interactivity of searched list in move dialog (#6597)
* improve interactivity of search result * clean up redundant code * clean up redundant code
This commit is contained in:
@@ -57,6 +57,8 @@ class FileChooser extends React.Component {
|
||||
searchInfo: '',
|
||||
searchResults: [],
|
||||
selectedItemInfo: {},
|
||||
isBrowsing: false,
|
||||
browsingPath: '',
|
||||
};
|
||||
this.inputValue = '';
|
||||
this.timer = null;
|
||||
@@ -115,6 +117,8 @@ class FileChooser extends React.Component {
|
||||
this.setState({
|
||||
isSearching: false,
|
||||
isResultGot: false,
|
||||
isBrowsing: false,
|
||||
browsingPath: '',
|
||||
searchInfo: '',
|
||||
searchResults: [],
|
||||
});
|
||||
@@ -182,8 +186,12 @@ class FileChooser extends React.Component {
|
||||
this.setState({
|
||||
isSearching: false,
|
||||
isResultGot: false,
|
||||
isBrowsing: false,
|
||||
browsingPath: '',
|
||||
searchInfo: '',
|
||||
searchResults: [],
|
||||
selectedPath: this.props.currentPath,
|
||||
selectedItemInfo: {},
|
||||
});
|
||||
this.inputValue = '';
|
||||
this.timer = null;
|
||||
@@ -204,7 +212,7 @@ class FileChooser extends React.Component {
|
||||
}
|
||||
this.inputValue = searchInfo;
|
||||
|
||||
if (this.inputValue === '' || this.getValueLength(this.inputValue) < 3) {
|
||||
if (this.inputValue === '') {
|
||||
this.setState({
|
||||
isResultGot: false,
|
||||
});
|
||||
@@ -242,18 +250,27 @@ class FileChooser extends React.Component {
|
||||
};
|
||||
|
||||
sendRequest = (queryData, cancelToken) => {
|
||||
const filterCurrentRepo = (results) => {
|
||||
if (this.props.mode === 'only_other_libraries') {
|
||||
return results.filter(item => item.repo_id !== this.state.currentRepoInfo.repo_id);
|
||||
}
|
||||
return results;
|
||||
};
|
||||
|
||||
if (isPro && enableSeasearch && !enableElasticsearch) {
|
||||
seafileAPI.aiSearchFiles(queryData, cancelToken).then(res => {
|
||||
const filteredResults = filterCurrentRepo(res.data.results.filter(item => item.is_dir));
|
||||
this.setState({
|
||||
searchResults: res.data.results.length > 0 ? this.formatResultItems(res.data.results.filter(item => item.is_dir)) : [],
|
||||
searchResults: filteredResults.length > 0 ? this.formatResultItems(filteredResults) : [],
|
||||
isResultGot: true
|
||||
});
|
||||
this.source = null;
|
||||
});
|
||||
} else {
|
||||
seafileAPI.searchFiles(queryData, cancelToken).then(res => {
|
||||
const filteredResults = filterCurrentRepo(res.data.results);
|
||||
this.setState({
|
||||
searchResults: res.data.total ? this.formatResultItems(res.data.results) : [],
|
||||
searchResults: res.data.total ? this.formatResultItems(filteredResults) : [],
|
||||
isResultGot: true
|
||||
});
|
||||
this.source = null;
|
||||
@@ -306,10 +323,6 @@ class FileChooser extends React.Component {
|
||||
};
|
||||
|
||||
renderSearchedView = () => {
|
||||
if (this.getValueLength(this.inputValue) < 3) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!this.state.isResultGot) {
|
||||
return (<Loading />);
|
||||
}
|
||||
@@ -409,7 +422,16 @@ class FileChooser extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
this.onCloseSearching();
|
||||
this.setState({
|
||||
isSearching: false,
|
||||
isResultGot: false,
|
||||
searchResults: [],
|
||||
isBrowsing: true,
|
||||
browsingPath: item.path.substring(0, item.path.length - 1),
|
||||
});
|
||||
this.inputValue = '';
|
||||
this.timer = null;
|
||||
this.source = null;
|
||||
};
|
||||
onScroll = (event) => {
|
||||
event.stopPropagation();
|
||||
@@ -481,6 +503,8 @@ class FileChooser extends React.Component {
|
||||
isShowFile={isShowFile}
|
||||
fileSuffixes={fileSuffixes}
|
||||
selectedItemInfo={selectedItemInfo}
|
||||
isBrowsing={this.state.isBrowsing}
|
||||
browsingPath={this.state.browsingPath}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -517,6 +541,8 @@ class FileChooser extends React.Component {
|
||||
isShowFile={isShowFile}
|
||||
fileSuffixes={fileSuffixes}
|
||||
selectedItemInfo={selectedItemInfo}
|
||||
isBrowsing={this.state.isBrowsing}
|
||||
browsingPath={this.state.browsingPath}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@@ -534,7 +560,7 @@ class FileChooser extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const { repoID } = this.props;
|
||||
const { repoID, mode } = this.props;
|
||||
const { selectedRepo, searchInfo, isSearching } = this.state;
|
||||
|
||||
if (!selectedRepo && repoID) {
|
||||
@@ -543,7 +569,7 @@ class FileChooser extends React.Component {
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{isPro && this.props.mode !== 'recently_used' && (
|
||||
{isPro && mode !== 'recently_used' && (
|
||||
<div className="file-chooser-search-input">
|
||||
<Input className="search-input" placeholder={gettext('Search')} type='text' value={searchInfo} onChange={this.onSearchInfoChanged}></Input>
|
||||
{searchInfo.length !== 0 && (
|
||||
|
@@ -21,6 +21,8 @@ const propTypes = {
|
||||
fileSuffixes: PropTypes.array,
|
||||
selectedItemInfo: PropTypes.object,
|
||||
hideLibraryName: PropTypes.bool,
|
||||
isBrowsing: PropTypes.bool,
|
||||
browsingPath: PropTypes.string,
|
||||
};
|
||||
|
||||
class RepoListItem extends React.Component {
|
||||
@@ -63,6 +65,30 @@ class RepoListItem extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.isBrowsing && !this.props.isBrowsing) {
|
||||
this.setState({
|
||||
treeData: treeHelper.buildTree(),
|
||||
isShowChildren: this.props.initToShowChildren,
|
||||
});
|
||||
|
||||
const { isCurrentRepo, currentPath, repo, selectedItemInfo } = this.props;
|
||||
const { repoID } = selectedItemInfo || {};
|
||||
|
||||
if (isCurrentRepo && !repoID) {
|
||||
this.loadRepoDirentList(repo);
|
||||
setTimeout(() => {
|
||||
const repoID = repo.repo_id;
|
||||
if (isCurrentRepo && currentPath && currentPath != '/') {
|
||||
const expandNode = true;
|
||||
this.loadNodeAndParentsByPath(repoID, currentPath, expandNode);
|
||||
}
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.setState({ isMounted: false });
|
||||
}
|
||||
@@ -205,7 +231,7 @@ class RepoListItem extends React.Component {
|
||||
|
||||
return (
|
||||
<li>
|
||||
{!this.props.hideLibraryName &&
|
||||
{!this.props.hideLibraryName && !this.props.isBrowsing &&
|
||||
<div className={`${repoActive ? 'item-active' : ''} item-info`} onClick={this.onRepoItemClick}>
|
||||
<div className="item-left-icon">
|
||||
<span className={`item-toggle icon sf3-font ${this.state.isShowChildren ? 'sf3-font-down' : 'sf3-font-down rotate-270 d-inline-block'}`} onClick={this.onToggleClick}></span>
|
||||
@@ -228,6 +254,8 @@ class RepoListItem extends React.Component {
|
||||
treeData={this.state.treeData}
|
||||
onNodeCollapse={this.onNodeCollapse}
|
||||
onNodeExpanded={this.onNodeExpanded}
|
||||
isBrowsing={this.props.isBrowsing}
|
||||
browsingPath={this.props.browsingPath}
|
||||
/>
|
||||
)}
|
||||
</li>
|
||||
|
@@ -15,6 +15,8 @@ const propTypes = {
|
||||
fileSuffixes: PropTypes.array,
|
||||
selectedItemInfo: PropTypes.object,
|
||||
currentPath: PropTypes.string,
|
||||
isBrowsing: PropTypes.bool,
|
||||
browsingPath: PropTypes.string,
|
||||
};
|
||||
|
||||
class RepoListView extends React.Component {
|
||||
@@ -43,6 +45,8 @@ class RepoListView extends React.Component {
|
||||
isShowFile={this.props.isShowFile}
|
||||
fileSuffixes={this.props.fileSuffixes}
|
||||
selectedItemInfo={this.props.selectedItemInfo}
|
||||
isBrowsing={this.props.isBrowsing}
|
||||
browsingPath={this.props.browsingPath}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
@@ -13,12 +13,44 @@ class SearchedListView extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
currentItem: null,
|
||||
currentItem: props.searchResults.length > 0 ? props.searchResults[0] : null,
|
||||
currentIndex: props.searchResults.length > 0 ? 0 : -1,
|
||||
};
|
||||
this.itemRef = React.createRef();
|
||||
}
|
||||
|
||||
onItemClick = (item) => {
|
||||
this.setState({ currentItem: item });
|
||||
componentDidMount() {
|
||||
document.addEventListener('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
document.removeEventListener('keydown', this.handleKeyDown);
|
||||
}
|
||||
|
||||
handleKeyDown = (event) => {
|
||||
const { searchResults } = this.props;
|
||||
const { currentIndex } = this.state;
|
||||
|
||||
if (event.key === 'ArrowDown') {
|
||||
const nextIndex = (currentIndex + 1) % searchResults.length;
|
||||
this.setState({
|
||||
currentItem: searchResults[nextIndex],
|
||||
currentIndex: nextIndex,
|
||||
});
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
const prevIndex = (currentIndex - 1 + searchResults.length) % searchResults.length;
|
||||
this.setState({
|
||||
currentItem: searchResults[prevIndex],
|
||||
currentIndex: prevIndex,
|
||||
});
|
||||
} else if (event.key === 'Enter') {
|
||||
this.onItemClick(searchResults[currentIndex], currentIndex);
|
||||
this.props.onSearchedItemDoubleClick(searchResults[currentIndex]);
|
||||
}
|
||||
};
|
||||
|
||||
onItemClick = (item, index) => {
|
||||
this.setState({ currentItem: item, currentIndex: index });
|
||||
this.props.onItemClick(item);
|
||||
};
|
||||
|
||||
@@ -36,9 +68,10 @@ class SearchedListView extends React.Component {
|
||||
return (
|
||||
<SearchedListItem
|
||||
key={index}
|
||||
ref={this.itemRef}
|
||||
item={item}
|
||||
currentItem={this.state.currentItem}
|
||||
onItemClick={this.onItemClick}
|
||||
onItemClick={() => this.onItemClick(item, index)}
|
||||
onSearchedItemDoubleClick={this.props.onSearchedItemDoubleClick}
|
||||
/>
|
||||
);
|
||||
|
@@ -12,6 +12,7 @@ const propTypes = {
|
||||
filePath: PropTypes.string,
|
||||
fileSuffixes: PropTypes.array,
|
||||
level: PropTypes.number,
|
||||
isBrowsing: PropTypes.bool,
|
||||
};
|
||||
|
||||
class TreeViewItem extends React.Component {
|
||||
@@ -96,7 +97,7 @@ class TreeViewItem extends React.Component {
|
||||
if (this.props.selectedRepo) {
|
||||
isCurrentRepo = this.props.selectedRepo.repo_id === this.props.repo.repo_id;
|
||||
}
|
||||
let isCurrentPath = this.props.selectedPath === this.state.filePath;
|
||||
let isCurrentPath = this.props.selectedPath === this.state.filePath || this.props.selectedPath === node.path;
|
||||
|
||||
const fileName = node.object.name;
|
||||
if (this.props.fileSuffixes && fileName && node.object.type === 'file') {
|
||||
|
@@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import TreeListItem from './tree-list-item';
|
||||
import treeHelper from '../tree-view/tree-helper';
|
||||
|
||||
const propTypes = {
|
||||
selectedPath: PropTypes.string,
|
||||
@@ -11,22 +12,42 @@ const propTypes = {
|
||||
onNodeCollapse: PropTypes.func.isRequired,
|
||||
onNodeExpanded: PropTypes.func.isRequired,
|
||||
fileSuffixes: PropTypes.array,
|
||||
isBrowsing: PropTypes.bool,
|
||||
browsingPath: PropTypes.string,
|
||||
};
|
||||
|
||||
class TreeListView extends React.Component {
|
||||
|
||||
render() {
|
||||
const {
|
||||
isBrowsing,
|
||||
browsingPath,
|
||||
treeData,
|
||||
selectedPath,
|
||||
onNodeCollapse,
|
||||
onNodeExpanded,
|
||||
repo,
|
||||
onDirentItemClick,
|
||||
selectedRepo,
|
||||
fileSuffixes
|
||||
} = this.props;
|
||||
|
||||
const browsingNode = treeHelper.findNodeByPath(treeData, browsingPath);
|
||||
if (isBrowsing && !browsingNode) return null;
|
||||
|
||||
const node = isBrowsing ? browsingNode : treeData.root;
|
||||
|
||||
return (
|
||||
<div className="list-view-content">
|
||||
<TreeListItem
|
||||
node={this.props.treeData.root}
|
||||
onNodeCollapse={this.props.onNodeCollapse}
|
||||
onNodeExpanded={this.props.onNodeExpanded}
|
||||
repo={this.props.repo}
|
||||
onDirentItemClick={this.props.onDirentItemClick}
|
||||
selectedRepo={this.props.selectedRepo}
|
||||
selectedPath={this.props.selectedPath}
|
||||
fileSuffixes={this.props.fileSuffixes}
|
||||
node={node}
|
||||
onNodeCollapse={onNodeCollapse}
|
||||
onNodeExpanded={onNodeExpanded}
|
||||
repo={repo}
|
||||
onDirentItemClick={onDirentItemClick}
|
||||
selectedRepo={selectedRepo}
|
||||
selectedPath={selectedPath}
|
||||
fileSuffixes={fileSuffixes}
|
||||
level={0}
|
||||
/>
|
||||
</div>
|
||||
|
Reference in New Issue
Block a user