diff --git a/package.json b/package.json index ca91bcb71e..ffb60265f8 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,6 @@ "eslint-plugin-react-hooks": "^1.7.0", "file-loader": "^4.1.0", "fscreen": "^1.0.2", - "fuzzysearch": "^1.0.3", "husky": "^3.0.5", "i18n-webpack-plugin": "^1.0.0", "jsuri": "^1.3.1", diff --git a/src/i18n/en-US.properties b/src/i18n/en-US.properties index 69f66c9897..a51a5b77e9 100644 --- a/src/i18n/en-US.properties +++ b/src/i18n/en-US.properties @@ -88,6 +88,8 @@ last_modified_date=Last modified date size=Size # Shown as the title in the breadcrumbs while searching. search_results=Search Results +# Shown as a placeholder in the search bar. +search_placeholder=Search files and folders # Media Preview # Label for autoplay in media player diff --git a/src/lib/viewers/archive/ArchiveExplorer.js b/src/lib/viewers/archive/ArchiveExplorer.js index e3d5244c63..1cfb5f459a 100644 --- a/src/lib/viewers/archive/ArchiveExplorer.js +++ b/src/lib/viewers/archive/ArchiveExplorer.js @@ -1,11 +1,10 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import getProp from 'lodash/get'; -import fuzzysearch from 'fuzzysearch'; import elementsMessages from 'box-elements-messages'; // eslint-disable-line import intlLocaleData from 'react-intl-locale-data'; // eslint-disable-line import Internationalize from 'box-ui-elements/es/elements/common/Internationalize'; -import SearchBar from 'box-ui-elements/es/elements/common/header'; +import fuzzySearch from 'box-ui-elements/es/utils/fuzzySearch'; import { readableTimeCellRenderer, sizeCellRenderer, @@ -15,6 +14,7 @@ import VirtualizedTable from 'box-ui-elements/es/features/virtualized-table'; import { addLocaleData } from 'react-intl'; import { Column } from 'react-virtualized/dist/es/Table/index'; import Breadcrumbs from './Breadcrumbs'; +import SearchBar from './SearchBar'; import { TABLE_COLUMNS, VIEWS } from './constants'; import './ArchiveExplorer.scss'; @@ -138,28 +138,19 @@ class ArchiveExplorer extends React.Component { * @param {string} query - raw query string in the search bar * @return {void} */ - search = query => { + handleSearch = query => { const trimmedQuery = query.trim(); + const newState = { + searchQuery: query, + }; if (!query) { - this.setState({ - searchQuery: query, - view: VIEW_FOLDER, - }); - return; + newState.view = VIEW_FOLDER; + } else if (trimmedQuery) { + newState.view = VIEW_SEARCH; } - if (!trimmedQuery) { - this.setState({ - searchQuery: query, - }); - return; - } - - this.setState({ - searchQuery: query, - view: VIEW_SEARCH, - }); + this.setState(newState); }; /** @@ -171,7 +162,7 @@ class ArchiveExplorer extends React.Component { */ getSearchResult = (itemCollection, searchQuery) => { const trimmedQuery = searchQuery.trim(); - return itemCollection.filter(item => fuzzysearch(trimmedQuery, item.name)); + return itemCollection.filter(item => fuzzySearch(trimmedQuery, item.name, 0)); }; /** @@ -190,7 +181,7 @@ class ArchiveExplorer extends React.Component { return (
- + {intl => [ diff --git a/src/lib/viewers/archive/Breadcrumbs.scss b/src/lib/viewers/archive/Breadcrumbs.scss index 4a8404f36c..a0351d7382 100644 --- a/src/lib/viewers/archive/Breadcrumbs.scss +++ b/src/lib/viewers/archive/Breadcrumbs.scss @@ -5,7 +5,7 @@ flex: 0 0 50px; align-items: center; justify-content: space-between; - padding: 0 20px 0 25px; + padding: 0 20px; border-bottom: 1px solid $bdl-gray-10; box-shadow: 0 4px 6px -2px $transparent-black; } diff --git a/src/lib/viewers/archive/SearchBar.js b/src/lib/viewers/archive/SearchBar.js new file mode 100644 index 0000000000..6549c1f65b --- /dev/null +++ b/src/lib/viewers/archive/SearchBar.js @@ -0,0 +1,28 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './SearchBar.scss'; + +class SearchBar extends React.PureComponent { + static propTypes = { + onSearch: PropTypes.func.isRequired, + searchQuery: PropTypes.string.isRequired, + }; + + render() { + const { onSearch, searchQuery } = this.props; + const search = ({ currentTarget }) => onSearch(currentTarget.value); + return ( +
+ +
+ ); + } +} + +export default SearchBar; diff --git a/src/lib/viewers/archive/SearchBar.scss b/src/lib/viewers/archive/SearchBar.scss new file mode 100644 index 0000000000..a1369d4996 --- /dev/null +++ b/src/lib/viewers/archive/SearchBar.scss @@ -0,0 +1,15 @@ +@import '~box-ui-elements/es/styles/variables'; + +.bp-SearchBar { + display: flex; + flex: 0 0 70px; + align-items: center; + padding: 0 20px; + background: $almost-white; + border-bottom: 1px solid $bdl-gray-10; + + input[type='search'] { + width: 100%; + font: inherit; + } +} diff --git a/src/lib/viewers/archive/__tests__/ArchiveExplorer-test-react.js b/src/lib/viewers/archive/__tests__/ArchiveExplorer-test-react.js index d040dcd2cc..a72984b586 100644 --- a/src/lib/viewers/archive/__tests__/ArchiveExplorer-test-react.js +++ b/src/lib/viewers/archive/__tests__/ArchiveExplorer-test-react.js @@ -72,7 +72,7 @@ describe('lib/viewers/archive/ArchiveExplorer', () => { const component = shallow(); expect(component.find('.bp-ArchiveExplorer').length).to.equal(1); - expect(component.find('InjectIntl(Header)').length).to.equal(1); + expect(component.find('SearchBar').length).to.equal(1); expect(component.find('Breadcrumbs').length).to.equal(1); expect(component.find('Internationalize').length).to.equal(1); expect(component.find('InjectIntl(VirtualizedTable)').length).to.equal(1); @@ -134,19 +134,19 @@ describe('lib/viewers/archive/ArchiveExplorer', () => { }); }); - describe('search()', () => { + describe('handleSearch()', () => { it('should set correct state when search query is not empty', () => { const component = shallow(); - component.instance().search('test'); + component.instance().handleSearch('test'); expect(component.state().searchQuery).to.equal('test'); expect(component.state().view).to.equal(VIEWS.VIEW_SEARCH); - component.instance().search(''); + component.instance().handleSearch(''); expect(component.state().searchQuery).to.equal(''); expect(component.state().view).to.equal(VIEWS.VIEW_FOLDER); - component.instance().search(' '); + component.instance().handleSearch(' '); expect(component.state().searchQuery).to.equal(' '); expect(component.state().view).to.equal(VIEWS.VIEW_FOLDER); }); diff --git a/src/lib/viewers/archive/__tests__/SearchBar-test-react.js b/src/lib/viewers/archive/__tests__/SearchBar-test-react.js new file mode 100644 index 0000000000..7736fea7ed --- /dev/null +++ b/src/lib/viewers/archive/__tests__/SearchBar-test-react.js @@ -0,0 +1,28 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import sinon from 'sinon'; +import SearchBar from '../SearchBar'; + +const sandbox = sinon.sandbox.create(); +let searchQuery; +let onSearch; + +describe('lib/viewers/archive/SearchBar', () => { + beforeEach(() => { + searchQuery = 'test'; + onSearch = sandbox.stub(); + }); + + afterEach(() => { + sandbox.verifyAndRestore(); + }); + + describe('render()', () => { + it('should render correct components', () => { + const component = shallow(); + + expect(component.find('.bp-SearchBar').length).to.equal(1); + expect(component.find('input').length).to.equal(1); + }); + }); +}); diff --git a/yarn.lock b/yarn.lock index 27f7c6ae71..32b2e624f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5662,11 +5662,6 @@ functions-have-names@^1.1.1: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.0.tgz#83da7583e4ea0c9ac5ff530f73394b033e0bf77d" integrity sha512-zKXyzksTeaCSw5wIX79iCA40YAa6CJMJgNg9wdkU/ERBrIdPSimPICYiLp65lRbSBqtiHql/HZfS2DyI/AH6tQ== -fuzzysearch@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/fuzzysearch/-/fuzzysearch-1.0.3.tgz#dffc80f6d6b04223f2226aa79dd194231096d008" - integrity sha1-3/yA9tawQiPyImqnndGUIxCW0Ag= - gather-stream@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b"