NewUX: On filename click, select file instead of downloading (#6023)

This commit has been done according to @abperiasamy's feedback as we
are going to reserve the click on file icon to open the preview modal
in the future.

Also, when the user now selects a single file, the file itself is
downloaded instead of a .zip file containing the file.

Fixes #6019
master
Kaan Kabalak 7 years ago committed by Dee Koder
parent 617a6d8e47
commit 94ec6f374e
  1. 10
      browser/app/js/objects/ObjectContainer.js
  2. 18
      browser/app/js/objects/ObjectItem.js
  3. 27
      browser/app/js/objects/ObjectsBulkActions.js
  4. 27
      browser/app/js/objects/__tests__/ObjectItem.test.js
  5. 28
      browser/app/js/objects/__tests__/ObjectsBulkActions.test.js
  6. 75
      browser/app/less/inc/list.less
  7. 4
      browser/app/less/inc/variables.less
  8. 50
      browser/ui-assets.go

@ -37,7 +37,7 @@ export const ObjectContainer = ({
if (checkedObjectsCount == 0) {
props.actionButtons = <ObjectActions object={object} />
}
return <ObjectItem {...props} onClick={() => downloadObject(object.name)} />
return <ObjectItem {...props} />
}
const mapStateToProps = state => {
@ -46,10 +46,4 @@ const mapStateToProps = state => {
}
}
const mapDispatchToProps = dispatch => {
return {
downloadObject: object => dispatch(actionsObjects.downloadObject(object))
}
}
export default connect(mapStateToProps, mapDispatchToProps)(ObjectContainer)
export default connect(mapStateToProps)(ObjectContainer)

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

@ -28,6 +28,15 @@ export class ObjectsBulkActions extends React.Component {
showDeleteConfirmation: false
}
}
handleDownload() {
const { checkedObjects, resetCheckedList, downloadChecked, downloadObject } = this.props
if (checkedObjects.length === 1) {
downloadObject(checkedObjects[0])
resetCheckedList()
} else {
downloadChecked()
}
}
deleteChecked() {
const { deleteChecked } = this.props
deleteChecked()
@ -39,24 +48,28 @@ export class ObjectsBulkActions extends React.Component {
})
}
render() {
const { checkedObjectsCount, downloadChecked, clearChecked } = this.props
const { checkedObjects, clearChecked } = this.props
return (
<div
className={
"list-actions" +
classNames({
" list-actions-toggled": checkedObjectsCount > 0
" list-actions-toggled": checkedObjects.length > 0
})
}
>
<span className="la-label">
<i className="fa fa-check-circle" /> {checkedObjectsCount} Objects
<i className="fa fa-check-circle" /> {checkedObjects.length}
{checkedObjects.length === 1 ? " Object " : " Objects "}
selected
</span>
<span className="la-actions pull-right">
<button id="download-checked" onClick={downloadChecked}>
<button
id="download-checked"
onClick={this.handleDownload.bind(this)}
>
{" "}
Download all as zip{" "}
Download {checkedObjects.length === 1 ? "object" : "all as zip"}{" "}
</button>
</span>
<span className="la-actions pull-right">
@ -86,13 +99,15 @@ export class ObjectsBulkActions extends React.Component {
const mapStateToProps = state => {
return {
checkedObjectsCount: getCheckedList(state).length
checkedObjects: getCheckedList(state)
}
}
const mapDispatchToProps = dispatch => {
return {
downloadChecked: () => dispatch(actions.downloadCheckedObjects()),
downloadObject: object => dispatch(actions.downloadObject(object)),
resetCheckedList: () => dispatch(actions.resetCheckedList()),
clearChecked: () => dispatch(actions.resetCheckedList()),
deleteChecked: () => dispatch(actions.deleteCheckedObjects())
}

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

@ -20,19 +20,33 @@ import { ObjectsBulkActions } from "../ObjectsBulkActions"
describe("ObjectsBulkActions", () => {
it("should render without crashing", () => {
shallow(<ObjectsBulkActions checkedObjectsCount={0} />)
shallow(<ObjectsBulkActions checkedObjects={0} />)
})
it("should show actions when checkObjectsCount is more than 0", () => {
const wrapper = shallow(<ObjectsBulkActions checkedObjectsCount={1} />)
const wrapper = shallow(<ObjectsBulkActions checkedObjects={["test"]} />)
expect(wrapper.hasClass("list-actions-toggled")).toBeTruthy()
})
it("should call downloadChecked when download button is clicked", () => {
it("should call downloadObject for single object when download button is clicked", () => {
const downloadObject = jest.fn()
const resetCheckedList = jest.fn()
const wrapper = shallow(
<ObjectsBulkActions
checkedObjects={["test1"]}
downloadObject={downloadObject}
resetCheckedList={resetCheckedList}
/>
)
wrapper.find("#download-checked").simulate("click")
expect(downloadObject).toHaveBeenCalled()
})
it("should call downloadChecked for multiple objects when download button is clicked", () => {
const downloadChecked = jest.fn()
const wrapper = shallow(
<ObjectsBulkActions
checkedObjectsCount={1}
checkedObjects={["test1", "test2"]}
downloadChecked={downloadChecked}
/>
)
@ -43,14 +57,14 @@ describe("ObjectsBulkActions", () => {
it("should call clearChecked when close button is clicked", () => {
const clearChecked = jest.fn()
const wrapper = shallow(
<ObjectsBulkActions checkedObjectsCount={1} clearChecked={clearChecked} />
<ObjectsBulkActions checkedObjects={["test"]} clearChecked={clearChecked} />
)
wrapper.find("#close-bulk-actions").simulate("click")
expect(clearChecked).toHaveBeenCalled()
})
it("shoud show DeleteObjectConfirmModal when delete-checked button is clicked", () => {
const wrapper = shallow(<ObjectsBulkActions checkedObjectsCount={1} />)
const wrapper = shallow(<ObjectsBulkActions checkedObjects={["test"]} />)
wrapper.find("#delete-checked").simulate("click")
wrapper.update()
expect(wrapper.find("DeleteObjectConfirmModal").length).toBe(1)
@ -60,7 +74,7 @@ describe("ObjectsBulkActions", () => {
const deleteChecked = jest.fn()
const wrapper = shallow(
<ObjectsBulkActions
checkedObjectsCount={1}
checkedObjects={["test"]}
deleteChecked={deleteChecked}
/>
)

@ -74,7 +74,7 @@ div.fesl-row {
border-bottom: 1px solid transparent;
cursor: default;
.transition(background-color);
.transition-duration(500ms);
.transition-duration(300ms);
@media (max-width: (@screen-xs-max - 100px)) {
padding: 5px 20px;
@ -87,16 +87,8 @@ div.fesl-row {
}
&:hover {
.fis-icon {
&:before {
.opacity(0)
}
}
.fis-helper {
&:before {
.opacity(1);
}
&:not(.fesl-row-selected) {
background: lighten(@text-muted-color, 22%);
}
}
@ -137,6 +129,14 @@ div.fesl-row {
.fesl-row-selected {
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 {
color: darken(@text-color, 10%);
}
@ -161,27 +161,6 @@ div.fesl-row {
height: 35px;
z-index: 8;
opacity: 0;
cursor: pointer;
&:checked {
& ~ .fis-icon {
background-color: #32393F;
&:before {
opacity: 0;
}
}
& ~ .fis-helper {
&:before {
.scale(0);
}
&:after {
.scale(1);
}
}
}
}
}
@ -210,38 +189,6 @@ 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
----------------------------*/

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

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