Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(archive-viewer): add breadcrumbs #1119

Merged
merged 1 commit into from
Dec 17, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/i18n/en-US.properties
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ filename=Filename
last_modified_date=Last modified date
# Label for size column name
size=Size
# Shown as the title in the breadcrumbs while searching.
search_results=Search Results

# Media Preview
# Label for autoplay in media player
Expand Down
84 changes: 47 additions & 37 deletions src/lib/viewers/archive/ArchiveExplorer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ import {
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 { TABLE_COLUMNS } from './constants';
import Breadcrumbs from './Breadcrumbs';
import { TABLE_COLUMNS, VIEWS } from './constants';
import './ArchiveExplorer.scss';

const language = __LANGUAGE__; // eslint-disable-line
const { KEY_NAME, KEY_MODIFIED_AT, KEY_SIZE } = TABLE_COLUMNS;
Expand Down Expand Up @@ -63,6 +65,7 @@ class ArchiveExplorer extends React.Component {

this.state = {
fullPath: props.itemCollection.find(info => !info.parent).absolute_path,
view: VIEWS.VIEW_FOLDER,
};
}

Expand Down Expand Up @@ -121,53 +124,60 @@ class ArchiveExplorer extends React.Component {
});
};

/**
* Handle click event, update fullPath state
*
* @param {string} fullPath - target folder path
* @return {void}
*/
handleClickFullPath = fullPath => this.setState({ fullPath });

/**
* render data
*
* @return {jsx} VirtualizedTable
*/
render() {
const { itemCollection } = this.props;
const { fullPath } = this.state;
const { fullPath, view } = this.state;
const itemList = this.getItemList(itemCollection, fullPath);

return (
<Internationalize language={language} messages={elementsMessages}>
<VirtualizedTable
className="ArchiveFilesTable"
rowData={itemList}
rowGetter={this.getRowData(itemList)}
>
{intl => [
<Column
key={KEY_NAME}
cellRenderer={itemNameCellRenderer(intl, this.handleClick)}
dataKey={KEY_NAME}
disableSort
flexGrow={3}
label={__('filename')}
width={1}
/>,
<Column
key={KEY_MODIFIED_AT}
cellRenderer={readableTimeCellRenderer}
dataKey={KEY_MODIFIED_AT}
disableSort
flexGrow={2}
label={__('last_modified_date')}
width={1}
/>,
<Column
key={KEY_SIZE}
cellRenderer={sizeCellRenderer()}
dataKey={KEY_SIZE}
disableSort
flexGrow={1}
label={__('size')}
width={1}
/>,
]}
</VirtualizedTable>
<div className="bp-ArchiveExplorer">
<Breadcrumbs fullPath={fullPath} onClick={this.handleClickFullPath} view={view} />
<VirtualizedTable rowData={itemList} rowGetter={this.getRowData(itemList)}>
{intl => [
<Column
key={KEY_NAME}
cellRenderer={itemNameCellRenderer(intl, this.handleClick)}
dataKey={KEY_NAME}
disableSort
flexGrow={3}
label={__('filename')}
width={1}
/>,
<Column
key={KEY_MODIFIED_AT}
cellRenderer={readableTimeCellRenderer}
dataKey={KEY_MODIFIED_AT}
disableSort
flexGrow={2}
label={__('last_modified_date')}
width={1}
/>,
<Column
key={KEY_SIZE}
cellRenderer={sizeCellRenderer()}
dataKey={KEY_SIZE}
disableSort
flexGrow={1}
label={__('size')}
width={1}
/>,
]}
</VirtualizedTable>
</div>
</Internationalize>
);
}
Expand Down
6 changes: 6 additions & 0 deletions src/lib/viewers/archive/ArchiveExplorer.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.bp-ArchiveExplorer {
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
}
58 changes: 58 additions & 0 deletions src/lib/viewers/archive/Breadcrumbs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import React from 'react';
import PropTypes from 'prop-types';
import Breadcrumb from 'box-ui-elements/es/components/breadcrumb';
import PlainButton from 'box-ui-elements/es/components/plain-button/PlainButton';
import { VIEWS } from './constants';
import './Breadcrumbs.scss';

