From 76bfd279b34f960149dba15424593dfd5fbfb956 Mon Sep 17 00:00:00 2001 From: Jonathan Date: Wed, 2 Aug 2017 15:38:54 -0400 Subject: PLT-7140: On slow connection searching should clear RHS and show spinner (#7014) * Added a RECEIVED_SEARCH_TERM event on search form submit, attempted to modify Search Results Header title when loading search results * Fixed RHS behaviour so that loading icon is shown while waiting for search results on slow connections. * PLT-7140: Fixed all eslint issues * PLT-7140: reverted changes to config/config.json that were accidentally committed * PLT-7140: Removed all static function decorators that I previously added to jsx files. These were suggested by eslint, but can cause issues for functions that override parent functionality. still can't reproduce the errors seen on spinmint locally, so I'm guessing at this point * PLT-7140: Changed var to const * Updating UI for search results loading (#7096) --- webapp/components/search_bar.jsx | 13 ++++++++-- webapp/components/search_results.jsx | 29 +++++++++++++++++++++-- webapp/components/search_results_header.jsx | 3 ++- webapp/components/sidebar_right/sidebar_right.jsx | 2 +- webapp/i18n/en.json | 1 + webapp/sass/components/_search.scss | 17 ++++++++----- webapp/sass/layout/_sidebar-right.scss | 9 +++++++ webapp/sass/responsive/_mobile.scss | 5 ++++ webapp/stores/search_store.jsx | 16 +++++++++++++ 9 files changed, 83 insertions(+), 12 deletions(-) diff --git a/webapp/components/search_bar.jsx b/webapp/components/search_bar.jsx index c635c5eb1..f2fed25ca 100644 --- a/webapp/components/search_bar.jsx +++ b/webapp/components/search_bar.jsx @@ -171,7 +171,16 @@ export default class SearchBar extends React.Component { handleSubmit(e) { e.preventDefault(); - this.handleSearch(this.state.searchTerm.trim()); + const terms = this.state.searchTerm.trim(); + + AppDispatcher.handleServerAction({ + type: ActionTypes.RECEIVED_SEARCH_TERM, + term: terms, + do_search: true, + is_mention_search: false + }); + + this.handleSearch(terms); this.search.blur(); } @@ -221,7 +230,7 @@ export default class SearchBar extends React.Component { var isSearching = null; if (this.state.isSearching) { - isSearching = ; + isSearching = ; } let helpClass = 'search-help-popover'; diff --git a/webapp/components/search_results.jsx b/webapp/components/search_results.jsx index 1d1627950..1499c8abb 100644 --- a/webapp/components/search_results.jsx +++ b/webapp/components/search_results.jsx @@ -39,7 +39,8 @@ function getStateFromStores() { results, channels, searchTerm: SearchStore.getSearchTerm(), - flaggedPosts: PreferenceStore.getCategory(Constants.Preferences.CATEGORY_FLAGGED_POST) + flaggedPosts: PreferenceStore.getCategory(Constants.Preferences.CATEGORY_FLAGGED_POST), + loading: SearchStore.isLoading() }; } @@ -71,6 +72,7 @@ export default class SearchResults extends React.Component { componentDidMount() { this.mounted = true; + SearchStore.addSearchTermChangeListener(this.onSearchTermChange); SearchStore.addSearchChangeListener(this.onChange); ChannelStore.addChangeListener(this.onChange); PreferenceStore.addChangeListener(this.onPreferenceChange); @@ -113,6 +115,7 @@ export default class SearchResults extends React.Component { componentWillUnmount() { this.mounted = false; + SearchStore.removeSearchTermChangeListener(this.onSearchTermChange); SearchStore.removeSearchChangeListener(this.onChange); ChannelStore.removeChangeListener(this.onChange); PreferenceStore.removeChangeListener(this.onPreferenceChange); @@ -144,6 +147,14 @@ export default class SearchResults extends React.Component { }); } + onSearchTermChange(doSearch) { + if (this.mounted && doSearch) { + this.setState({ + loading: true + }); + } + } + onChange() { if (this.mounted) { this.setState(getStateFromStores()); @@ -175,7 +186,20 @@ export default class SearchResults extends React.Component { var ctls = null; - if (this.props.isFlaggedPosts && noResults) { + if (this.state.loading) { + ctls = + ( +
+
+ + +
+
+ ); + } else if (this.props.isFlaggedPosts && noResults) { ctls = (
    @@ -319,6 +343,7 @@ export default class SearchResults extends React.Component { isFlaggedPosts={this.props.isFlaggedPosts} isPinnedPosts={this.props.isPinnedPosts} channelDisplayName={this.props.channelDisplayName} + isLoading={this.state.loading} />
  • If you're searching a partial phrase (ex. searching \"rea\", looking for \"reach\" or \"reaction\"), append a * to your search term.
  • Two letter searches and common words like \"this\", \"a\" and \"is\" won't appear in search results due to excessive results returned.
", "search_results.noResults": "No results found. Try again?", + "search_results.searching": "Searching...", "search_results.usage": "
  • Use \"quotation marks\" to search for phrases
  • Use from: to find posts from specific users and in: to find posts in specific channels
", "search_results.usageFlag1": "You haven't flagged any messages yet.", "search_results.usageFlag2": "You can add a flag to messages and comments by clicking the ", diff --git a/webapp/sass/components/_search.scss b/webapp/sass/components/_search.scss index c9b8d4c02..4461b1da1 100644 --- a/webapp/sass/components/_search.scss +++ b/webapp/sass/components/_search.scss @@ -42,10 +42,6 @@ width: 40px; } -.search-form__container { - -} - .search__form { position: relative; @@ -71,15 +67,16 @@ width: 100%; } - .icon--refresh { + .fa-spin { @include opacity(0.5); + font-size: 1.2em; position: absolute; right: 27px; top: 27px; .search-bar__container & { right: 12px; - top: 11px; + top: 10px; } } } @@ -93,6 +90,14 @@ position: relative; } +.search-items-container div.loading { + text-align: center; +} + +.search-items-container img { + display: inline-block; +} + .search-results-header { border-bottom: $border-gray; color: #999999; diff --git a/webapp/sass/layout/_sidebar-right.scss b/webapp/sass/layout/_sidebar-right.scss index 6d31c1606..d7a18b587 100644 --- a/webapp/sass/layout/_sidebar-right.scss +++ b/webapp/sass/layout/_sidebar-right.scss @@ -224,6 +224,15 @@ text-transform: uppercase; } + .sidebar--right__loading { + @include opacity(.7); + text-align: center; + + .fa { + margin-right: 5px; + } + } + .sidebar--right__subheader { font-size: 1em; padding: .5em 1em 0; diff --git a/webapp/sass/responsive/_mobile.scss b/webapp/sass/responsive/_mobile.scss index 8f44a883f..d39797efb 100644 --- a/webapp/sass/responsive/_mobile.scss +++ b/webapp/sass/responsive/_mobile.scss @@ -1008,6 +1008,11 @@ margin-top: 9px; width: 100%; + .fa-spin { + font-size: 1.1em; + top: 9px; + } + .search-bar { font-size: 14px; height: 32px; diff --git a/webapp/stores/search_store.jsx b/webapp/stores/search_store.jsx index d57c630cb..dd9b6dbdf 100644 --- a/webapp/stores/search_store.jsx +++ b/webapp/stores/search_store.jsx @@ -24,6 +24,7 @@ class SearchStoreClass extends EventEmitter { this.isPinnedPosts = false; this.isVisible = false; this.searchTerm = ''; + this.loading = false; } emitChange() { @@ -157,6 +158,14 @@ class SearchStoreClass extends EventEmitter { results.order.splice(index, 1); } } + + setLoading(loading) { + this.loading = loading; + } + + isLoading() { + return this.loading; + } } var SearchStore = new SearchStoreClass(); @@ -173,10 +182,17 @@ SearchStore.dispatchToken = AppDispatcher.register((payload) => { // ignore pin posts update after switch to a new channel return; } + SearchStore.setLoading(false); SearchStore.storeSearchResults(action.results, action.is_mention_search, action.is_flagged_posts, action.is_pinned_posts); SearchStore.emitSearchChange(); break; case ActionTypes.RECEIVED_SEARCH_TERM: + if (action.do_search) { + // while a search is in progress, hide results from previous search + SearchStore.setLoading(true); + SearchStore.storeSearchResults(null, false, false, false); + SearchStore.emitSearchChange(); + } SearchStore.storeSearchTerm(action.term); SearchStore.emitSearchTermChange(action.do_search, action.is_mention_search); break; -- cgit v1.2.3-1-g7c22