Fix regression issue where users couldn't click into folders (#6029)

This commit fixes the issue introduced in #6023

The clicks on folder names direct the users inside the folders; while
the clicks on file names don't download the files, and will open file
previews on a separate modal in the future. Additionally, when a file
has been selected using the checkbox, it can now be downloaded without
being inside a zip file.

Fixes #6026
master
Kaan Kabalak 7 years ago committed by Harshavardhana
parent 7e12c3e8b9
commit 39919708d6
  1. 20
      browser/app/js/objects/ObjectItem.js
  2. 18
      browser/app/js/objects/ObjectsBulkActions.js
  3. 34
      browser/app/js/objects/__tests__/ObjectItem.test.js
  4. 24
      browser/app/js/objects/__tests__/ObjectsBulkActions.test.js
  5. 75
      browser/app/less/inc/list.less
  6. 4
      browser/app/less/inc/variables.less
  7. 48
      browser/ui-assets.go

@ -15,7 +15,6 @@
*/ */
import React from "react" import React from "react"
import classNames from "classnames"
import { connect } from "react-redux" import { connect } from "react-redux"
import humanize from "humanize" import humanize from "humanize"
import Moment from "moment" import Moment from "moment"
@ -35,22 +34,19 @@ export const ObjectItem = ({
onClick onClick
}) => { }) => {
return ( return (
<div <div className={"fesl-row"} data-type={getDataType(name, contentType)}>
className={
"fesl-row " +
classNames({
"fesl-row-selected": checked
})
}
data-type={getDataType(name, contentType)}
>
<div className="fesl-item fesl-item-icon"> <div className="fesl-item fesl-item-icon">
<div className="fi-select"> <div className="fi-select">
<input <input
type="checkbox" type="checkbox"
name={name} name={name}
checked={checked}
onChange={() => {
checked ? uncheckObject(name) : checkObject(name)
}}
/> />
<i className="fis-icon" /> <i className="fis-icon" />
<i className="fis-helper" />
</div> </div>
</div> </div>
<div className="fesl-item fesl-item-name"> <div className="fesl-item fesl-item-name">
@ -58,7 +54,9 @@ export const ObjectItem = ({
href="#" href="#"
onClick={e => { onClick={e => {
e.preventDefault() e.preventDefault()
checked ? uncheckObject(name) : checkObject(name) if (onClick) {
onClick()
}
}} }}
> >
{name} {name}

@ -29,10 +29,10 @@ export class ObjectsBulkActions extends React.Component {
} }
} }
handleDownload() { handleDownload() {
const { checkedObjects, resetCheckedList, downloadChecked, downloadObject } = this.props const { checkedObjects, clearChecked, downloadChecked, downloadObject } = this.props
if (checkedObjects.length === 1) { if (checkedObjects.length === 1 && !checkedObjects[0].endsWith('/')) {
downloadObject(checkedObjects[0]) downloadObject(checkedObjects[0])
resetCheckedList() clearChecked()
} else { } else {
downloadChecked() downloadChecked()
} }
@ -59,17 +59,16 @@ export class ObjectsBulkActions extends React.Component {
} }
> >
<span className="la-label"> <span className="la-label">
<i className="fa fa-check-circle" /> {checkedObjects.length} <i className="fa fa-check-circle" /> {checkedObjects.length}
{checkedObjects.length === 1 ? " Object " : " Objects "} {checkedObjects.length === 1 ? " Object " : " Objects "}
selected selected
</span> </span>
<span className="la-actions pull-right"> <span className="la-actions pull-right">
<button <button id="download-checked" onClick={this.handleDownload.bind(this)}>
id="download-checked"
onClick={this.handleDownload.bind(this)}
>
{" "} {" "}
Download {checkedObjects.length === 1 ? "object" : "all as zip"}{" "} Download
{(checkedObjects.length === 1 && !checkedObjects[0].endsWith('/')) ?
" object" : " all as zip" }{" "}
</button> </button>
</span> </span>
<span className="la-actions pull-right"> <span className="la-actions pull-right">
@ -105,6 +104,7 @@ const mapStateToProps = state => {
const mapDispatchToProps = dispatch => { const mapDispatchToProps = dispatch => {
return { return {
downloadObject: object => dispatch(actions.downloadObject(object)),
downloadChecked: () => dispatch(actions.downloadCheckedObjects()), downloadChecked: () => dispatch(actions.downloadCheckedObjects()),
downloadObject: object => dispatch(actions.downloadObject(object)), downloadObject: object => dispatch(actions.downloadObject(object)),
resetCheckedList: () => dispatch(actions.resetCheckedList()), resetCheckedList: () => dispatch(actions.resetCheckedList()),

@ -28,22 +28,40 @@ describe("ObjectItem", () => {
expect(wrapper.prop("data-type")).toBe("image") expect(wrapper.prop("data-type")).toBe("image")
}) })
it("should call checkObject when the object is selected", () => { it("shouldn't call onClick when the object isclicked", () => {
const checkObject = jest.fn() const onClick = jest.fn()
const wrapper = shallow(<ObjectItem name={"test"} checked={false} checkObject={checkObject} />) const wrapper = shallow(<ObjectItem name={"test"} />)
wrapper.find("a").simulate("click", { preventDefault: jest.fn() })
expect(onClick).not.toHaveBeenCalled()
})
it("should call onClick when the folder isclicked", () => {
const onClick = jest.fn()
const wrapper = shallow(<ObjectItem name={"test/"} onClick={onClick} />)
wrapper.find("a").simulate("click", { preventDefault: jest.fn() }) wrapper.find("a").simulate("click", { preventDefault: jest.fn() })
expect(onClick).toHaveBeenCalled()
})
it("should call checkObject when the object/prefix is checked", () => {
const checkObject = jest.fn()
const wrapper = shallow(
<ObjectItem name={"test"} checked={false} checkObject={checkObject} />
)
wrapper.find("input[type='checkbox']").simulate("change")
expect(checkObject).toHaveBeenCalledWith("test") expect(checkObject).toHaveBeenCalledWith("test")
}) })
it("should render highlighted row when object is selected", () => { it("should render checked checkbox", () => {
const wrapper = shallow(<ObjectItem name={"test"} checked={true} />) const wrapper = shallow(<ObjectItem name={"test"} checked={true} />)
expect(wrapper.find(".fesl-row").hasClass("fesl-row-selected")).toBeTruthy() expect(wrapper.find("input[type='checkbox']").prop("checked")).toBeTruthy()
}) })
it("should call uncheckObject when the object is deselected", () => { it("should call uncheckObject when the object/prefix is unchecked", () => {
const uncheckObject = jest.fn() const uncheckObject = jest.fn()
const wrapper = shallow(<ObjectItem name={"test"} checked={true} uncheckObject={uncheckObject} />) const wrapper = shallow(
wrapper.find("a").simulate("click", { preventDefault: jest.fn() }) <ObjectItem name={"test"} checked={true} uncheckObject={uncheckObject} />
)
wrapper.find("input[type='checkbox']").simulate("change")
expect(uncheckObject).toHaveBeenCalledWith("test") expect(uncheckObject).toHaveBeenCalledWith("test")
}) })
}) })

@ -20,7 +20,7 @@ import { ObjectsBulkActions } from "../ObjectsBulkActions"
describe("ObjectsBulkActions", () => { describe("ObjectsBulkActions", () => {
it("should render without crashing", () => { it("should render without crashing", () => {
shallow(<ObjectsBulkActions checkedObjects={0} />) shallow(<ObjectsBulkActions checkedObjects={[]} />)
}) })
it("should show actions when checkObjectsCount is more than 0", () => { it("should show actions when checkObjectsCount is more than 0", () => {
@ -28,21 +28,33 @@ describe("ObjectsBulkActions", () => {
expect(wrapper.hasClass("list-actions-toggled")).toBeTruthy() expect(wrapper.hasClass("list-actions-toggled")).toBeTruthy()
}) })
it("should call downloadObject for single object when download button is clicked", () => { it("should call downloadObject when single object is selected and download button is clicked", () => {
const downloadObject = jest.fn() const downloadObject = jest.fn()
const resetCheckedList = jest.fn() const clearChecked = jest.fn()
const wrapper = shallow( const wrapper = shallow(
<ObjectsBulkActions <ObjectsBulkActions
checkedObjects={["test1"]} checkedObjects={["test"]}
downloadObject={downloadObject} downloadObject={downloadObject}
resetCheckedList={resetCheckedList} clearChecked={clearChecked}
/> />
) )
wrapper.find("#download-checked").simulate("click") wrapper.find("#download-checked").simulate("click")
expect(downloadObject).toHaveBeenCalled() expect(downloadObject).toHaveBeenCalled()
}) })
it("should call downloadChecked for multiple objects when download button is clicked", () => { it("should call downloadChecked when a folder is selected and download button is clicked", () => {
const downloadChecked = jest.fn()
const wrapper = shallow(
<ObjectsBulkActions
checkedObjects={["test/"]}
downloadChecked={downloadChecked}
/>
)
wrapper.find("#download-checked").simulate("click")
expect(downloadChecked).toHaveBeenCalled()
})
it("should call downloadChecked when multiple objects are selected and download button is clicked", () => {
const downloadChecked = jest.fn() const downloadChecked = jest.fn()
const wrapper = shallow( const wrapper = shallow(
<ObjectsBulkActions <ObjectsBulkActions

@ -74,7 +74,7 @@ div.fesl-row {
border-bottom: 1px solid transparent; border-bottom: 1px solid transparent;
cursor: default; cursor: default;
.transition(background-color); .transition(background-color);
.transition-duration(300ms); .transition-duration(500ms);
@media (max-width: (@screen-xs-max - 100px)) { @media (max-width: (@screen-xs-max - 100px)) {
padding: 5px 20px; padding: 5px 20px;
@ -87,8 +87,16 @@ div.fesl-row {
} }
&:hover { &:hover {
&:not(.fesl-row-selected) { .fis-icon {
background: lighten(@text-muted-color, 22%); &:before {
.opacity(0)
}
}
.fis-helper {
&:before {
.opacity(1);
}
} }
} }
@ -129,14 +137,6 @@ div.fesl-row {
.fesl-row-selected { .fesl-row-selected {
background-color: @list-row-selected-bg; background-color: @list-row-selected-bg;
&:nth-child(even) {
background-color: @list-row-selected-even-bg;
}
&:hover {
background: @list-row-selected-hover;
}
&, .fesl-item a { &, .fesl-item a {
color: darken(@text-color, 10%); color: darken(@text-color, 10%);
} }
@ -161,6 +161,27 @@ div.fesl-row {
height: 35px; height: 35px;
z-index: 8; z-index: 8;
opacity: 0; opacity: 0;
cursor: pointer;
&:checked {
& ~ .fis-icon {
background-color: #32393F;
&:before {
opacity: 0;
}
}
& ~ .fis-helper {
&:before {
.scale(0);
}
&:after {
.scale(1);
}
}
}
} }
} }
@ -189,6 +210,38 @@ div.fesl-row {
} }
} }
.fis-helper {
&:before,
&:after {
position: absolute;
.transition(all);
.transition-duration(250ms);
}
&:before {
content: '';
width: 15px;
height: 15px;
border: 2px solid @white;
z-index: 7;
border-radius: 2px;
top: 10px;
left: 10px;
opacity: 0;
}
&:after {
font-family: @font-family-icon;
content: '\f00c';
top: 8px;
left: 9px;
color: @white;
font-size: 14px;
.scale(0);
}
}
/*-------------------------- /*--------------------------
Files and Folders Files and Folders
----------------------------*/ ----------------------------*/

@ -97,7 +97,5 @@
/*------------------------- /*-------------------------
List List
--------------------------*/ --------------------------*/
@list-row-selected-bg: #fffad6; @list-row-selected-bg: #fbf2bf;
@list-row-selected-even-bg: #faf5d1;
@list-row-selected-hover: #f5f0cc;
@list-row-even-bg: #fafafa; @list-row-even-bg: #fafafa;

File diff suppressed because one or more lines are too long
Loading…
Cancel
Save