diff --git a/frontend/src/components/search/ai-search.js b/frontend/src/components/search/ai-search.js index 7cac8becdc..33af771e03 100644 --- a/frontend/src/components/search/ai-search.js +++ b/frontend/src/components/search/ai-search.js @@ -197,9 +197,36 @@ export default class AISearch extends Component { onItemClickHandler = (item) => { this.resetToDefault(); + this.keepVisitedItem(item); this.props.onSearchedClick(item); }; + keepVisitedItem = (targetItem) => { + const { repoID } = this.props; + let targetIndex; + let storeKey = 'sfVisitedAISearchItems'; + if (repoID) { + storeKey += repoID; + } + const items = JSON.parse(localStorage.getItem(storeKey)) || []; + for (let i = 0, len = items.length; i < len; i++) { + const { repo_id, path } = items[i]; + const { repo_id: targetRepoID, path: targetPath } = targetItem; + if (repo_id == targetRepoID && path == targetPath) { + targetIndex = i; + break; + } + } + if (targetIndex != undefined) { + items.splice(targetIndex, 1); + } + items.unshift(targetItem); + if (items.length > 50) { // keep 50 items at most + items.pop(); + } + localStorage.setItem(storeKey, JSON.stringify(items)); + }; + onChangeHandler = (event) => { const newValue = event.target.value; this.setState({ value: newValue }, () => { @@ -342,11 +369,54 @@ export default class AISearch extends Component { this.setState({ searchMode: SEARCH_MODE.COMBINED }); } + renderVisitedItems = (items) => { + const { highlightIndex } = this.state; + const results = ( + <> +

{gettext('Search results visited recently')}

+ + + ); + + return ( + <> + +
{results}
+
+ + {results} + + + ); + } + renderSearchResult() { const { resultItems, highlightIndex, width, searchMode, answeringResult } = this.state; if (!width || width === 'default') return null; - if (!this.state.isResultShow) return null; + if (!this.state.isResultShow) { + const { repoID } = this.props; + let storeKey = 'sfVisitedAISearchItems'; + if (repoID) { + storeKey += repoID; + } + const visitedItems = JSON.parse(localStorage.getItem(storeKey)) || []; + return visitedItems.length ? this.renderVisitedItems(visitedItems) : null; + } + if (!this.state.isResultGetted || getValueLength(this.inputValue) < 3) { return ( diff --git a/frontend/src/components/search/search.js b/frontend/src/components/search/search.js index fe8c3d7f2c..f03091af4f 100644 --- a/frontend/src/components/search/search.js +++ b/frontend/src/components/search/search.js @@ -163,9 +163,36 @@ class Search extends Component { onItemClickHandler = (item) => { this.resetToDefault(); + this.keepVisitedItem(item); this.props.onSearchedClick(item); }; + keepVisitedItem = (targetItem) => { + const { repoID } = this.props; + let targetIndex; + let storeKey = 'sfVisitedSearchItems'; + if (repoID) { + storeKey += repoID; + } + const items = JSON.parse(localStorage.getItem(storeKey)) || []; + for (let i = 0, len = items.length; i < len; i++) { + const { repo_id, path } = items[i]; + const { repo_id: targetRepoID, path: targetPath } = targetItem; + if (repo_id == targetRepoID && path == targetPath) { + targetIndex = i; + break; + } + } + if (targetIndex != undefined) { + items.splice(targetIndex, 1); + } + items.unshift(targetItem); + if (items.length > 50) { // keep 50 items at most + items.pop(); + } + localStorage.setItem(storeKey, JSON.stringify(items)); + }; + onChangeHandler = (event) => { const newValue = event.target.value; this.setState({ value: newValue }, () => { @@ -341,7 +368,16 @@ class Search extends Component { const { resultItems, highlightIndex, width } = this.state; if (!width || width === 'default') return null; - if (!this.state.isResultShow) return null; + if (!this.state.isResultShow) { + const { repoID } = this.props; + let storeKey = 'sfVisitedSearchItems'; + if (repoID) { + storeKey += repoID; + } + const visitedItems = JSON.parse(localStorage.getItem(storeKey)) || []; + return visitedItems.length ? this.renderResults(visitedItems, true) : null; + } + if (!this.state.isResultGetted || getValueLength(this.inputValue) < 3) { return ( @@ -353,7 +389,14 @@ class Search extends Component { ); } + return this.renderResults(resultItems); + } + + renderResults = (resultItems, isVisited) => { + const { highlightIndex } = this.state; const results = ( + <> + {isVisited &&

{gettext('Search results visited recently')}

} + ); return ( diff --git a/frontend/src/css/search.css b/frontend/src/css/search.css index dcb7de2e27..64f049410b 100644 --- a/frontend/src/css/search.css +++ b/frontend/src/css/search.css @@ -346,3 +346,10 @@ .search-result-container .search-mode-similarity-index-status.index-status-uncreated { cursor: pointer; } + +.visited-search-results-title { + color: #999; + font-size: .875rem; + font-weight: normal; + margin: 7px 0 10px; +}