mirror of
https://github.com/haiwen/seahub.git
synced 2025-09-20 02:48:51 +00:00
combine normal and semantic search (#5743)
This commit is contained in:
@@ -15,11 +15,6 @@ const INDEX_STATE = {
|
|||||||
FINISHED: 'finished'
|
FINISHED: 'finished'
|
||||||
};
|
};
|
||||||
|
|
||||||
const SEARCH_MODE = {
|
|
||||||
SIMILARITY: 'similarity',
|
|
||||||
NORMAL: 'normal',
|
|
||||||
};
|
|
||||||
|
|
||||||
const propTypes = {
|
const propTypes = {
|
||||||
repoID: PropTypes.string,
|
repoID: PropTypes.string,
|
||||||
placeholder: PropTypes.string,
|
placeholder: PropTypes.string,
|
||||||
@@ -51,8 +46,7 @@ class Search extends Component {
|
|||||||
isCloseShow: false,
|
isCloseShow: false,
|
||||||
isSearchInputShow: false, // for mobile
|
isSearchInputShow: false, // for mobile
|
||||||
searchPageUrl: this.baseSearchPageURL,
|
searchPageUrl: this.baseSearchPageURL,
|
||||||
searchMode: SEARCH_MODE.NORMAL,
|
indexState: '',
|
||||||
indexState: INDEX_STATE.UNCREATED,
|
|
||||||
};
|
};
|
||||||
this.inputValue = '';
|
this.inputValue = '';
|
||||||
this.highlightRef = null;
|
this.highlightRef = null;
|
||||||
@@ -66,6 +60,22 @@ class Search extends Component {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
document.addEventListener('keydown', this.onDocumentKeydown);
|
document.addEventListener('keydown', this.onDocumentKeydown);
|
||||||
|
if (enableSeafileAI && this.props.isLibView) {
|
||||||
|
this.queryLibraryIndexState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
queryLibraryIndexState() {
|
||||||
|
seafileAPI.queryLibraryIndexState(this.props.repoID).then(res => {
|
||||||
|
const { state: indexState, task_id: taskId } = res.data;
|
||||||
|
this.setState({ indexState }, () => {
|
||||||
|
if (indexState === INDEX_STATE.RUNNING) {
|
||||||
|
this.queryIndexTaskStatus(taskId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}).catch(error => {
|
||||||
|
this.setState({ indexState: INDEX_STATE.UNCREATED });
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@@ -96,21 +106,7 @@ class Search extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onFocusHandler = () => {
|
onFocusHandler = () => {
|
||||||
const { searchMode, indexState: currentIndexState } = this.state;
|
this.setState({ width: '570px', isMaskShow: true, isCloseShow: true });
|
||||||
const { repoID } = this.props;
|
|
||||||
this.setState({ width: '570px', isMaskShow: true, isCloseShow: true }, () => {
|
|
||||||
if (searchMode !== SEARCH_MODE.SIMILARITY) return;
|
|
||||||
if (currentIndexState === INDEX_STATE.FINISHED) return;
|
|
||||||
seafileAPI.queryLibraryIndexState(repoID).then(res => {
|
|
||||||
const { state: indexState, task_id: taskId } = res.data;
|
|
||||||
this.setState({ indexState }, () => {
|
|
||||||
if (indexState !== INDEX_STATE.RUNNING) return;
|
|
||||||
this.queryIndexTaskStatus(taskId);
|
|
||||||
});
|
|
||||||
}).catch(error => {
|
|
||||||
this.setState({ indexState: INDEX_STATE.UNCREATED });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onCloseHandler = () => {
|
onCloseHandler = () => {
|
||||||
@@ -167,18 +163,17 @@ class Search extends Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onChangeHandler = (event) => {
|
onChangeHandler = (event) => {
|
||||||
const { searchMode } = this.state;
|
|
||||||
const newValue = event.target.value;
|
const newValue = event.target.value;
|
||||||
this.setState({ value: newValue }, () => {
|
this.setState({ value: newValue }, () => {
|
||||||
if (this.inputValue === newValue.trim()) return;
|
if (this.inputValue === newValue.trim()) return;
|
||||||
this.inputValue = newValue.trim();
|
this.inputValue = newValue.trim();
|
||||||
this.onSearch(searchMode === SEARCH_MODE.NORMAL);
|
this.onSearch(!this.props.isLibView || !enableSeafileAI);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onKeydownHandler = (event) => {
|
onKeydownHandler = (event) => {
|
||||||
if (isHotkey('enter', event)) {
|
if (isHotkey('enter', event)) {
|
||||||
if (this.state.searchMode === SEARCH_MODE.NORMAL) return;
|
if (!enableSeafileAI || !this.props.isLibView) return;
|
||||||
this.onSearch(true);
|
this.onSearch(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -255,10 +250,10 @@ class Search extends Component {
|
|||||||
this.updateSearchPageURL(queryData);
|
this.updateSearchPageURL(queryData);
|
||||||
queryData['per_page'] = PER_PAGE;
|
queryData['per_page'] = PER_PAGE;
|
||||||
queryData['page'] = page;
|
queryData['page'] = page;
|
||||||
if (this.state.searchMode === SEARCH_MODE.NORMAL) {
|
if (!enableSeafileAI || !this.props.isLibView) {
|
||||||
this.onNormalSearch(queryData, cancelToken, page);
|
this.onNormalSearch(queryData, cancelToken, page);
|
||||||
} else {
|
} else {
|
||||||
this.onSimilaritySearch(queryData, cancelToken, page);
|
this.onCombinedSearch(queryData, cancelToken, page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -326,6 +321,51 @@ class Search extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
onCombinedSearch = (queryData, cancelToken, page) => {
|
||||||
|
const { indexState } = this.state;
|
||||||
|
if (indexState === INDEX_STATE.UNCREATED) {
|
||||||
|
toaster.warning(gettext('Please create index first.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (indexState === INDEX_STATE.RUNNING) {
|
||||||
|
toaster.warning(gettext('Indexing, please try again later.'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let results = []
|
||||||
|
seafileAPI.searchFiles(queryData, cancelToken).then(res => {
|
||||||
|
if (res.data.total > 0) {
|
||||||
|
results = [...results, ...this.formatResultItems(res.data.results)]
|
||||||
|
}
|
||||||
|
seafileAPI.similaritySearchFiles(queryData, cancelToken).then(res => {
|
||||||
|
this.source = null;
|
||||||
|
if (res.data && res.data.children_list) {
|
||||||
|
results = [...results, ...this.formatSimilarityItems(res.data.children_list)]
|
||||||
|
}
|
||||||
|
|
||||||
|
let tempPathObj = {}
|
||||||
|
let searchResults = []
|
||||||
|
results.forEach(item => {
|
||||||
|
if (!tempPathObj[item.path]) {
|
||||||
|
tempPathObj[item.path] = true
|
||||||
|
searchResults.push(item)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
this.setState({
|
||||||
|
resultItems: searchResults,
|
||||||
|
isResultGetted: true,
|
||||||
|
isLoading: false,
|
||||||
|
page: page + 1,
|
||||||
|
hasMore: false,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}).catch(error => {
|
||||||
|
/* eslint-disable */
|
||||||
|
console.log(error);
|
||||||
|
this.setState({ isLoading: false });
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
onResultListScroll = (e) => {
|
onResultListScroll = (e) => {
|
||||||
// Load less than 100 results
|
// Load less than 100 results
|
||||||
if (!this.state.hasMore || this.state.isLoading || this.state.resultItems.length > 100) {
|
if (!this.state.hasMore || this.state.isLoading || this.state.resultItems.length > 100) {
|
||||||
@@ -416,9 +456,9 @@ class Search extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderSearchResult() {
|
renderSearchResult() {
|
||||||
const { resultItems, highlightIndex, indexState, searchMode, width } = this.state;
|
const { resultItems, highlightIndex, indexState, width } = this.state;
|
||||||
if (!width) return null;
|
if (!width || width === 'default') return null;
|
||||||
if (searchMode === SEARCH_MODE.SIMILARITY && indexState === INDEX_STATE.UNCREATED) {
|
if (enableSeafileAI && indexState === INDEX_STATE.UNCREATED) {
|
||||||
return (
|
return (
|
||||||
<div className="search-mode-similarity-index-status index-status-uncreated" onClick={this.onCreateIndex}>
|
<div className="search-mode-similarity-index-status index-status-uncreated" onClick={this.onCreateIndex}>
|
||||||
{gettext('Click create index')}
|
{gettext('Click create index')}
|
||||||
@@ -426,7 +466,7 @@ class Search extends Component {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (searchMode === SEARCH_MODE.SIMILARITY && indexState === INDEX_STATE.RUNNING) {
|
if (enableSeafileAI && indexState === INDEX_STATE.RUNNING) {
|
||||||
return (
|
return (
|
||||||
<div className="search-mode-similarity-index-status">
|
<div className="search-mode-similarity-index-status">
|
||||||
{gettext('Indexing...')}
|
{gettext('Indexing...')}
|
||||||
@@ -482,52 +522,13 @@ class Search extends Component {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
onChangeSearchMode = (event) => {
|
queryIndexTaskStatus = (taskId) => {
|
||||||
const searchMode = event.target.getAttribute('mode-type');
|
|
||||||
if (searchMode === this.state.searchMode) return;
|
|
||||||
const { repoID } = this.props;
|
|
||||||
const { indexState: currentIndexState } = this.state;
|
|
||||||
this.timer && clearTimeout(this.timer);
|
|
||||||
this.setState({ searchMode }, () => {
|
|
||||||
if (searchMode === SEARCH_MODE.NORMAL) {
|
|
||||||
this.onSearch();
|
|
||||||
this.indexStateTimer && clearInterval(this.indexStateTimer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchMode === SEARCH_MODE.SIMILARITY) {
|
|
||||||
if (currentIndexState === INDEX_STATE.FINISHED) {
|
|
||||||
this.onSearch(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
seafileAPI.queryLibraryIndexState(repoID).then(res => {
|
|
||||||
const { state: indexState, task_id: taskId } = res.data;
|
|
||||||
this.setState({ indexState }, () => {
|
|
||||||
if (indexState === INDEX_STATE.FINISHED) {
|
|
||||||
this.onSearch(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (indexState === INDEX_STATE.RUNNING) {
|
|
||||||
this.queryIndexTaskStatus(taskId, () => this.onSearch(true));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}).catch(error => {
|
|
||||||
this.setState({ indexState: INDEX_STATE.UNCREATED });
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
queryIndexTaskStatus = (taskId, callback) => {
|
|
||||||
if (!taskId) return;
|
if (!taskId) return;
|
||||||
this.indexStateTimer = setInterval(() => {
|
this.indexStateTimer = setInterval(() => {
|
||||||
seafileAPI.queryIndexTaskStatus(taskId).then(res => {
|
seafileAPI.queryIndexTaskStatus(taskId).then(res => {
|
||||||
const isFinished = res.data.is_finished;
|
const isFinished = res.data.is_finished;
|
||||||
if (isFinished) {
|
if (isFinished) {
|
||||||
this.setState({ indexState: INDEX_STATE.FINISHED }, () => {
|
this.setState({ indexState: INDEX_STATE.FINISHED });
|
||||||
callback && callback();
|
|
||||||
});
|
|
||||||
this.indexStateTimer && clearInterval(this.indexStateTimer);
|
this.indexStateTimer && clearInterval(this.indexStateTimer);
|
||||||
this.indexStateTimer = null;
|
this.indexStateTimer = null;
|
||||||
}
|
}
|
||||||
@@ -556,7 +557,7 @@ class Search extends Component {
|
|||||||
render() {
|
render() {
|
||||||
let width = this.state.width !== 'default' ? this.state.width : '';
|
let width = this.state.width !== 'default' ? this.state.width : '';
|
||||||
let style = {'width': width};
|
let style = {'width': width};
|
||||||
const { searchPageUrl, isMaskShow, searchMode, indexState, isCloseShow } = this.state;
|
const { searchPageUrl, isMaskShow, indexState, isCloseShow, resultItems } = this.state;
|
||||||
const placeholder = `${this.props.placeholder}${isMaskShow ? '' : ` (${controlKey} + f )`}`;
|
const placeholder = `${this.props.placeholder}${isMaskShow ? '' : ` (${controlKey} + f )`}`;
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
@@ -577,7 +578,7 @@ class Search extends Component {
|
|||||||
onChange={this.onChangeHandler}
|
onChange={this.onChangeHandler}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
ref={this.inputRef}
|
ref={this.inputRef}
|
||||||
readOnly={isCloseShow && enableSeafileAI && SEARCH_MODE.SIMILARITY === searchMode && indexState !== INDEX_STATE.FINISHED}
|
readOnly={isCloseShow && this.props.isLibView && enableSeafileAI && indexState !== INDEX_STATE.FINISHED}
|
||||||
onKeyDown={this.onKeydownHandler}
|
onKeyDown={this.onKeydownHandler}
|
||||||
/>
|
/>
|
||||||
{(this.state.isCloseShow && username) &&
|
{(this.state.isCloseShow && username) &&
|
||||||
@@ -592,12 +593,6 @@ class Search extends Component {
|
|||||||
onScroll={this.onResultListScroll}
|
onScroll={this.onResultListScroll}
|
||||||
ref={this.searchContainer}
|
ref={this.searchContainer}
|
||||||
>
|
>
|
||||||
{isCloseShow && enableSeafileAI && this.props.isLibView &&
|
|
||||||
<div className="search-mode-container">
|
|
||||||
<div className={`search-mode-item ${SEARCH_MODE.NORMAL === searchMode ? 'search-mode-active' : ''}`} mode-type={SEARCH_MODE.NORMAL} onClick={this.onChangeSearchMode}>{gettext('Normal search')}</div>
|
|
||||||
<div className={`search-mode-item ${SEARCH_MODE.SIMILARITY === searchMode ? 'search-mode-active' : ''}`} mode-type={SEARCH_MODE.SIMILARITY} onClick={this.onChangeSearchMode}>{gettext('Similarity search')}</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
{this.renderSearchResult()}
|
{this.renderSearchResult()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user