diff --git a/frontend/src/components/search/details/index.js b/frontend/src/components/search/details/index.js
index d38c78df32..6d12d9e804 100644
--- a/frontend/src/components/search/details/index.js
+++ b/frontend/src/components/search/details/index.js
@@ -34,6 +34,11 @@ const SearchedItemDetails = ({ repoID, path, dirent }) => {
const err = gettext('Library does not exist');
setRepoInfo(null);
setLibErrorMessage(err);
+
+ const storeKey = 'sfVisitedSearchItems' + repoID;
+ const visitedItems = JSON.parse(localStorage.getItem(storeKey)) || [];
+ const filteredItems = visitedItems.filter(item => item.repo_id !== repoID);
+ localStorage.setItem(storeKey, JSON.stringify(filteredItems));
} else {
const errMessage = Utils.getErrorMsg(error);
toaster.danger(errMessage);
@@ -46,7 +51,7 @@ const SearchedItemDetails = ({ repoID, path, dirent }) => {
controller.abort();
clearTimeout(timer);
};
- }, [repoID]);
+ }, [repoID, path]);
useEffect(() => {
setDirentDetail(null);
@@ -73,6 +78,12 @@ const SearchedItemDetails = ({ repoID, path, dirent }) => {
return; // Ignore abort errors
}
if (error.response && error.response.status === 404) {
+ const storeKey = 'sfVisitedSearchItems' + repoID;
+ const visitedItems = JSON.parse(localStorage.getItem(storeKey)) || [];
+ const filteredItems = visitedItems.filter(item =>
+ item.path !== path || item.repo_id !== repoID
+ );
+ localStorage.setItem(storeKey, JSON.stringify(filteredItems));
const err = `${dirent.type === 'file' ? 'File' : 'Folder'} does not exist`;
setErrMessage(err);
return;
diff --git a/frontend/src/components/search/search-result-item.js b/frontend/src/components/search/search-result-item.js
index 98255e35c5..d6f5354f3c 100644
--- a/frontend/src/components/search/search-result-item.js
+++ b/frontend/src/components/search/search-result-item.js
@@ -2,6 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Utils } from '../../utils/utils';
+import { gettext } from '../../utils/constants';
const propTypes = {
item: PropTypes.object.isRequired,
@@ -12,6 +13,7 @@ const propTypes = {
onHighlightIndex: PropTypes.func,
timer: PropTypes.number,
onSetTimer: PropTypes.func,
+ onDeleteItem: PropTypes.func,
};
class SearchResultItem extends React.Component {
@@ -37,6 +39,13 @@ class SearchResultItem extends React.Component {
}
};
+ deleteItem = (e) => {
+ e.stopPropagation();
+ if (this.props.onDeleteItem) {
+ this.props.onDeleteItem(this.props.item);
+ }
+ };
+
render() {
const { item, setRef = (() => {}) } = this.props;
let folderIconUrl = item.link_content ? Utils.getFolderIconUrl(false, 192) : Utils.getDefaultLibIconUrl();
@@ -61,6 +70,15 @@ class SearchResultItem extends React.Component {
{showName}
+ {this.props.isHighlight && (
+
+ )}
);
}
diff --git a/frontend/src/components/search/search.js b/frontend/src/components/search/search.js
index 3a67f96ca9..b1f99122c0 100644
--- a/frontend/src/components/search/search.js
+++ b/frontend/src/components/search/search.js
@@ -69,6 +69,7 @@ class Search extends Component {
},
suffixes: '',
},
+ visitedItems: [],
};
this.highlightRef = null;
this.source = null; // used to cancel request;
@@ -86,7 +87,9 @@ class Search extends Component {
document.addEventListener('compositionstart', this.onCompositionStart);
document.addEventListener('compositionend', this.onCompositionEnd);
const isFiltersShow = localStorage.getItem(SEARCH_FILTERS_SHOW_KEY) === 'true';
- this.setState({ isFiltersShow });
+ const visitedItems = JSON.parse(localStorage.getItem(this.storeKey)) || [];
+
+ this.setState({ isFiltersShow, visitedItems });
}
UNSAFE_componentWillReceiveProps(nextProps) {
@@ -94,6 +97,15 @@ class Search extends Component {
this.isChineseInput = false;
}
+ componentDidUpdate(prevProps, prevState) {
+ if (this.state.isMaskShow && !prevState.isMaskShow) {
+ const visitedItems = JSON.parse(localStorage.getItem(this.storeKey)) || [];
+ if (visitedItems !== prevState.visitedItems) {
+ this.setState({ visitedItems });
+ }
+ }
+ }
+
componentWillUnmount() {
document.removeEventListener('keydown', this.onDocumentKeydown);
document.removeEventListener('compositionstart', this.onCompositionStart);
@@ -556,11 +568,10 @@ class Search extends Component {
};
renderSearchResult() {
- const { resultItems, width, showRecent, isResultGotten, isLoading } = this.state;
+ const { resultItems, width, showRecent, isResultGotten, isLoading, visitedItems } = this.state;
if (!width || width === 'default') return null;
if (showRecent) {
- const visitedItems = JSON.parse(localStorage.getItem(this.storeKey)) || [];
if (visitedItems.length > 0) {
return this.renderResults(visitedItems, true);
}
@@ -734,6 +745,13 @@ class Search extends Component {
this.setState({ highlightIndex: index });
}, 200);
+ deleteItem = (item) => {
+ const { visitedItems } = this.state;
+ const update = visitedItems.filter(i => i.path !== item.path || i.repo_id !== item.repo_id);
+ this.setState({ visitedItems: update });
+ localStorage.setItem(this.storeKey, JSON.stringify(update));
+ };
+
renderResults = (resultItems, isVisited) => {
const { highlightIndex } = this.state;
@@ -758,6 +776,7 @@ class Search extends Component {
onHighlightIndex={this.debounceHighlight}
timer={this.timer}
onSetTimer={(timer) => {this.timer = timer;}}
+ onDeleteItem={this.deleteItem}
/>
);
})}
diff --git a/frontend/src/css/search.css b/frontend/src/css/search.css
index dac1f02295..9dca4af4b4 100644
--- a/frontend/src/css/search.css
+++ b/frontend/src/css/search.css
@@ -188,6 +188,16 @@
overflow: hidden;
}
+.search-result-item .search-icon-right {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.search-result-item .search-icon-right:hover {
+ background-color: #dbdbdb;
+}
+
.item-content .item-name a {
color: #EA8102 !important;
}