class Breadcrumbs extends React.PureComponent {
static propTypes = {
fullPath: PropTypes.string.isRequired,
onClick: PropTypes.func.isRequired,
view: PropTypes.string.isRequired,
};

/**
* Split full path string to path items
*
* @param {string} fullPath - Full path for current folder
* @return {Array<Object>} path items including name and path string
*/
getPathItems = fullPath => {
const pathNames = fullPath.split('/').slice(0, -1);
// join path names from root to current index to get absolute path
const getAbsolutePath = index => pathNames.slice(0, index + 1).join('/');

return pathNames.map((name, index) => ({
name,
path: `${getAbsolutePath(index)}/`,
}));
};

/**
* render breadcrumbs
*
* @return {jsx} Breadcrumbs
*/
render() {
const { fullPath, onClick, view } = this.props;

return (
<div className="bp-Breadcrumbs">
<Breadcrumb>
{view === VIEWS.VIEW_SEARCH ? (
<span>{__('search_results')}</span>
) : (
this.getPathItems(fullPath).map(pathItem => (
<PlainButton key={pathItem.path} onClick={() => onClick(pathItem.path)} type="button">
{pathItem.name}
</PlainButton>
))
)}
</Breadcrumb>
</div>
);
}
}

export default Breadcrumbs;
11 changes: 11 additions & 0 deletions src/lib/viewers/archive/Breadcrumbs.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@import '~box-ui-elements/es/styles/variables';

.bp-Breadcrumbs {
display: flex;
flex: 0 0 50px;
align-items: center;
justify-content: space-between;
padding: 0 20px 0 25px;
border-bottom: 1px solid $bdl-gray-10;
box-shadow: 0 4px 6px -2px $transparent-black;
}
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,11 @@ describe('lib/viewers/archive/ArchiveExplorer', () => {
});

describe('render()', () => {
it('should render VirtualizedTable', () => {
it('should render correct components', () => {
const component = shallow(<ArchiveExplorer itemCollection={data} />);

expect(component.find('.bp-ArchiveExplorer').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);
});
Expand All @@ -86,6 +88,16 @@ describe('lib/viewers/archive/ArchiveExplorer', () => {
});
});

describe('handleClickFullPath()', () => {
it('should set state when handleClickFullPath() is called', () => {
const component = shallow(<ArchiveExplorer itemCollection={data} />);

component.instance().handleClickFullPath('test/subfolder/');

expect(component.state().fullPath).to.equal('test/subfolder/');
});
});

describe('getRowData()', () => {
it('should return correct row data', () => {
const component = shallow(<ArchiveExplorer itemCollection={data} />);
Expand Down
57 changes: 57 additions & 0 deletions src/lib/viewers/archive/__tests__/Breadcrumbs-test-react.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React from 'react';
import { shallow } from 'enzyme';
import sinon from 'sinon';
import Breadcrumbs from '../Breadcrumbs';
import { VIEWS } from '../constants';

const sandbox = sinon.sandbox.create();
let fullPath;
let onClick;
let view;

describe('lib/viewers/archive/Breadcrumbs', () => {
beforeEach(() => {
fullPath = 'test/subfolder/';
onClick = sandbox.stub();
view = VIEWS.VIEW_FOLDER;
});

afterEach(() => {
sandbox.verifyAndRestore();
});

describe('render()', () => {
it('should render correct components', () => {
const component = shallow(<Breadcrumbs fullPath={fullPath} onClick={onClick} view={view} />);

expect(component.find('.bp-Breadcrumbs').length).to.equal(1);
expect(component.find('InjectIntl(Breadcrumb)').length).to.equal(1);
expect(component.find('PlainButton').length).to.equal(2);
});

it('should render search result if view is search', () => {
const component = shallow(<Breadcrumbs fullPath={fullPath} onClick={onClick} view={VIEWS.VIEW_SEARCH} />);

expect(component.find('span').text()).to.equal(__('search_results'));
});
});

describe('getPathItems()', () => {
it('should return correct path items', () => {
const component = shallow(<Breadcrumbs fullPath={fullPath} onClick={onClick} view={view} />);

const pathItems = component.instance().getPathItems(fullPath);

expect(pathItems).to.eql([
{
name: 'test',
path: 'test/',
},
{
name: 'subfolder',
path: 'test/subfolder/',
},
]);
});
});
});
8 changes: 6 additions & 2 deletions src/lib/viewers/archive/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,9 @@ const TABLE_COLUMNS = {
KEY_SIZE: 'key_size',
};

// eslint-disable-next-line import/prefer-default-export
export { TABLE_COLUMNS };
const VIEWS = {
VIEW_FOLDER: 'folder',
VIEW_SEARCH: 'search',
};

export { TABLE_COLUMNS, VIEWS };